Torque3D Documentation / _generateds / tamlXmlReader.cpp

tamlXmlReader.cpp

Engine/source/persistence/taml/xml/tamlXmlReader.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/xml/tamlXmlReader.h"
 25
 26// Debug Profiling.
 27#include "platform/profiler.h"
 28#include "persistence/taml/fsTinyXml.h"
 29
 30//-----------------------------------------------------------------------------
 31
 32SimObject* TamlXmlReader::read( FileStream& stream )
 33{
 34    // Debug Profiling.
 35    PROFILE_SCOPE(TamlXmlReader_Read);
 36
 37    // Create document.
 38    fsTiXmlDocument xmlDocument;
 39
 40    // Load document from stream.
 41    if ( !xmlDocument.LoadFile( stream ) )
 42    {
 43        // Warn!
 44        Con::warnf("Taml: Could not load Taml XML file from stream.");
 45        return NULL;
 46    }
 47
 48    // Parse root element.
 49    SimObject* pSimObject = parseElement( xmlDocument.RootElement() );
 50
 51    // Reset parse.
 52    resetParse();
 53
 54    return pSimObject;
 55}
 56
 57//-----------------------------------------------------------------------------
 58
 59void TamlXmlReader::resetParse( void )
 60{
 61    // Debug Profiling.
 62    PROFILE_SCOPE(TamlXmlReader_ResetParse);
 63
 64    // Clear object reference map.
 65    mObjectReferenceMap.clear();
 66}
 67
 68//-----------------------------------------------------------------------------
 69
 70SimObject* TamlXmlReader::parseElement( TiXmlElement* pXmlElement )
 71{
 72    // Debug Profiling.
 73    PROFILE_SCOPE(TamlXmlReader_ParseElement);
 74
 75    SimObject* pSimObject = NULL;
 76
 77    // Fetch element name.
 78    StringTableEntry typeName = StringTable->insert( pXmlElement->Value() );
 79
 80    // Fetch reference to Id.
 81    const U32 tamlRefToId = getTamlRefToId( pXmlElement );
 82
 83    // Do we have a reference to Id?
 84    if ( tamlRefToId != 0 )
 85    {
 86        // Yes, so fetch reference.
 87        typeObjectReferenceHash::Iterator referenceItr = mObjectReferenceMap.find( tamlRefToId );
 88
 89        // Did we find the reference?
 90        if ( referenceItr == mObjectReferenceMap.end() )
 91        {
 92            // No, so warn.
 93            Con::warnf( "Taml: Could not find a reference Id of '%d'", tamlRefToId );
 94            return NULL;
 95        }
 96
 97        // Return object.
 98        return referenceItr->value;
 99    }
100
101    // No, so fetch reference Id.
102    const U32 tamlRefId = getTamlRefId( pXmlElement );
103
104#ifdef TORQUE_DEBUG
105    // Format the type location.
106    char typeLocationBuffer[64];
107    dSprintf( typeLocationBuffer, sizeof(typeLocationBuffer), "Taml [format='xml' row=%d column=%d]", pXmlElement->Row(), pXmlElement->Column() );    
108
109    // Create type.
110    pSimObject = Taml::createType( typeName, mpTaml, typeLocationBuffer );
111#else
112    // Create type.
113    pSimObject = Taml::createType( typeName, mpTaml );
114#endif
115
116
117    // Finish if we couldn't create the type.
118    if ( pSimObject == NULL )
119        return NULL;
120
121    // Find Taml callbacks.
122    TamlCallbacks* pCallbacks = dynamic_cast<TamlCallbacks*>( pSimObject );
123
124    // Are there any Taml callbacks?
125    if ( pCallbacks != NULL )
126    {
127        // Yes, so call it.
128        mpTaml->tamlPreRead( pCallbacks );
129    }
130
131    // Parse attributes.
132    parseAttributes( pXmlElement, pSimObject );
133
134    // Fetch object name.
135    StringTableEntry objectName = StringTable->insert( getTamlObjectName( pXmlElement ) );
136
137    // Does the object require a name?
138    if ( objectName == StringTable->EmptyString() )
139    {
140        // No, so just register anonymously.
141        pSimObject->registerObject();
142    }
143    else
144    {
145        // Yes, so register a named object.
146        pSimObject->registerObject( objectName );
147
148        // Was the name assigned?
149        if ( pSimObject->getName() != objectName )
150        {
151            // No, so warn that the name was rejected.
152#ifdef TORQUE_DEBUG
153            Con::warnf( "Taml::parseElement() - 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.  '%s'", typeName, objectName, typeLocationBuffer );
154#else
155            Con::warnf( "Taml::parseElement() - 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.", typeName, objectName );
156#endif
157        }
158    }
159
160
161    // Do we have a reference Id?
162    if ( tamlRefId != 0 )
163    {
164        // Yes, so insert reference.
165        mObjectReferenceMap.insertUnique( tamlRefId, pSimObject );
166    }
167
168    // Fetch any children.
169    TiXmlNode* pChildXmlNode = pXmlElement->FirstChild();
170
171    TamlCustomNodes customProperties;
172
173    // Do we have any element children?
174    if ( pChildXmlNode != NULL )
175    {
176        // Fetch the Taml children.
177        TamlChildren* pChildren = dynamic_cast<TamlChildren*>( pSimObject );
178
179        // Fetch any container child class specifier.
180        AbstractClassRep* pContainerChildClass = pSimObject->getClassRep()->getContainerChildClass( true );
181
182        // Iterate siblings.
183        do
184        {
185            // Fetch element.
186            TiXmlElement* pChildXmlElement = dynamic_cast<TiXmlElement*>( pChildXmlNode );
187
188            // Move to next sibling.
189            pChildXmlNode = pChildXmlNode->NextSibling();
190
191            // Skip if this is not an element?
192            if ( pChildXmlElement == NULL )
193                continue;
194
195            // Is this a standard child element?
196            if ( dStrchr( pChildXmlElement->Value(), '.' ) == NULL )
197            {
198                // Is this a Taml child?
199                if ( pChildren == NULL )
200                {
201                    // No, so warn.
202                    Con::warnf("Taml: Child element '%s' found under parent '%s' but object cannot have children.",
203                        pChildXmlElement->Value(),
204                        pXmlElement->Value() );
205
206                    // Skip.
207                    continue;
208                }
209
210                // Yes, so parse child element.
211                SimObject* pChildSimObject = parseElement( pChildXmlElement );
212
213                // Skip if the child was not created.
214                if ( pChildSimObject == NULL )
215                    continue;
216
217                // Do we have a container child class?
218                if ( pContainerChildClass != NULL )
219                {
220                    // Yes, so is the child object the correctly derived type?
221                    if ( !pChildSimObject->getClassRep()->isClass( pContainerChildClass ) )
222                    {
223                        // No, so warn.
224                        Con::warnf("Taml: Child element '%s' found under parent '%s' but object is restricted to children of type '%s'.",
225                            pChildSimObject->getClassName(),
226                            pSimObject->getClassName(),
227                            pContainerChildClass->getClassName() );
228
229                        // NOTE: We can't delete the object as it may be referenced elsewhere!
230                        pChildSimObject = NULL;
231
232                        // Skip.
233                        continue;
234                    }
235                }
236
237                // Add child.
238                pChildren->addTamlChild( pChildSimObject );
239
240                // Find Taml callbacks for child.
241                TamlCallbacks* pChildCallbacks = dynamic_cast<TamlCallbacks*>( pChildSimObject );
242
243                // Do we have callbacks on the child?
244                if ( pChildCallbacks != NULL )
245                {
246                    // Yes, so perform callback.
247                    mpTaml->tamlAddParent( pChildCallbacks, pSimObject );
248                }
249            }
250            else
251            {
252                // No, so parse custom element.
253                parseCustomElement( pChildXmlElement, customProperties );
254            }
255        }
256        while( pChildXmlNode != NULL );
257
258        // Call custom read.
259        mpTaml->tamlCustomRead( pCallbacks, customProperties );
260    }
261
262    // Are there any Taml callbacks?
263    if ( pCallbacks != NULL )
264    {
265        // Yes, so call it.
266        mpTaml->tamlPostRead( pCallbacks, customProperties );
267    }
268
269    // Return object.
270    return pSimObject;
271}
272
273//-----------------------------------------------------------------------------
274
275void TamlXmlReader::parseAttributes( TiXmlElement* pXmlElement, SimObject* pSimObject )
276{
277    // Debug Profiling.
278    PROFILE_SCOPE(TamlXmlReader_ParseAttributes);
279
280    // Sanity!
281    AssertFatal( pSimObject != NULL, "Taml: Cannot parse attributes on a NULL object." );
282
283    // Iterate attributes.
284    for ( TiXmlAttribute* pAttribute = pXmlElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->Next() )
285    {
286        // Insert attribute name.
287        StringTableEntry attributeName = StringTable->insert( pAttribute->Name() );
288
289        // Ignore if this is a Taml attribute.
290        if (    attributeName == tamlRefIdName ||
291                attributeName == tamlRefToIdName ||
292                attributeName == tamlNamedObjectName )
293            continue;
294
295        // Set the field.
296        pSimObject->setPrefixedDataField(attributeName, NULL, pAttribute->Value());
297    }
298}
299
300//-----------------------------------------------------------------------------
301
302void TamlXmlReader::parseCustomElement( TiXmlElement* pXmlElement, TamlCustomNodes& customNodes )
303{
304    // Debug Profiling.
305    PROFILE_SCOPE(TamlXmlReader_ParseCustomElement);
306
307    // Is this a standard child element?
308    const char* pPeriod = dStrchr( pXmlElement->Value(), '.' );
309
310    // Sanity!
311    AssertFatal( pPeriod != NULL, "Parsing extended element but no period character found." );
312
313    // Fetch any custom XML node.
314    TiXmlNode* pCustomXmlNode = pXmlElement->FirstChild();
315
316    // Finish is no XML node exists.
317    if ( pCustomXmlNode == NULL )
318        return;
319
320    // Yes, so add custom node.
321    TamlCustomNode* pCustomNode = customNodes.addNode( pPeriod+1 );
322
323    do
324    {
325        // Fetch element.
326        TiXmlElement* pCustomXmlElement = dynamic_cast<TiXmlElement*>( pCustomXmlNode );
327
328        // Move to next sibling.
329        pCustomXmlNode = pCustomXmlNode->NextSibling();
330
331        // Skip if this is not an element.
332        if ( pCustomXmlElement == NULL )
333            continue;
334
335        // Parse custom node.
336        parseCustomNode( pCustomXmlElement, pCustomNode );
337    }
338    while ( pCustomXmlNode != NULL );
339}
340
341//-----------------------------------------------------------------------------
342
343void TamlXmlReader::parseCustomNode( TiXmlElement* pXmlElement, TamlCustomNode* pCustomNode )
344{
345    // Is the node a proxy object?
346    if (  getTamlRefId( pXmlElement ) != 0 || getTamlRefToId( pXmlElement ) != 0 )
347    {
348        // Yes, so parse proxy object.
349        SimObject* pProxyObject = parseElement( pXmlElement );
350
351        // Add child node.
352        pCustomNode->addNode( pProxyObject );
353
354        return;
355    }
356
357    // Yes, so add child node.
358    TamlCustomNode* pChildNode = pCustomNode->addNode( pXmlElement->Value() );
359
360    // Iterate attributes.
361    for ( TiXmlAttribute* pAttribute = pXmlElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->Next() )
362    {
363        // Insert attribute name.
364        StringTableEntry attributeName = StringTable->insert( pAttribute->Name() );
365
366        // Skip if a Taml reference attribute.
367        if ( attributeName == tamlRefIdName || attributeName == tamlRefToIdName )
368            continue;
369
370        // Add node field.
371        pChildNode->addField( attributeName, pAttribute->Value() );
372    }
373
374    // Fetch any element text.
375    const char* pElementText = pXmlElement->GetText();
376
377    // Do we have any element text?
378    if ( pElementText != NULL )
379    {
380        // Yes, so store it.
381        pChildNode->setNodeText( pElementText );
382    }
383
384    // Fetch any children.
385    TiXmlNode* pChildXmlNode = pXmlElement->FirstChild();
386
387    // Do we have any element children?
388    if ( pChildXmlNode != NULL )
389    {
390        do
391        {
392            // Yes, so fetch child element.
393            TiXmlElement* pChildXmlElement = dynamic_cast<TiXmlElement*>( pChildXmlNode );
394
395            // Move to next sibling.
396            pChildXmlNode = pChildXmlNode->NextSibling();
397
398            // Skip if this is not an element.
399            if ( pChildXmlElement == NULL )
400                continue;
401
402            // Parse custom node.
403            parseCustomNode( pChildXmlElement, pChildNode );
404        }
405        while( pChildXmlNode != NULL );
406    }
407}
408
409//-----------------------------------------------------------------------------
410
411U32 TamlXmlReader::getTamlRefId( TiXmlElement* pXmlElement )
412{
413    // Debug Profiling.
414    PROFILE_SCOPE(TamlXmlReader_GetTamlRefId);
415
416    // Iterate attributes.
417    for ( TiXmlAttribute* pAttribute = pXmlElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->Next() )
418    {
419        // Insert attribute name.
420        StringTableEntry attributeName = StringTable->insert( pAttribute->Name() );
421
422        // Skip if not the correct attribute.
423        if ( attributeName != tamlRefIdName )
424            continue;
425
426        // Return it.
427        return dAtoi( pAttribute->Value() );
428    }
429
430    // Not found.
431    return 0;
432}
433
434//-----------------------------------------------------------------------------
435
436U32 TamlXmlReader::getTamlRefToId( TiXmlElement* pXmlElement )
437{
438    // Debug Profiling.
439    PROFILE_SCOPE(TamlXmlReader_GetTamlRefToId);
440
441    // Iterate attributes.
442    for ( TiXmlAttribute* pAttribute = pXmlElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->Next() )
443    {
444        // Insert attribute name.
445        StringTableEntry attributeName = StringTable->insert( pAttribute->Name() );
446
447        // Skip if not the correct attribute.
448        if ( attributeName != tamlRefToIdName )
449            continue;
450
451        // Return it.
452        return dAtoi( pAttribute->Value() );
453    }
454
455    // Not found.
456    return 0;
457}
458
459//-----------------------------------------------------------------------------
460
461const char* TamlXmlReader::getTamlObjectName( TiXmlElement* pXmlElement )
462{
463    // Debug Profiling.
464    PROFILE_SCOPE(TamlXmlReader_GetTamlObjectName);
465
466    // Iterate attributes.
467    for ( TiXmlAttribute* pAttribute = pXmlElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->Next() )
468    {
469        // Insert attribute name.
470        StringTableEntry attributeName = StringTable->insert( pAttribute->Name() );
471
472        // Skip if not the correct attribute.
473        if ( attributeName != tamlNamedObjectName )
474            continue;
475
476        // Return it.
477        return pAttribute->Value();
478    }
479
480    // Not found.
481    return NULL;
482}
483
484
485
486