tamlCustom.h

Engine/source/persistence/taml/tamlCustom.h

More...

Classes:

Public Defines

Public Typedefs

TamlCustomFieldVector 
TamlCustomNodeVector 

Detailed Description

Public Defines

MAX_TAML_NODE_FIELDVALUE_LENGTH() 2048

Public Typedefs

typedef Vector< TamlCustomField * > TamlCustomFieldVector 
typedef Vector< TamlCustomNode * > TamlCustomNodeVector 

Public Variables

FactoryCache< TamlCustomField > TamlCustomFieldFactory 
FactoryCache< TamlCustomNode > TamlCustomNodeFactory 
  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#ifndef _TAML_CUSTOM_H_
 25#define _TAML_CUSTOM_H_
 26
 27#ifndef _FACTORY_CACHE_H_
 28#include "core/factoryCache.h"
 29#endif
 30
 31#ifndef _STRINGTABLE_H_
 32#include "core/stringTable.h"
 33#endif
 34
 35#ifndef _CONSOLE_H_
 36#include "console/console.h"
 37#endif
 38
 39#ifndef _CONSOLETYPES_H_
 40#include "console/consoleTypes.h"
 41#endif
 42
 43#ifndef B2_MATH_H
 44//TODO: Look at this
 45//#include "box2d/Common/b2Math.h"
 46#endif
 47
 48#ifndef _COLOR_H_
 49#include "core/color.h"
 50#endif
 51
 52#ifndef _SIMBASE_H_
 53#include "console/simBase.h"
 54#endif
 55
 56#include "core/util/safeDelete.h"
 57
 58#include "math/mMath.h"
 59
 60//-----------------------------------------------------------------------------
 61
 62#define MAX_TAML_NODE_FIELDVALUE_LENGTH 2048
 63
 64//-----------------------------------------------------------------------------
 65
 66class TamlWriteNode;
 67class TamlCustomNode;
 68class TamlCustomField;
 69extern FactoryCache<TamlCustomNode> TamlCustomNodeFactory;
 70extern FactoryCache<TamlCustomField> TamlCustomFieldFactory;
 71typedef Vector<TamlCustomNode*> TamlCustomNodeVector;
 72typedef Vector<TamlCustomField*> TamlCustomFieldVector;
 73
 74//-----------------------------------------------------------------------------
 75
 76class TamlCustomField : public IFactoryObjectReset
 77{
 78public:
 79    TamlCustomField()
 80    {
 81        resetState();
 82    }
 83
 84    virtual ~TamlCustomField()
 85    {
 86        // Everything should already be cleared in a state reset.
 87        // Touching any memory here is dangerous as this type is typically
 88        // held in a static factory cache until shutdown at which point
 89        // pretty much anything or everything could be invalid!
 90    }
 91
 92    virtual void resetState( void )
 93    {
 94        mFieldName = StringTable->EmptyString();
 95        *mFieldValue = 0;
 96    }
 97
 98    void set( const char* pFieldName, const char* pFieldValue );
 99
100    inline void setFieldValue( const char* pFieldName, const ColorI& fieldValue )
101    {
102        // Fetch the field value.
103        const char* pFieldValue = Con::getData( TypeColorI, &const_cast<ColorI&>(fieldValue), 0 );
104
105        // Did we get a field value?
106        if ( pFieldValue == NULL )
107        {
108            // No, so warn.
109            Con::warnf( "Taml: Failed to add node field name '%s' with ColorI value.", pFieldName );
110            pFieldValue = StringTable->EmptyString();
111        }
112
113        set( pFieldName, pFieldValue );
114    }
115
116    inline void setFieldValue( const char* pFieldName, const LinearColorF& fieldValue )
117    {
118        // Fetch the field value.
119        const char* pFieldValue = Con::getData( TypeColorF, &const_cast<LinearColorF&>(fieldValue), 0 );
120
121        // Did we get a field value?
122        if ( pFieldValue == NULL )
123        {
124            // No, so warn.
125            Con::warnf( "Taml: Failed to add node field name '%s' with LinearColorF value.", pFieldName );
126            pFieldValue = StringTable->EmptyString();
127        }
128
129        set( pFieldName, pFieldValue );
130    }
131
132    inline void setFieldValue( const char* pFieldName, const Point2I& fieldValue )
133    {
134        char fieldValueBuffer[32];
135        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d %d", fieldValue.x, fieldValue.y );
136        set( pFieldName, fieldValueBuffer );
137    }
138
139    inline void setFieldValue( const char* pFieldName, const Point2F& fieldValue )
140    {
141        char fieldValueBuffer[32];
142        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g %0.5g", fieldValue.x, fieldValue.y );
143        set( pFieldName, fieldValueBuffer );
144    }
145
146    inline void setFieldValue( const char* pFieldName, const Point3I& fieldValue )
147    {
148        char fieldValueBuffer[32];
149        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d %d %d", fieldValue.x, fieldValue.y, fieldValue.z );
150        set( pFieldName, fieldValueBuffer );
151    }
152    
153    inline void setFieldValue( const char* pFieldName, const Point3F& fieldValue )
154    {
155        char fieldValueBuffer[32];
156        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g %0.5g %.5g", fieldValue.x, fieldValue.y, fieldValue.z );
157        set( pFieldName, fieldValueBuffer );
158    }
159    
160    inline void setFieldValue( const char* pFieldName, const RectF& fieldValue )
161    {
162        char fieldValueBuffer[32];
163        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g %0.5g %.5g %.5g", 
164           fieldValue.point.x, fieldValue.point.y, fieldValue.extent.x, fieldValue.extent.y);
165        set( pFieldName, fieldValueBuffer );
166    }
167    
168    inline void setFieldValue( const char* pFieldName, const QuatF& fieldValue )
169    {
170        char fieldValueBuffer[32];
171        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g %0.5g %.5g %.5g", fieldValue.x, fieldValue.y, fieldValue.z, fieldValue.w );
172        set( pFieldName, fieldValueBuffer );
173    }
174    
175    inline void setFieldValue( const char* pFieldName, const AngAxisF& fieldValue )
176    {
177        char fieldValueBuffer[32];
178        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g %0.5g %.5g %.5g", fieldValue.axis.x, fieldValue.axis.y, fieldValue.axis.z, fieldValue.angle );
179        set( pFieldName, fieldValueBuffer );
180    }
181
182    inline void setFieldValue( const char* pFieldName, const U32 fieldValue )
183    {
184        char fieldValueBuffer[16];
185        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d", fieldValue );
186        set( pFieldName, fieldValueBuffer );
187    }
188
189    inline void setFieldValue( const char* pFieldName, const bool fieldValue )
190    {
191        char fieldValueBuffer[16];
192        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d", fieldValue );
193        set( pFieldName, fieldValueBuffer );
194    }
195
196    inline void setFieldValue( const char* pFieldName, const S32 fieldValue )
197    {
198        char fieldValueBuffer[16];
199        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d", fieldValue );
200        set( pFieldName, fieldValueBuffer );
201    }
202
203    inline void setFieldValue( const char* pFieldName, const float fieldValue )
204    {
205        char fieldValueBuffer[16];
206        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g", fieldValue );
207        set( pFieldName, fieldValueBuffer );
208    }
209
210    inline void setFieldValue( const char* pFieldName, const char* fieldValue )
211    {
212        set( pFieldName, fieldValue );
213    }
214
215    inline void getFieldValue( LinearColorF& fieldValue ) const
216    {
217        fieldValue.set( 1.0f, 1.0f, 1.0f, 1.0f );
218
219        // Set color.
220        const char* argv = (char*)mFieldValue;
221        Con::setData( TypeColorF, &fieldValue, 0, 1, &argv );
222    }
223
224    inline void getFieldValue( ColorI& fieldValue ) const
225    {
226        fieldValue.set( 255, 255, 255, 255 );
227
228        // Set color.
229        const char* argv = (char*)mFieldValue;
230        Con::setData( TypeColorI, &fieldValue, 0, 1, &argv );
231    }
232
233    inline void getFieldValue( Point2I& fieldValue ) const
234    {
235        if ( dSscanf( mFieldValue, "%d %d", &fieldValue.x, &fieldValue.y ) != 2 )
236        {
237            // Warn.
238            Con::warnf( "TamlCustomField - Reading point2I but it has an incorrect format: '%s'.", mFieldValue );
239        }
240    }
241
242    inline void getFieldValue( Point2F& fieldValue ) const
243    {
244        if ( dSscanf( mFieldValue, "%g %g", &fieldValue.x, &fieldValue.y ) != 2 )
245        {
246            // Warn.
247            Con::warnf( "TamlCustomField - Reading point2F but it has an incorrect format: '%s'.", mFieldValue );
248        }
249    }
250
251    inline void getFieldValue( Point3I& fieldValue ) const
252    {
253       if ( dSscanf( mFieldValue, "%d %d %d", &fieldValue.x, &fieldValue.y, &fieldValue.z ) != 3 )
254        {
255            // Warn.
256            Con::warnf( "TamlCustomField - Reading point3I but it has an incorrect format: '%s'.", mFieldValue );
257        }
258    }
259
260    inline void getFieldValue( Point3F& fieldValue ) const
261    {
262        if ( dSscanf( mFieldValue, "%g %g %g", &fieldValue.x, &fieldValue.y, &fieldValue.z ) != 3 )
263        {
264            // Warn.
265            Con::warnf( "TamlCustomField - Reading point3F but it has an incorrect format: '%s'.", mFieldValue );
266        }
267    }
268
269    inline void getFieldValue( RectF& fieldValue ) const
270    {
271        if ( dSscanf( mFieldValue, "%g %g %g %g", &fieldValue.point.x, &fieldValue.point.y, &fieldValue.extent.x, &fieldValue.extent.y ) != 3 )
272        {
273            // Warn.
274            Con::warnf( "TamlCustomField - Reading RectF but it has an incorrect format: '%s'.", mFieldValue );
275        }
276    }
277    
278    inline void getFieldValue( QuatF& fieldValue ) const
279    {
280        if ( dSscanf( mFieldValue, "%g %g %g %g", &fieldValue.x, &fieldValue.y, &fieldValue.z, &fieldValue.w ) != 4 )
281        {
282            // Warn.
283            Con::warnf( "TamlCustomField - Reading QuatF but it has an incorrect format: '%s'.", mFieldValue );
284        }
285    }
286    
287    inline void getFieldValue( AngAxisF& fieldValue ) const
288    {
289        if ( dSscanf( mFieldValue, "%g %g %g %g", &fieldValue.axis.x, &fieldValue.axis.y, &fieldValue.axis.z, &fieldValue.angle ) != 4 )
290        {
291            // Warn.
292            Con::warnf( "TamlCustomField - Reading AngAxisF but it has an incorrect format: '%s'.", mFieldValue );
293        }
294    }
295
296    inline void getFieldValue( bool& fieldValue ) const
297    {
298        fieldValue = dAtob( mFieldValue );
299    }
300
301    inline void getFieldValue( S32& fieldValue ) const
302    {
303        fieldValue = dAtoi( mFieldValue );
304    }
305
306    inline void getFieldValue( U32& fieldValue ) const
307    {
308        fieldValue = (U32)dAtoi( mFieldValue );
309    }
310
311    inline void getFieldValue( F32& fieldValue ) const
312    {
313        fieldValue = dAtof( mFieldValue );
314    }
315
316    inline const char* getFieldValue( void ) const
317    {
318        return mFieldValue;
319    }
320
321    inline StringTableEntry getFieldName( void ) const { return mFieldName; }
322
323    bool fieldNameBeginsWith( const char* pComparison ) const
324    {
325        const U32 comparisonLength = dStrlen( pComparison );
326        const U32 fieldNameLength = dStrlen( mFieldName );
327
328        if ( comparisonLength == 0 || fieldNameLength == 0 || comparisonLength > fieldNameLength )
329            return false;
330
331        StringTableEntry comparison = StringTable->insert( pComparison );
332
333        char fieldNameBuffer[1024];
334
335        // Sanity!
336        AssertFatal( fieldNameLength < sizeof(fieldNameBuffer), "TamlCustomField: Field name is too long." );
337
338        dStrcpy( fieldNameBuffer, mFieldName, 1024 );
339        fieldNameBuffer[fieldNameLength-1] = 0;
340        StringTableEntry fieldName = StringTable->insert( fieldNameBuffer );
341
342        return ( fieldName == comparison );
343    }
344
345    inline bool isValueEmpty( void ) const { return *mFieldValue == 0; }
346
347private:
348    StringTableEntry    mFieldName;
349    char                mFieldValue[MAX_TAML_NODE_FIELDVALUE_LENGTH];
350};
351
352//-----------------------------------------------------------------------------
353
354class TamlCustomNode : public IFactoryObjectReset
355{
356public:
357    TamlCustomNode()
358    {
359        // Reset proxy object.
360        // NOTE: This MUST be done before the state is reset otherwise we'll be touching uninitialized stuff.
361        mpProxyWriteNode = NULL;
362        mpProxyObject = NULL;
363
364        resetState();
365    }
366
367    virtual ~TamlCustomNode()
368    {
369        // Everything should already be cleared in a state reset.
370        // Touching any memory here is dangerous as this type is typically
371        // held in a static factory cache until shutdown at which point
372        // pretty much anything or everything could be invalid!
373    }
374
375    virtual void resetState( void )
376    {
377        // We don't need to delete the write node as it'll get destroyed when the compilation is reset!
378        mpProxyWriteNode = NULL;
379        mpProxyObject = NULL;
380
381        // Cache the children.
382        while ( mChildren.size() > 0 )
383        {
384            TamlCustomNodeFactory.cacheObject( mChildren.back() );
385            mChildren.pop_back();
386        }
387
388        // Cache the fields.
389        while( mFields.size() > 0 )
390        {
391            TamlCustomFieldFactory.cacheObject( mFields.back() );
392            mFields.pop_back();
393        }
394
395        // Reset the node name.
396        mNodeName = StringTable->EmptyString();
397
398        // Reset node text.
399        mNodeText.resetState();
400
401        // Reset the ignore empty flag.
402        mIgnoreEmpty = false;
403    }
404
405    inline TamlCustomNode* addNode( SimObject* pProxyObject )
406    {
407        // Sanity!
408        AssertFatal( pProxyObject != NULL, "Field object cannot be NULL." );
409        AssertFatal( mpProxyWriteNode == NULL, "Field write node must be NULL." );
410
411        // Create a custom node.
412        TamlCustomNode* pCustomNode = TamlCustomNodeFactory.createObject();
413
414        // Set node name.
415        pCustomNode->setNodeName( pProxyObject->getClassName() );
416
417        // Set proxy object.
418        pCustomNode->mpProxyObject = pProxyObject;
419
420        // Store node.
421        mChildren.push_back( pCustomNode );
422
423        return pCustomNode;
424    }
425
426    inline TamlCustomNode* addNode( const char* pNodeName, const bool ignoreEmpty = true )
427    {
428        // Create a custom node.
429        TamlCustomNode* pCustomNode = TamlCustomNodeFactory.createObject();
430
431        // Fetch node name.
432        pCustomNode->setNodeName( pNodeName );
433
434        // Set ignore-empty flag.
435        pCustomNode->setIgnoreEmpty( ignoreEmpty );
436
437        // Store node.
438        mChildren.push_back( pCustomNode );
439
440        return pCustomNode;
441    }
442
443    inline void removeNode( const U32 index )
444    {
445        // Sanity!
446        AssertFatal( index < (U32)mChildren.size(), "tamlCustomNode::removeNode() - Index is out of bounds." );
447
448        // Cache the custom node.
449        TamlCustomNodeFactory.cacheObject( mChildren[index] );
450
451        // Remove it.
452        mChildren.erase( index );
453    }
454
455    inline const TamlCustomNode* findNode( const char* pNodeName ) const
456    {
457        // Sanity!
458        AssertFatal( pNodeName != NULL, "Cannot find Taml node name that is NULL." );
459
460        // Fetch node name.
461        StringTableEntry nodeName = StringTable->insert( pNodeName );
462
463        // Find node.
464        for( Vector<TamlCustomNode*>::const_iterator nodeItr = mChildren.begin(); nodeItr != mChildren.end(); ++nodeItr )
465        {
466            if ( (*nodeItr)->getNodeName() == nodeName )
467                return (*nodeItr);
468        }
469
470        return NULL;
471    }
472
473    inline TamlCustomField* addField( const char* pFieldName, const ColorI& fieldValue )
474    {
475        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
476        pNodeField->setFieldValue( pFieldName, fieldValue );
477        return registerField( pNodeField );
478    }
479
480    inline TamlCustomField* addField( const char* pFieldName, const LinearColorF& fieldValue )
481    {
482        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
483        pNodeField->setFieldValue( pFieldName, fieldValue );
484        return registerField( pNodeField );
485    }
486
487    inline TamlCustomField* addField( const char* pFieldName, const Point2I& fieldValue )
488    {
489        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
490        pNodeField->setFieldValue( pFieldName, fieldValue );
491        return registerField( pNodeField );
492
493    }
494
495    inline TamlCustomField* addField( const char* pFieldName, const Point2F& fieldValue )
496    {
497        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
498        pNodeField->setFieldValue( pFieldName, fieldValue );
499        return registerField( pNodeField );
500    }
501
502    inline TamlCustomField* addField( const char* pFieldName, const Point3I& fieldValue )
503    {
504        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
505        pNodeField->setFieldValue( pFieldName, fieldValue );
506        return registerField( pNodeField );
507
508    }
509
510    inline TamlCustomField* addField( const char* pFieldName, const Point3F& fieldValue )
511    {
512        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
513        pNodeField->setFieldValue( pFieldName, fieldValue );
514        return registerField( pNodeField );
515    }
516
517    inline TamlCustomField* addField( const char* pFieldName, const RectF& fieldValue )
518    {
519        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
520        pNodeField->setFieldValue( pFieldName, fieldValue );
521        return registerField( pNodeField );
522    }
523    
524    inline TamlCustomField* addField( const char* pFieldName, const QuatF& fieldValue )
525    {
526        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
527        pNodeField->setFieldValue( pFieldName, fieldValue );
528        return registerField( pNodeField );
529    }
530    
531    inline TamlCustomField* addField( const char* pFieldName, const AngAxisF& fieldValue )
532    {
533        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
534        pNodeField->setFieldValue( pFieldName, fieldValue );
535        return registerField( pNodeField );
536    }
537
538    inline TamlCustomField* addField( const char* pFieldName, const U32 fieldValue )
539    {
540        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
541        pNodeField->setFieldValue( pFieldName, fieldValue );
542        return registerField( pNodeField );
543    }
544
545    inline TamlCustomField* addField( const char* pFieldName, const bool fieldValue )
546    {
547        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
548        pNodeField->setFieldValue( pFieldName, fieldValue );
549        return registerField( pNodeField );
550    }
551
552    inline TamlCustomField* addField( const char* pFieldName, const S32 fieldValue )
553    {
554        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
555        pNodeField->setFieldValue( pFieldName, fieldValue );
556        return registerField( pNodeField );
557    }
558
559    inline TamlCustomField* addField( const char* pFieldName, const float fieldValue )
560    {
561        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
562        pNodeField->setFieldValue( pFieldName, fieldValue );
563        return registerField( pNodeField );
564    }
565
566    inline TamlCustomField* addField( const char* pFieldName, const char* fieldValue )
567    {
568        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
569        pNodeField->setFieldValue( pFieldName, fieldValue );
570        return registerField( pNodeField );
571    }
572
573    inline const TamlCustomField* findField( const char* pFieldName ) const
574    {
575        // Sanity!
576        AssertFatal( pFieldName != NULL, "Cannot find Taml field name that is NULL." );
577
578        // Fetch field name.
579        StringTableEntry fieldName = StringTable->insert( pFieldName );
580
581        // Find node field.
582        for( TamlCustomFieldVector::const_iterator fieldItr = mFields.begin(); fieldItr != mFields.end(); ++fieldItr )
583        {
584            if ( (*fieldItr)->getFieldName() == fieldName )
585                return (*fieldItr);
586        }
587
588        return NULL;
589    }
590
591    inline void setNodeName( const char* pNodeName )
592    {
593        // Sanity!
594        AssertFatal( pNodeName != NULL, "Cannot add a NULL node name." );
595
596        mNodeName = StringTable->insert( pNodeName );
597    }
598
599    inline StringTableEntry getNodeName( void ) const { return mNodeName; }
600
601    void setWriteNode( TamlWriteNode* pWriteNode );
602
603    inline void setNodeText( const char* pNodeText )
604    {
605        AssertFatal( dStrlen( pNodeText ) < MAX_TAML_NODE_FIELDVALUE_LENGTH, "Custom node text is too long." );
606
607        mNodeText.set( StringTable->EmptyString(), pNodeText );
608    }
609    inline const TamlCustomField& getNodeTextField( void ) const { return mNodeText; }
610    inline TamlCustomField& getNodeTextField( void ) { return mNodeText; }
611
612    inline const Vector<TamlCustomNode*>& getChildren( void ) const { return mChildren; }
613    inline const TamlCustomFieldVector& getFields( void ) const { return mFields; }
614
615    inline bool isProxyObject( void ) const { return mpProxyObject != NULL; }
616    template<typename T> T* getProxyObject( const bool deleteIfNotType ) const
617    {
618        // Return nothing if no proxy object.
619        if ( mpProxyObject == NULL )
620            return NULL;
621
622        // Cast object to specified type.
623        T* pTypeCast = dynamic_cast<T*>( mpProxyObject );
624
625        // Destroy the object if not the specified type and requested to do so.
626        if ( deleteIfNotType && pTypeCast == NULL )
627        {
628            mpProxyObject->deleteObject();
629            return NULL;
630        }
631
632        return pTypeCast;
633    }
634    inline const TamlWriteNode* getProxyWriteNode( void ) const { return mpProxyWriteNode; }
635
636    inline bool isEmpty( void ) const { return mNodeText.isValueEmpty() && mFields.size() == 0 && mChildren.size() == 0; }
637
638    inline void setIgnoreEmpty( const bool ignoreEmpty ) { mIgnoreEmpty = ignoreEmpty; }
639    inline bool getIgnoreEmpty( void ) const { return mIgnoreEmpty; }
640
641private:
642    inline TamlCustomField* registerField( TamlCustomField* pCustomField )
643    {
644#if TORQUE_DEBUG
645        // Ensure a field name conflict does not exist.
646        for( Vector<TamlCustomField*>::iterator nodeFieldItr = mFields.begin(); nodeFieldItr != mFields.end(); ++nodeFieldItr )
647        {
648            // Skip if field name is not the same.
649            if ( pCustomField->getFieldName() != (*nodeFieldItr)->getFieldName() )
650                continue;
651
652            // Warn!
653            Con::warnf("Conflicting Taml node field name of '%s' in node '%s'.", pCustomField->getFieldName(), mNodeName );
654
655            // Cache node field.
656            TamlCustomFieldFactory.cacheObject( pCustomField );
657            return NULL;
658        }
659
660        // Ensure the field value is not too long.
661        if ( dStrlen( pCustomField->getFieldValue() ) >= MAX_TAML_NODE_FIELDVALUE_LENGTH )
662        {
663            // Warn.
664            Con::warnf("Taml field name '%s' has a field value that is too long (Max:%d): '%s'.",
665                pCustomField->getFieldName(),
666                MAX_TAML_NODE_FIELDVALUE_LENGTH,
667                pCustomField->getFieldValue() );
668
669            // Cache node field.
670            TamlCustomFieldFactory.cacheObject( pCustomField );
671            return NULL;
672        }
673#endif
674        // Store node field.
675        mFields.push_back( pCustomField );
676
677        return pCustomField;
678    }
679
680    inline TamlCustomField* createField( void ) const { return TamlCustomFieldFactory.createObject(); }
681
682private:
683    StringTableEntry        mNodeName;
684    TamlCustomField         mNodeText;
685    Vector<TamlCustomNode*> mChildren;
686    TamlCustomFieldVector   mFields;
687    bool                    mIgnoreEmpty;
688
689    SimObject*              mpProxyObject;
690    TamlWriteNode*          mpProxyWriteNode;
691};
692
693//-----------------------------------------------------------------------------
694
695class TamlCustomNodes : public IFactoryObjectReset
696{
697public:
698    TamlCustomNodes()
699    {
700    }
701
702    virtual ~TamlCustomNodes()
703    {
704        resetState();
705    }
706
707    virtual void resetState( void )
708    {
709        // Cache the nodes.
710        while ( mNodes.size() > 0 )
711        {
712            TamlCustomNodeFactory.cacheObject( mNodes.back() );
713            mNodes.pop_back();
714        }
715    }
716
717    inline TamlCustomNode* addNode( const char* pNodeName, const bool ignoreEmpty = true )
718    {
719        // Create a custom node.
720        TamlCustomNode* pCustomNode = TamlCustomNodeFactory.createObject();
721
722        // Set node name.
723        pCustomNode->setNodeName( pNodeName );
724
725        // Set ignore-empty flag.
726        pCustomNode->setIgnoreEmpty( ignoreEmpty );
727
728#if TORQUE_DEBUG
729        // Ensure a node name conflict does not exist.
730        for( TamlCustomNodeVector::iterator nodeItr = mNodes.begin(); nodeItr != mNodes.end(); ++nodeItr )
731        {
732            // Skip if node name is not the same.
733            if ( pCustomNode->getNodeName() != (*nodeItr)->getNodeName() )
734                continue;
735
736            // Warn!
737            Con::warnf("Conflicting Taml custom node name of '%s'.", pNodeName );
738
739            // Cache node.
740            TamlCustomNodeFactory.cacheObject( pCustomNode );
741            return NULL;
742        }
743#endif
744        // Store node.
745        mNodes.push_back( pCustomNode );
746
747        return pCustomNode;
748    }
749
750    inline void removeNode( const U32 index )
751    {
752        // Sanity!
753        AssertFatal( index < (U32)mNodes.size(), "tamlCustomNode::removeNode() - Index is out of bounds." );
754
755        // Cache the custom node.
756        TamlCustomNodeFactory.cacheObject( mNodes[index] );
757
758        // Remove it.
759        mNodes.erase( index );
760    }
761
762    inline const TamlCustomNode* findNode( const char* pNodeName ) const
763    {
764        // Sanity!
765        AssertFatal( pNodeName != NULL, "Cannot find Taml node name that is NULL." );
766
767        // Fetch node name.
768        StringTableEntry nodeName = StringTable->insert( pNodeName );
769
770        // Find node.
771        for( Vector<TamlCustomNode*>::const_iterator nodeItr = mNodes.begin(); nodeItr != mNodes.end(); ++nodeItr )
772        {
773            if ( (*nodeItr)->getNodeName() == nodeName )
774                return (*nodeItr);
775        }
776
777        return NULL;
778    }
779
780    inline const TamlCustomNodeVector& getNodes( void ) const { return mNodes; }
781
782private:
783    TamlCustomNodeVector mNodes;
784};
785
786#endif // _TAML_CUSTOM_H_
787