Torque3D Documentation / _generateds / tamlJSONReader.cpp

tamlJSONReader.cpp

Engine/source/persistence/taml/json/tamlJSONReader.cpp

More...

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2013 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "persistence/taml/json/tamlJSONReader.h"
 25#include "persistence/taml/json/tamlJSONWriter.h"
 26#include "core/stream/fileStream.h"
 27#include "core/strings/stringUnit.h"
 28#include "core/frameAllocator.h"
 29
 30// Debug Profiling.
 31#include "platform/profiler.h"
 32
 33//-----------------------------------------------------------------------------
 34
 35SimObject* TamlJSONReader::read( FileStream& stream )
 36{
 37    // Debug Profiling.
 38    PROFILE_SCOPE(TamlJSONReader_Read);
 39   
 40    // Read JSON file.
 41    const U32 streamSize = stream.getStreamSize();
 42    FrameTemp<char> jsonText( streamSize + 1 );
 43    if ( !stream.read( streamSize, jsonText ) )
 44    {
 45        // Warn!
 46        Con::warnf("TamlJSONReader::read() -  Could not load Taml JSON file from stream.");
 47        return NULL;
 48    }
 49    jsonText[streamSize] = '\0'; 
 50
 51    // Create JSON document.
 52    rapidjson::Document document;
 53    document.Parse<0>( jsonText );
 54
 55    // Check the document is valid.
 56    if ( document.GetType() != rapidjson::kObjectType )
 57    {
 58        // Warn!
 59        Con::warnf("TamlJSONReader::read() -  Load Taml JSON file from stream but was invalid.");
 60        return NULL;
 61    }
 62    
 63    // Parse root value.
 64    SimObject* pSimObject = parseType( document.MemberBegin() );
 65
 66    // Reset parse.
 67    resetParse();
 68
 69    return pSimObject;
 70}
 71
 72//-----------------------------------------------------------------------------
 73
 74void TamlJSONReader::resetParse( void )
 75{
 76    // Debug Profiling.
 77    PROFILE_SCOPE(TamlJSONReader_ResetParse);
 78
 79    // Clear object reference map.
 80    mObjectReferenceMap.clear();
 81}
 82
 83//-----------------------------------------------------------------------------
 84
 85SimObject* TamlJSONReader::parseType( const rapidjson::Value::ConstMemberIterator& memberItr )
 86{
 87    // Debug Profiling.
 88    PROFILE_SCOPE(TamlJSONReader_ParseType);
 89
 90    // Fetch name and value.
 91    const rapidjson::Value& typeName = memberItr->name;
 92    const rapidjson::Value& typeValue = memberItr->value;
 93
 94    // Is value an object?
 95    if ( !typeValue.IsObject() )
 96    {
 97        // No, so warn.
 98        Con::warnf( "TamlJSONReader::parseType() -  Cannot process type '%s' as it is not an object.", typeName.GetString() );
 99        return NULL;
100    }
101
102    // Fetch engine type name (demangled).
103    StringTableEntry engineTypeName = getDemangledName( typeName.GetString() );
104
105    // Fetch reference to Id.
106    const U32 tamlRefToId = getTamlRefToId( typeValue );
107
108    // Do we have a reference to Id?
109    if ( tamlRefToId != 0 )
110    {
111        // Yes, so fetch reference.
112        typeObjectReferenceHash::Iterator referenceItr = mObjectReferenceMap.find( tamlRefToId );
113
114        // Did we find the reference?
115        if ( referenceItr == mObjectReferenceMap.end() )
116        {
117            // No, so warn.
118            Con::warnf( "TamlJSONReader::parseType() -  Could not find a reference Id of '%d'", tamlRefToId );
119            return NULL;
120        }
121
122        // Return object.
123        return referenceItr->value;
124    }
125
126    // No, so fetch reference Id.
127    const U32 tamlRefId = getTamlRefId( typeValue );
128
129    // Create type.
130    SimObject* pSimObject = Taml::createType( engineTypeName, mpTaml );
131
132    // Finish if we couldn't create the type.
133    if ( pSimObject == NULL )
134        return NULL;
135
136    // Find Taml callbacks.
137    TamlCallbacks* pCallbacks = dynamic_cast<TamlCallbacks*>( pSimObject );
138
139    TamlCustomNodes customNodes;
140
141    // Are there any Taml callbacks?
142    if ( pCallbacks != NULL )
143    {
144        // Yes, so call it.
145        mpTaml->tamlPreRead( pCallbacks );
146    }
147
148    // Parse field members.
149    for( rapidjson::Value::ConstMemberIterator fieldMemberItr = typeValue.MemberBegin(); fieldMemberItr != typeValue.MemberEnd(); ++fieldMemberItr )
150    {
151        // Fetch value.
152        const rapidjson::Value& fieldValue = fieldMemberItr->value;
153        
154        // Skip if not a field.
155        if ( fieldValue.IsObject() )
156            continue;
157
158        // Parse as field.
159        parseField( fieldMemberItr, pSimObject );
160    }
161
162    // Fetch object name.
163    StringTableEntry objectName = StringTable->insert( getTamlObjectName( typeValue ) );
164
165    // Does the object require a name?
166    if ( objectName == StringTable->EmptyString() )
167    {
168        // No, so just register anonymously.
169        pSimObject->registerObject();
170    }
171    else
172    {
173        // Yes, so register a named object.
174        pSimObject->registerObject( objectName );
175
176        // Was the name assigned?
177        if ( pSimObject->getName() != objectName )
178        {
179            // No, so warn that the name was rejected.
180            Con::warnf( "Taml::parseType() - Registered an instance of type '%s' but a request to name it '%s' was rejected.  This is typically because an object of that name already exists.",
181                engineTypeName, objectName );
182        }
183    }
184
185    // Do we have a reference Id?
186    if ( tamlRefId != 0 )
187    {
188        // Yes, so insert reference.
189        mObjectReferenceMap.insertUnique( tamlRefId, pSimObject );
190    }
191
192    // Parse children and custom node members.
193    for( rapidjson::Value::ConstMemberIterator objectMemberItr = typeValue.MemberBegin(); objectMemberItr != typeValue.MemberEnd(); ++objectMemberItr )
194    {
195        // Fetch name and value.
196        const rapidjson::Value& objName = objectMemberItr->name;
197        const rapidjson::Value& objectValue = objectMemberItr->value;
198        
199        // Skip if not an object.
200        if ( !objectValue.IsObject() )
201            continue;
202
203        // Find the period character in the name.
204        const char* pPeriod = dStrchr( objName.GetString(), '.' );
205
206        // Did we find the period?
207        if ( pPeriod == NULL )
208        {
209            // No, so parse child object.
210            parseChild( objectMemberItr, pSimObject );
211            continue;
212        }
213
214        // Yes, so parse custom object.
215        parseCustom( objectMemberItr, pSimObject, pPeriod+1, customNodes );
216    }
217
218    // Call custom read.
219    if ( pCallbacks )
220    {
221        mpTaml->tamlCustomRead( pCallbacks, customNodes );
222        mpTaml->tamlPostRead( pCallbacks, customNodes );
223    }
224
225    // Return object.
226    return pSimObject;
227}
228
229//-----------------------------------------------------------------------------
230
231inline void TamlJSONReader::parseField( rapidjson::Value::ConstMemberIterator& memberItr, SimObject* pSimObject )
232{
233    // Debug Profiling.
234    PROFILE_SCOPE(TamlJSONReader_ParseField);
235
236    // Fetch name and value.
237    const rapidjson::Value& name = memberItr->name;
238    const rapidjson::Value& value = memberItr->value;
239
240    // Insert the field name.
241    StringTableEntry fieldName = StringTable->insert( name.GetString() );
242
243    // Ignore if this is a Taml attribute.
244    if (    fieldName == tamlRefIdName ||
245            fieldName == tamlRefToIdName ||
246            fieldName == tamlNamedObjectName )
247            return;
248
249    // Get field value.
250    char valueBuffer[4096];
251    if ( !parseStringValue( valueBuffer, sizeof(valueBuffer), value, fieldName ) )
252    {
253        // Warn.
254        Con::warnf( "Taml::parseField() Could not interpret value for field '%s'", fieldName );
255        return;
256    }
257
258    // Set field.
259    pSimObject->setPrefixedDataField(fieldName, NULL, valueBuffer);
260}
261
262//-----------------------------------------------------------------------------
263
264inline void TamlJSONReader::parseChild( rapidjson::Value::ConstMemberIterator& memberItr, SimObject* pSimObject )
265{
266    // Debug Profiling.
267    PROFILE_SCOPE(TamlJSONReader_ParseChild);
268
269    // Fetch name.
270    const rapidjson::Value& name = memberItr->name;
271
272    // Fetch the Taml children.
273    TamlChildren* pChildren = dynamic_cast<TamlChildren*>( pSimObject );
274
275    // Is this a Taml child?
276    if ( pChildren == NULL )
277    {
278        // No, so warn.
279        Con::warnf("Taml::parseChild() - Child member '%s' found under parent '%s' but object cannot have children.",
280            name.GetString(),
281            pSimObject->getClassName() );
282
283        return;
284    }
285
286    // Fetch any container child class specifier.
287    AbstractClassRep* pContainerChildClass = pSimObject->getClassRep()->getContainerChildClass( true );
288
289    // Parse child member.
290    SimObject* pChildSimObject = parseType( memberItr );
291
292    // Finish if the child was not created.
293    if ( pChildSimObject == NULL )
294        return;
295
296    // Do we have a container child class?
297    if ( pContainerChildClass != NULL )
298    {
299        // Yes, so is the child object the correctly derived type?
300        if ( !pChildSimObject->getClassRep()->isClass( pContainerChildClass ) )
301        {
302            // No, so warn.
303            Con::warnf("Taml::parseChild() - Child element '%s' found under parent '%s' but object is restricted to children of type '%s'.",
304                pChildSimObject->getClassName(),
305                pSimObject->getClassName(),
306                pContainerChildClass->getClassName() );
307
308            // NOTE: We can't delete the object as it may be referenced elsewhere!
309            pChildSimObject = NULL;
310
311            return;
312        }
313    }
314
315    // Add child.
316    pChildren->addTamlChild( pChildSimObject );
317
318    // Find Taml callbacks for child.
319    TamlCallbacks* pChildCallbacks = dynamic_cast<TamlCallbacks*>( pChildSimObject );
320
321    // Do we have callbacks on the child?
322    if ( pChildCallbacks != NULL )
323    {
324        // Yes, so perform callback.
325        mpTaml->tamlAddParent( pChildCallbacks, pSimObject );
326    }
327}
328
329//-----------------------------------------------------------------------------
330
331inline void TamlJSONReader::parseCustom( rapidjson::Value::ConstMemberIterator& memberItr, SimObject* pSimObject, const char* pCustomNodeName, TamlCustomNodes& customNodes )
332{
333    // Debug Profiling.
334    PROFILE_SCOPE(TamlJSONReader_ParseCustom);
335
336    // Fetch value.
337    const rapidjson::Value& value = memberItr->value;
338
339    // Add custom node.
340    TamlCustomNode* pCustomNode = customNodes.addNode( pCustomNodeName );
341
342    // Iterate members.
343    for( rapidjson::Value::ConstMemberIterator customMemberItr = value.MemberBegin(); customMemberItr != value.MemberEnd(); ++customMemberItr )
344    {
345        // Fetch value.
346        const rapidjson::Value& customValue = customMemberItr->value;
347
348        // Is the member an object?
349        if ( !customValue.IsObject() && !customValue.IsArray() )
350        {
351            // No, so warn.
352            Con::warnf( "Taml::parseCustom() - Cannot process custom node name '%s' member as child value is not an object or array.", pCustomNodeName );
353            return;
354        }
355
356        // Parse custom node.
357        parseCustomNode( customMemberItr, pCustomNode );
358    }
359}
360
361//-----------------------------------------------------------------------------
362
363inline void TamlJSONReader::parseCustomNode( rapidjson::Value::ConstMemberIterator& memberItr, TamlCustomNode* pCustomNode )
364{
365    // Debug Profiling.
366    PROFILE_SCOPE(TamlJSONReader_ParseCustomNode);
367
368    // Fetch name and value.
369    const rapidjson::Value& name = memberItr->name;
370    const rapidjson::Value& value = memberItr->value;
371
372    // Is the value an object?
373    if ( value.IsObject() )
374    {
375        // Yes, so is the node a proxy object?
376        if (  getTamlRefId( value ) != 0 || getTamlRefToId( value ) != 0 )
377        {
378            // Yes, so parse proxy object.
379            SimObject* pProxyObject = parseType( memberItr );
380
381            // Add child node.
382            pCustomNode->addNode( pProxyObject );
383
384            return;
385        }
386    }
387
388    char valueBuffer[4096];
389
390    // Fetch the node name.
391    StringTableEntry nodeName = getDemangledName( name.GetString() );
392
393    // Yes, so add child node.
394    TamlCustomNode* pChildNode = pCustomNode->addNode( nodeName );
395
396    // Is the value an array?
397    if ( value.IsArray() )
398    {
399        // Yes, so does it have a single entry?
400        if ( value.Size() == 1 )
401        {
402            // Yes, so parse the node text.
403            if ( parseStringValue( valueBuffer, sizeof(valueBuffer), *value.Begin(), nodeName ) )
404            {
405                pChildNode->setNodeText( valueBuffer );
406            }
407            else
408            {
409                // Warn.
410                Con::warnf( "Taml::parseCustomNode() - Encountered text in the custom node '%s' but could not interpret the value.", nodeName );
411            }
412        }
413        else
414        {
415            // No, so warn.
416            Con::warnf( "Taml::parseCustomNode() - Encountered text in the custom node '%s' but more than a single element was found in the array.", nodeName );
417        }
418
419        return;
420    }
421
422    // Iterate child members.
423    for( rapidjson::Value::ConstMemberIterator childMemberItr = value.MemberBegin(); childMemberItr != value.MemberEnd(); ++childMemberItr )
424    {
425        // Fetch name and value.
426        const rapidjson::Value& childName = childMemberItr->name;
427        const rapidjson::Value& childValue = childMemberItr->value;
428
429        // Fetch the field name.
430        StringTableEntry fieldName = StringTable->insert( childName.GetString() );
431
432        // Is the value an array?
433        if ( childValue.IsArray() )
434        {
435            // Yes, so does it have a single entry?
436            if ( childValue.Size() == 1 )
437            {
438                // Yes, so parse the node text.
439                if ( parseStringValue( valueBuffer, sizeof(valueBuffer), *childValue.Begin(), fieldName ) )
440                {
441                    // Yes, so add sub-child node.
442                    TamlCustomNode* pSubChildNode = pChildNode->addNode( fieldName );
443
444                    // Set sub-child text.
445                    pSubChildNode->setNodeText( valueBuffer );
446                    continue;
447                }
448
449                // Warn.
450                Con::warnf( "Taml::parseCustomNode() - Encountered text in the custom node '%s' but could not interpret the value.", fieldName );
451                return;
452            }
453
454            // No, so warn.
455            Con::warnf( "Taml::parseCustomNode() - Encountered text in the custom node '%s' but more than a single element was found in the array.", fieldName );
456            return;
457        }
458
459        // Is the member an object?
460        if ( childValue.IsObject() )
461        {
462            // Yes, so parse custom node.
463            parseCustomNode( childMemberItr, pChildNode );
464            continue;
465        }
466
467        // Ignore if this is a Taml attribute.
468        if (    fieldName == tamlRefIdName ||
469                fieldName == tamlRefToIdName ||
470                fieldName == tamlNamedObjectName )
471                continue;
472
473        // Parse string value.
474        if ( !parseStringValue( valueBuffer, sizeof(valueBuffer), childValue, childName.GetString() ) )
475        {
476            // Warn.
477            Con::warnf( "Taml::parseCustomNode() - Could not interpret value for field '%s'", fieldName );
478            continue;
479        }
480        
481        // Add node field.
482        pChildNode->addField( fieldName, valueBuffer );
483    }
484}
485
486//-----------------------------------------------------------------------------
487
488inline StringTableEntry TamlJSONReader::getDemangledName( const char* pMangledName )
489{
490    // Debug Profiling.
491    PROFILE_SCOPE(TamlJSONReader_GetDemangledName);
492
493    // Is the type name mangled?
494    if ( StringUnit::getUnitCount( pMangledName, JSON_RFC4627_NAME_MANGLING_CHARACTERS ) > 1 )
495    {
496        // Yes, so fetch type name portion.
497        return StringTable->insert( StringUnit::getUnit( pMangledName, 0, JSON_RFC4627_NAME_MANGLING_CHARACTERS ) );
498    }
499
500    // No, so use all the type name.
501    return StringTable->insert( pMangledName );
502}
503
504//-----------------------------------------------------------------------------
505
506inline bool TamlJSONReader::parseStringValue( char* pBuffer, const S32 bufferSize, const rapidjson::Value& value, const char* pName )
507{
508    // Debug Profiling.
509    PROFILE_SCOPE(TamlJSONReader_ParseStringValue);
510
511    // Handle field value appropriately.
512
513    if ( value.IsString() )
514    {
515        dSprintf( pBuffer, bufferSize, "%s", value.GetString() );
516        return true;
517    }
518
519    if ( value.IsNumber() )
520    {
521        if ( value.IsInt() )
522        {
523            dSprintf( pBuffer, bufferSize, "%d", value.GetInt() );
524            return true;
525        }
526
527        if ( value.IsUint() )
528        {
529            dSprintf( pBuffer, bufferSize, "%d", value.GetUint() );
530            return true;
531        }
532
533        if ( value.IsInt64() )
534        {
535            dSprintf( pBuffer, bufferSize, "%d", value.GetInt64() );
536            return true;
537        }
538
539        if ( value.IsUint64() )
540        {
541            dSprintf( pBuffer, bufferSize, "%d", value.GetUint64() );
542            return true;
543        }
544
545        if ( value.IsDouble() )
546        {
547            dSprintf( pBuffer, bufferSize, "%f", value.GetDouble() );
548            return true;
549        }
550    }
551
552    if ( value.IsBool() )
553    {
554        dSprintf( pBuffer, bufferSize, "%d", value.GetBool() );
555        return true;
556    }
557
558    // Failed to get value type.
559    Con::warnf( "Taml: Encountered a field '%s' but its value is an unknown type.", pName );
560    return false;
561}
562
563//-----------------------------------------------------------------------------
564
565inline U32 TamlJSONReader::getTamlRefId( const rapidjson::Value& value )
566{
567    // Debug Profiling.
568    PROFILE_SCOPE(TamlJSONReader_GetTamlRefId);
569
570    // Is the value an object?
571    if ( !value.IsObject()  )
572    {
573        // No, so warn.
574        Con::warnf( "Taml::getTamlRefId() - Cannot get '%s' member as value is not an object.", tamlRefIdName );
575        return 0;
576    }
577
578    // Iterate members.
579    for( rapidjson::Value::ConstMemberIterator memberItr = value.MemberBegin(); memberItr != value.MemberEnd(); ++memberItr )
580    {
581        // Insert member name.
582        StringTableEntry attributeName = StringTable->insert( memberItr->name.GetString() );
583
584        // Skip if not the correct attribute.
585        if ( attributeName != tamlRefIdName )
586            continue;
587
588        // Is the value an integer?
589        if ( !memberItr->value.IsInt() )
590        {
591            // No, so warn.
592            Con::warnf( "Taml::getTamlRefId() - Found '%s' member but it is not an integer.", tamlRefIdName );
593            return 0;
594        }
595
596        // Return it.
597        return (U32)memberItr->value.GetInt();
598    }
599
600    // Not found.
601    return 0;
602}
603
604//-----------------------------------------------------------------------------
605
606inline U32 TamlJSONReader::getTamlRefToId( const rapidjson::Value& value )
607{
608    // Debug Profiling.
609    PROFILE_SCOPE(TamlJSONReader_GetTamlRefToId);
610
611    // Is the value an object?
612    if ( !value.IsObject()  )
613    {
614        // No, so warn.
615        Con::warnf( "Taml::getTamlRefToId() - Cannot get '%s' member as value is not an object.", tamlRefToIdName );
616        return 0;
617    }
618
619    // Iterate members.
620    for( rapidjson::Value::ConstMemberIterator memberItr = value.MemberBegin(); memberItr != value.MemberEnd(); ++memberItr )
621    {
622        // Insert member name.
623        StringTableEntry attributeName = StringTable->insert( memberItr->name.GetString() );
624
625        // Skip if not the correct attribute.
626        if ( attributeName != tamlRefToIdName )
627            continue;
628
629        // Is the value an integer?
630        if ( !memberItr->value.IsInt() )
631        {
632            // No, so warn.
633            Con::warnf( "Taml::getTamlRefToId() - Found '%s' member but it is not an integer.", tamlRefToIdName );
634            return 0;
635        }
636
637        // Return it.
638        return (U32)memberItr->value.GetInt();
639    }
640
641    // Not found.
642    return 0;
643}
644
645//-----------------------------------------------------------------------------
646
647inline const char* TamlJSONReader::getTamlObjectName( const rapidjson::Value& value )
648{
649    // Debug Profiling.
650    PROFILE_SCOPE(TamlJSONReader_GetTamlObjectName);
651
652    // Is the value an object?
653    if ( !value.IsObject()  )
654    {
655        // No, so warn.
656        Con::warnf( "Taml::getTamlObjectName() - Cannot get '%s' member as value is not an object.", tamlNamedObjectName );
657        return 0;
658    }
659
660    // Iterate members.
661    for( rapidjson::Value::ConstMemberIterator memberItr = value.MemberBegin(); memberItr != value.MemberEnd(); ++memberItr )
662    {
663        // Insert member name.
664        StringTableEntry attributeName = StringTable->insert( memberItr->name.GetString() );
665
666        // Skip if not the correct attribute.
667        if ( attributeName != tamlNamedObjectName )
668            continue;
669
670        // Is the value an integer?
671        if ( !memberItr->value.IsString() )
672        {
673            // No, so warn.
674            Con::warnf( "Taml::getTamlObjectName() - Found '%s' member but it is not a string.", tamlNamedObjectName );
675            return NULL;
676        }
677
678        // Return it.
679        return memberItr->value.GetString();
680    }
681
682    // Not found.
683    return NULL;
684}
685
686
687
688