AaronCameron.net
I care not for your petty politics.
Not a Member? - Login or Create an Account
Sunday the 20th of May 2012 @ 03:37pm
Front Page Journal Projects Your Profile About
[]

LibN2L-4 Library Code Reference

Classes
Compounds
Files
Members
Method Index
Full Reference

cDynVar.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002 Nova-2 Library (libN2L, or simply n2l) Game development C++ Library
00003 Copyright (C) 2003  Aaron Cameron
00004 
00005 This library is free software; you can redistribute it and/or
00006 modify it under the terms of the GNU Lesser General Public
00007 License as published by the Free Software Foundation; either
00008 version 2.1 of the License, or (at your option) any later version.
00009 
00010 This library is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 Lesser General Public License for more details.
00014 
00015 You should have received a copy of the GNU Lesser General Public
00016 License along with this library; if not, write to the Free Software
00017 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00018 
00019 A copy of the GNU Lesser General Public License has been provided with
00020 this library in the file 'COPYING'.
00021 
00022 Contact information for the author of this library has been provided
00023 with this library in the file 'AUTHOR'.
00024 ************************************************************************/
00025 #include "cDynVar.h"
00026 #include "n2l/timing.h"
00027 #include <stdlib.h>
00028 
00029 #include <iostream>
00030 
00031 using namespace std;
00032 
00033 namespace n2l
00034 {
00035 
00036     tUint cDynVar::smCount[6] = { 0,0,0,0,0,0 };
00037 
00038     const cDynVar::tDynVarArray cDynVar::Array;
00039 
00044     const cDynVar cDynVar::NoKey( cDynVar::Array );
00045 
00046     const cDynVar cDynVar::Null( cDynVar::VarType_Null );
00047 
00048     /* ********************************************************************** */
00049     cDynVar::cDynVar() :
00050         mType(VarType_Null)
00051     {
00052         memset(&mValue,0,sizeof(tValue));
00053     }
00054 
00055     /* ********************************************************************** */
00056     cDynVar::cDynVar( const tVarType iType ) :
00057         mType(iType)
00058     {
00059         memset(&mValue,0,sizeof(tValue));
00060         if (mType==VarType_String) {
00061             mValue.mString = new char[1];
00062             mValue.mString[0] = '\0';
00063         }
00064         if (mType==VarType_Array) {
00065             mValue.mArray = new tDynVarArray;
00066         }
00067     }
00068 
00069     /* ********************************************************************** */
00070     cDynVar::cDynVar( const cDynVar & iDynVar )
00071     {
00072         mType = VarType_Sint32;
00073         memset(&mValue,0,sizeof(tValue));
00074         assign(iDynVar);
00075     }
00076 
00077 
00078     /* ********************************************************************** */
00079     cDynVar::cDynVar( const char * const iValue ) :
00080         mType(VarType_String)
00081     {
00082         if (!iValue)
00083             throw cBadDataUseException( "cDynVar::cDynVar(const char * const)",
00084                 "Null string" );
00085         mValue.mString = new char[ strlen(iValue)+1 ];
00086         strcpy(mValue.mString,iValue);
00087     }
00088 
00089     /* ********************************************************************** */
00090     cDynVar::cDynVar( const tString & iValue ) :
00091         mType(VarType_String)
00092     {
00093         mValue.mString = new char[ iValue.size()+1 ];
00094         strcpy(mValue.mString,iValue.c_str());
00095     }
00096 
00097     /* ********************************************************************** */
00098     cDynVar::cDynVar( const tSint iValue ) :
00099         mType(VarType_Sint32)
00100     {
00101         mValue.mSint32 = iValue;
00102     }
00103 
00104     /* ********************************************************************** */
00105     cDynVar::cDynVar( const tUint iValue ) :
00106         mType(VarType_Sint32)
00107     {
00108         mValue.mSint32 = tSint(iValue);
00109     }
00110 
00111     /* ********************************************************************** */
00112     cDynVar::cDynVar( const tFloat iValue ) :
00113         mType(VarType_Float)
00114     {
00115         mValue.mFloat = iValue;
00116     }
00117 
00118     /* ********************************************************************** */
00119     cDynVar::cDynVar( const tBool iValue ) :
00120         mType(VarType_Bool)
00121     {
00122         mValue.mBool = iValue;
00123     }
00124 
00125 
00126     /* ********************************************************************** */
00127     cDynVar::cDynVar( const tDynVarArray & iValue ) :
00128         mType(VarType_Array)
00129     {
00130         mValue.mArray = new tDynVarArray( iValue );
00131     }
00132     
00133 
00134     /* ********************************************************************** */
00135     cDynVar::~cDynVar()
00136     {
00137         if (mType==VarType_String && mValue.mString) {
00138             delete []mValue.mString;
00139             mValue.mString = 0;
00140         }
00141         if (mType==VarType_Array && mValue.mArray) {
00142             delete mValue.mArray;
00143             mValue.mArray = 0;
00144         }
00145     }
00146 
00147 
00148     /* ********************************************************************** */
00149     void cDynVar::assign( const cDynVar & iDynVar )
00150     {
00151         // Let's make sure that we're not self assigning
00152         if (&iDynVar == this) return;
00153 
00154         // Before we do anything, if we're a tString we have to delete
00155         // the char* we currently hold
00156         if (mType==VarType_String && mValue.mString) {
00157             delete []mValue.mString;
00158             mValue.mString = 0;
00159         }
00160 
00161         // Also, if we're an array, we have to delete that as well.
00162         if (mType==VarType_Array && mValue.mArray) {
00163             delete mValue.mArray;
00164             mValue.mArray = 0;
00165         }
00166 
00167         // This is safe no matter what, we'll just replace mValue if
00168         // we have to
00169         mType = iDynVar.mType;
00170         mValue = iDynVar.mValue;
00171 
00172         // If we're copying a string
00173         if (mType==VarType_String) {
00174             mValue.mString = new char[ iDynVar.size()+1 ];
00175             strcpy(mValue.mString, iDynVar.mValue.mString);
00176         }
00177         if (mType==VarType_Array) {
00178             mValue.mArray = new tDynVarArray( *(iDynVar.mValue.mArray) );
00179         }
00180     }
00181 
00182 
00183     /* ********************************************************************** */
00184     cDynVar & cDynVar::operator =( const cDynVar & iDynVar )
00185     {
00186         assign(iDynVar);
00187         return *this;
00188     }
00189 
00190 
00191     /* ********************************************************************** */
00192     void cDynVar::eval( const tString & iValStr )
00193     {
00194         // Is the tString empty?
00195         if (iValStr.empty()) {
00196             assign(0);
00197             return;
00198         }
00199         // Note: This will never evaluate to an array or null
00200 
00201         // Try to detect the type of information in the tString
00202         // First thing we'll do is find out if there's alpha characters
00203         // present
00204         const tBool IsNumeric = isNumericStr(iValStr,true); // true: . allowed
00205         if (!IsNumeric) {
00206             assign(iValStr);
00207             return;
00208         }
00209         // Looks numeric, let's make sure
00210         const tString::size_type NegPos = iValStr.rfind('-');
00211         if (NegPos!=0 && NegPos!=tString::npos) {
00212             // Negative sign somewhere not the beginning of the
00213             // value.  It's a tString afterall.
00214             assign(iValStr);
00215             return;
00216         }
00217         // It is numeric, we need to figure out what kind
00218         const tString::size_type DecimalPos = iValStr.find('.');
00219         if (tString::npos!=DecimalPos) {    // Is it a float?
00220             // Looks like it let's make sure
00221             if (DecimalPos!=iValStr.rfind('.')) {
00222                 // Two or more decimals?  It's a tString after all.
00223                 assign( iValStr );
00224                 return;
00225             }
00226             // Still a float, ok, let's trust it now
00227             assign( asFloat(iValStr) );
00228             return;
00229         }
00230         // It has to be an int
00231         assign( asSint32(iValStr) );
00232     }
00233 
00234     /* ********************************************************************** */
00235     cDynVar::operator const tString() const
00236     {
00237         static const tString ArrayStr("Array");
00238         static const tString NullStr("");
00239         switch (mType) {
00240             case VarType_String:
00241                 return mValue.mString;
00242                 
00243             case VarType_Sint32:
00244                 return asString( mValue.mSint32 );
00245 
00246             case VarType_Float:
00247                 return asString( double(mValue.mFloat) );
00248 
00249             case VarType_Bool:
00250                 return asString( mValue.mBool );
00251 
00252             case VarType_Array:
00253                 return ArrayStr;
00254 
00255             case VarType_Null:
00256                 return NullStr;
00257         }
00258 
00259         throw cBadDataUseException( "cDynVar::operator tString",
00260                                     "Internal type is unknown" );
00261     }
00262 
00263     /* ********************************************************************** */
00264     cDynVar::operator const tSint() const
00265     {
00266         switch (mType) {
00267             case VarType_String:
00268                 return asSint32(mValue.mString);
00269                 
00270             case VarType_Sint32:
00271                 return mValue.mSint32;
00272 
00273             case VarType_Float:
00274                 return tSint32(mValue.mFloat);
00275 
00276             case VarType_Bool:
00277                 return tSint32(mValue.mBool);
00278 
00279             case VarType_Array:
00280                 return (mValue.mArray->empty()?0:1);
00281 
00282             case VarType_Null:
00283                 return 0;
00284         }
00285 
00286         throw cBadDataUseException( "cDynVar::operator n2l::Sint32",
00287             "Internal type is unknown" );
00288     }
00289 
00290 
00291     /* ********************************************************************** */
00292     cDynVar::operator const tFloat() const
00293     {
00294         switch (mType) {
00295             case VarType_String:
00296                 return asFloat(mValue.mString);
00297                 
00298             case VarType_Sint32:
00299                 return tFloat(mValue.mSint32);
00300 
00301             case VarType_Float:
00302                 return mValue.mFloat;
00303 
00304             case VarType_Bool:
00305                 return tFloat(mValue.mBool);
00306 
00307             case VarType_Array:
00308                 return tFloat(mValue.mArray->empty()?0:1);
00309 
00310             case VarType_Null:
00311                 return 0.0f;
00312         }
00313 
00314         throw cBadDataUseException( "cDynVar::operator n2l::float",
00315             "Internal type is unknown" );
00316     }
00317 
00318 
00319     /* ********************************************************************** */
00320     cDynVar::operator const tBool() const
00321     {
00322         switch (mType) {
00323             case VarType_String: {
00324                 if (mValue.mString==0) return false;
00325                 const tUint32 SLength = strlen(mValue.mString);
00326                 if (SLength==0) return false;
00327                 if (mValue.mString[0]=='0') return false;
00328                 return true;
00329             }
00330                 
00331             case VarType_Sint32:
00332                 return tBool(mValue.mSint32);
00333 
00334             case VarType_Float:
00335                 return tBool(mValue.mFloat);
00336 
00337             case VarType_Bool:
00338                 return mValue.mBool;
00339 
00340             case VarType_Array:
00341                 return tBool(mValue.mArray->empty()?false:true);
00342 
00343             case VarType_Null:
00344                 return false;
00345         }
00346 
00347         throw cBadDataUseException( "cDynVar::operator n2l::bool",
00348             "Internal type is unknown" );
00349     }
00350 
00351 
00352     /* ********************************************************************** */
00353     const cDynVar::tVarType cDynVar::type() const
00354     {
00355         return mType;
00356     }
00357 
00358     /* ********************************************************************** */
00359     const tString & cDynVar::anyTypeStr( const tVarType iType )
00360     {
00361         static const tString smStringTypeStr("string");
00362         static const tString smSint32TypeStr("int");
00363         static const tString smFloatTypeStr("float");
00364         static const tString smBoolTypeStr("bool");
00365         static const tString smArrayTypeStr("array");
00366         static const tString smNullTypeStr("null");
00367         switch (iType)
00368         {
00369             case VarType_String:    return smStringTypeStr;
00370             case VarType_Sint32:    return smSint32TypeStr;
00371             case VarType_Float:     return smFloatTypeStr;
00372             case VarType_Bool:      return smBoolTypeStr;
00373             case VarType_Array:     return smArrayTypeStr;
00374             case VarType_Null:      return smNullTypeStr;
00375         }
00376         // We have idea what to do with this.
00377         throw cBadDataUseException( "cDynVar::typeStr",
00378             tString("Type is unknown") + asString(iType) );
00379     }
00380 
00381 
00382     /* ********************************************************************** */
00383     const tString & cDynVar::typeStr() const
00384     {
00385         return anyTypeStr(mType);
00386     }
00387 
00388     /* ********************************************************************** */
00389     const cDynVar::tSize cDynVar::size() const
00390     {
00391         switch (mType)
00392         {
00393             case VarType_String:
00394                 if (0==mValue.mString) return 0;
00395                 return strlen(mValue.mString);
00396 
00397             case VarType_Sint32:
00398                 return 4;
00399 
00400             case VarType_Float:
00401                 return sizeof(float);
00402 
00403             case VarType_Bool:
00404                 return sizeof(tBool);
00405 
00406             case VarType_Array:
00407                 return mValue.mArray->size();
00408 
00409             case VarType_Null:
00410                 return 0;
00411         }
00412         // We have idea what to do with this.
00413         throw cBadDataUseException( "cDynVar::size",
00414             "Internal type is unknown" );
00415     }
00416 
00417 
00418     /* ********************************************************************** */
00419     const cDynVar cDynVar::casted( const tVarType iType ) const
00420     {
00421         switch (iType)
00422         {
00423             case VarType_String:
00424                 return tString(*this);
00425             case VarType_Sint32:
00426                 return tSint32(*this);
00427 
00428             case VarType_Float:
00429                 return float(*this);
00430 
00431             case VarType_Bool:
00432                 return tBool(*this);
00433 
00434             case VarType_Array: {
00435                 if (mType==VarType_Array) return *this;
00436                 cDynVar temp( cDynVar::Array );
00437                 temp[0] = *this;
00438                 return temp;
00439             }
00440 
00441             case VarType_Null:
00442                 return Null;
00443 
00444         }
00445         // We have idea what to do with this.
00446         throw cBadDataUseException( "cDynVar::casted",
00447             "Internal type is unknown" );
00448     }
00449 
00450 
00451     /* ********************************************************************** */
00452     cDynVar & cDynVar::cast( const tVarType iType )
00453     {
00454         cDynVar newVar;
00455         switch (iType)
00456         {
00457             case VarType_String:
00458                 newVar = tString(*this);
00459                 *this = newVar;
00460                 return *this;
00461 
00462             case VarType_Sint32:
00463                 newVar = tSint32(*this);
00464                 *this = newVar;
00465                 return *this;
00466 
00467             case VarType_Float:
00468                 newVar = float(*this);
00469                 *this = newVar;
00470                 return *this;
00471 
00472             case VarType_Bool:
00473                 newVar = tBool(*this);
00474                 *this = newVar;
00475                 return *this;
00476 
00477             case VarType_Array:
00478                 newVar = cDynVar::Array;
00479                 newVar[0] = *this;
00480                 *this = newVar;
00481                 return *this;
00482 
00483             case VarType_Null:
00484                 *this = Null;
00485                 return *this;
00486         }
00487         // We have idea what to do with this.
00488         throw cBadDataUseException( "cDynVar::cast",
00489             "Internal type is unknown" );
00490     }
00491 
00492 
00493     /* ********************************************************************** */
00494     void cDynVar::mkNumeric()
00495     {
00496         *this = asNumeric();
00497     }
00498 
00499 
00500     /* ********************************************************************** */
00501     const cDynVar cDynVar::asNumeric() const
00502     {
00503         switch (mType)
00504         {
00505             case VarType_String: {
00506                 tUint32 i = 0;
00507                 while (mValue.mString[i]!='\0' && mValue.mString[i]!='.') ++i;
00508                 if (mValue.mString[i]=='.') return asFloat(mValue.mString);
00509                 return asSint32(mValue.mString);
00510             }
00511 
00512             case VarType_Sint32:
00513                 return *this;
00514 
00515             case VarType_Float:
00516                 return *this;
00517 
00518             case VarType_Bool:
00519                 return tSint32(mValue.mBool);
00520 
00521             case VarType_Array:
00522                 return (mValue.mArray->size()?1:0);
00523 
00524             case VarType_Null:
00525                 return 0;
00526         }
00527         // We have idea what to do with this.
00528         throw cBadDataUseException( "cDynVar::asNumeric",
00529             "Internal type is unknown" );
00530     }
00531 
00532 
00533     /* ********************************************************************** */
00534     const tBool cDynVar::isNumericType() const
00535     {
00536         return (mType==VarType_Sint32 || mType==VarType_Float);
00537     }
00538 
00539 
00540     /* ********************************************************************** */
00541     const tBool cDynVar::isNumericValue() const
00542     {
00543         if (mType==VarType_Null) return false;
00544         if (mType!=VarType_String && mType!=VarType_Array) return true;
00545         if (mType==VarType_String) {
00546             // If the string only contains numeric symbols, one or fewer
00547             // decimals and one or fewer '-' signs in the first charater
00548             // position.
00549             const tUint StrLen( strlen(mValue.mString) );
00550             tUbyte dCount = 0;
00551             for (tUint cPos=0; cPos<StrLen; ++cPos) {
00552                 char c = mValue.mString[cPos];
00553                 if (c=='-' && cPos==0) continue;
00554                 if (c=='.') {
00555                     if (dCount==0) { ++dCount; continue; }
00556                     else return false;
00557                 }
00558                 if (c=='f') {
00559                     if (cPos+1==StrLen) return true;
00560                     else return false;
00561                 }
00562                 if (c<'0' || c>'9') return false;
00563             }
00564             return true;
00565         }
00566         return false;
00567     }
00568 
00569 
00570     /* ********************************************************************** */
00571     cDynVar &cDynVar::insert( const cDynVar & iValue )
00572     {
00573         if (!isArray())
00574             throw cBadDataUseException( "cDynVar::insert",
00575                 "Can\'t insert into non-array types" );
00576         
00577         cDynVar *next = &((*(mValue.mArray))[
00578             getKey(nextIntegralKey(*(mValue.mArray))) ]);
00579         *next = iValue;
00580         return *next;
00581     }
00582 
00583 
00584     /* ********************************************************************** */
00585     cDynVar &cDynVar::insert(const cDynVar & iKey, const cDynVar & iValue )
00586     {
00587         cDynVar *next;
00588         if (!isArray())
00589             throw cBadDataUseException( "cDynVar::insert",
00590                 "Can\'t insert into non-array types" );
00591         if (&iKey==&NoKey) {
00592             next = &((*(mValue.mArray))[
00593                 getKey(nextIntegralKey(*(mValue.mArray)))]);
00594             *next = iValue;
00595         } else {
00596             if (iKey.isArray())
00597                 throw cBadDataUseException( "cDynVar::insert",
00598                     "Arrays may not be keys" );
00599             next = &((*(mValue.mArray))[ getKey(iKey) ]);
00600             *next = iValue;
00601         }
00602         return *next;
00603     }
00604 
00605 
00606     /* ********************************************************************** */
00607     const tBool cDynVar::keyExists( const cDynVar &iKey ) const
00608     {
00609         if (!isArray()) return false;
00610         if (iKey.isNull()) return false;
00611         const tDynVarArray::const_iterator IT(
00612             mValue.mArray->find(getKey(iKey)) );
00613         return (IT!=mValue.mArray->end());
00614     }
00615 
00616     /* ********************************************************************** */
00617     const tBool cDynVar::keyExistsAsArray( const cDynVar &iKey ) const
00618     {
00619         if (!isArray()) return false;
00620         if (iKey.isNull()) return false;
00621         const tDynVarArray::const_iterator IT(
00622             mValue.mArray->find(getKey(iKey)) );
00623         if (IT == mValue.mArray->end()) return false;
00624         if (!IT->second.isArray()) return false;
00625         return true;
00626     }
00627 
00628     /* ********************************************************************** */
00629     const cDynVar &cDynVar::operator []( const cDynVar &iKey ) const
00630     {
00631         static const cDynVar NoValue( false );
00632         if (iKey.isNull()) return NoValue;
00633         switch (mType) {
00634             case VarType_Array: {
00635                 tDynVarArray::const_iterator vIT(
00636                     mValue.mArray->find(getKey(iKey)) );
00637                 if (vIT==mValue.mArray->end()) return NoValue;
00638                 return vIT->second;
00639             }
00640             default:
00641                 return NoValue;
00642         } // switch
00643     }
00644 
00645 
00646     /* ********************************************************************** */
00647     cDynVar &cDynVar::operator []( const cDynVar & iKey )
00648     {
00649         if (mType!=VarType_Array)
00650             throw cBadDataUseException( "cDynVar::operator []",
00651                 "Non-const [] accessor cannot create a "
00652                 "key in a non-array structure" );
00653         if (&iKey==&NoKey || iKey.isNull())
00654             return ((*(mValue.mArray))[
00655                 getKey(nextIntegralKey(*(mValue.mArray))) ] = false);
00656         return (*mValue.mArray)[getKey(iKey)];
00657     }
00658 
00659     /* ********************************************************************** */
00660     const cDynVar &cDynVar::keyValueOr( const cDynVar &iKey,
00661         const cDynVar &iDefault ) const
00662     {
00663         if (mType!=VarType_Array || &iKey==&NoKey || iKey.isNull())
00664             return iDefault;
00665         tDynVarArray::const_iterator vIT( mValue.mArray->find(getKey(iKey)) );
00666         if (vIT==mValue.mArray->end()) return iDefault;
00667         return vIT->second;
00668     }
00669 
00670     /* ********************************************************************** */
00671     const cDynVar::tConstIterator cDynVar::begin() const
00672     {
00673         if (mType!=VarType_Array)
00674             throw cBadDataUseException( "cDynVar::begin (const)",
00675                 "Cannot get the beginning iterator of a "
00676                 "non-array structure" );
00677         return mValue.mArray->begin();
00678     }
00679 
00680 
00681     /* ********************************************************************** */
00682     const cDynVar::tConstIterator cDynVar::end() const
00683     {
00684         if (mType!=VarType_Array)
00685             throw cBadDataUseException( "cDynVar::end (const)",
00686                 "Cannot get the end iterator of a "
00687                 "non-array structure" );
00688         return mValue.mArray->end();
00689     }
00690     
00691     /* ********************************************************************** */
00692     const cDynVar::tConstIterator cDynVar::find( const cDynVar &iKey ) const
00693     {
00694         if (mType!=VarType_Array)
00695             throw cBadDataUseException( "cDynVar::end (const)",
00696                 "Cannot get the end iterator of a non-array structure" );
00697         return mValue.mArray->find( iKey );
00698     }
00699 
00700     /* ********************************************************************** */
00701     const cDynVar cDynVar::operator -( const cDynVar & iRValue ) const
00702     {
00703         cDynVar lSide, rSide;
00704         if (isNumericType()) lSide = *this;
00705         else lSide = asNumeric();
00706         if (iRValue.isNumericType()) rSide = iRValue;
00707         else rSide = iRValue.asNumeric();
00708         // Do the math
00709         if (lSide.mType==VarType_Float || rSide.mType==VarType_Float)
00710             return float(lSide)-float(rSide);
00711         return tSint32(lSide)-tSint32(rSide);
00712     }
00713 
00714 
00715     /* ********************************************************************** */
00716     const cDynVar cDynVar::operator +( const cDynVar & iRValue ) const
00717     {
00718         cDynVar lSide, rSide;
00719         if (isNumericType()) lSide = *this;
00720         else lSide = asNumeric();
00721         if (iRValue.isNumericType()) rSide = iRValue;
00722         else rSide = iRValue.asNumeric();
00723         // Do the math
00724         if (lSide.mType==VarType_Float || rSide.mType==VarType_Float)
00725             return float(lSide)+float(rSide);
00726         return tSint32(lSide)+tSint32(rSide);
00727     }
00728 
00729 
00730     /* ********************************************************************** */
00731     const cDynVar cDynVar::operator *( const cDynVar & iRValue ) const
00732     {
00733         cDynVar lSide, rSide;
00734         if (isNumericType()) lSide = *this;
00735         else lSide = asNumeric();
00736         if (iRValue.isNumericType()) rSide = iRValue;
00737         else rSide = iRValue.asNumeric();
00738         // Do the math
00739         if (lSide.mType==VarType_Float || rSide.mType==VarType_Float)
00740             return float(lSide)*float(rSide);
00741         return tSint32(lSide)*tSint32(rSide);
00742     }
00743 
00744 
00745     /* ********************************************************************** */
00746     const cDynVar cDynVar::operator /( const cDynVar & iRValue ) const
00747     {
00748         cDynVar lSide, rSide;
00749         if (isNumericType()) lSide = *this;
00750         else lSide = asNumeric();
00751         if (iRValue.isNumericType()) rSide = iRValue;
00752         else rSide = iRValue.asNumeric();
00753         // Do the math
00754         if (lSide.mType==VarType_Float || rSide.mType==VarType_Float)
00755             return float(lSide)/float(rSide);
00756         // Do some auto sensing.  We want to send back a float if necessary,
00757         // but prefer Sint32
00758         const div_t r = div(tSint32(lSide),tSint32(rSide));
00759         if (r.rem!=0) return float(lSide)/float(rSide);
00760         return r.quot;
00761     }
00762 
00763 
00764     /* ********************************************************************** */
00765     const cDynVar cDynVar::operator %( const cDynVar & iRValue ) const
00766     {
00767         return tSint32(*this)%tSint32(iRValue);
00768     }
00769 
00770 
00771     /* ********************************************************************** */
00772     const cDynVar cDynVar::operator ==( const cDynVar & iRValue ) const
00773     {
00774         // String vs String is always compared as tStrings
00775         if (mType==VarType_String && iRValue.mType==VarType_String)
00776             return (strcmp(mValue.mString,iRValue.mValue.mString)==0);
00777 
00778         // If not strings and either side is Null, we have some special rules
00779         if (isNull() || iRValue.isNull()) {
00780             return (tBool(*this)==tBool(iRValue));
00781         }
00782         
00783         // If the left or right sides are not integer convertable, make them
00784         // both strings.
00785         if (!isNumericValue() || !iRValue.isNumericValue()) {
00786             return tString(*this)==tString(iRValue);
00787         }
00788 
00789         // We know we're dealing with something numeric, or easily
00790         // cast to numeric, so continue that way.
00791         cDynVar lSide, rSide;
00792         if (isNumericType()) lSide = *this;
00793         else lSide = asNumeric();
00794         if (iRValue.isNumericType()) rSide = iRValue;
00795         else rSide = iRValue.asNumeric();
00796         // Same as normal math, upscale to float if either side is
00797         if (lSide.mType==VarType_Float || rSide.mType==VarType_Float)
00798             return float(lSide)==float(rSide);
00799         // Must be integers, good stuff
00800         return tSint32(lSide)==tSint32(rSide);
00801     }
00802 
00803 
00804     /* ********************************************************************** */
00805     const cDynVar cDynVar::operator !=( const cDynVar & iRValue ) const
00806     {
00807         return !(*this==iRValue);
00808     }
00809 
00810 
00811     /* ********************************************************************** */
00812     const cDynVar cDynVar::operator >( const cDynVar &iRValue ) const
00813     {
00814         // String vs String is always compared as tStrings
00815         if (mType==VarType_String && iRValue.mType==VarType_String)
00816             return (strcmp(mValue.mString,iRValue.mValue.mString)>0);
00817         else if (mType==VarType_Null)
00818             return false;
00819         else if (mType==VarType_String && iRValue.mType==VarType_Null)
00820             return mValue.mString[0]!='\0';
00821 
00822         // We know we're dealing with something numeric, or easily
00823         // cast to numeric, so continue that way.
00824         cDynVar lSide, rSide;
00825         if (isNumericType()) lSide = *this;
00826         else lSide = asNumeric();
00827         if (iRValue.isNumericType()) rSide = iRValue;
00828         else rSide = iRValue.asNumeric();
00829         // Same as normal math, upscale to float if either side is
00830         if (lSide.mType==VarType_Float || rSide.mType==VarType_Float)
00831             return float(lSide)>float(rSide);
00832         // Must be integers, good stuff
00833         return tSint32(lSide)>tSint32(rSide);
00834     }
00835 
00836 
00837     /* ********************************************************************** */
00838     const cDynVar cDynVar::operator <( const cDynVar & iRValue ) const
00839     {
00840         // String vs String is always compared as tStrings
00841         if (mType==VarType_String && iRValue.mType==VarType_String)
00842             return (strcmp(mValue.mString,iRValue.mValue.mString)<0);
00843         else if (mType==VarType_Null && iRValue.mType==VarType_Null)
00844             return false;
00845         else if (mType==VarType_Null && iRValue.mType==VarType_String)
00846             return iRValue.mValue.mString[0]!='\0';
00847         else if (iRValue.mType==VarType_Null)
00848             return false;
00849         
00850         // We know we're dealing with something numeric, or easily
00851         // cast to numeric, so continue that way.
00852         cDynVar lSide, rSide;
00853         if (isNumericType()) lSide = *this;
00854         else lSide = asNumeric();
00855         if (iRValue.isNumericType()) rSide = iRValue;
00856         else rSide = iRValue.asNumeric();
00857         // Same as normal math, upscale to float if either side is
00858         if (lSide.mType==VarType_Float || rSide.mType==VarType_Float)
00859             return float(lSide)<float(rSide);
00860         // Must be integers, good stuff
00861         return tSint32(lSide)<tSint32(rSide);
00862     }
00863 
00864 
00865     /* ********************************************************************** */
00866     const cDynVar cDynVar::operator >=( const cDynVar & iRValue ) const
00867     {
00868         return !(*this<iRValue);
00869     }
00870 
00871 
00872     /* ********************************************************************** */
00873     const cDynVar cDynVar::operator <=( const cDynVar & iRValue ) const
00874     {
00875         return !(*this>iRValue);
00876     }
00877 
00878     /* ********************************************************************** */
00879     const cDynVar cDynVar::operator !() const
00880     {
00881         return !(tBool(*this));
00882     }
00883 
00884 
00885     /* ********************************************************************** */
00886     const cDynVar & cDynVar::operator ++()
00887     {
00888         if (!isNumericType()) mkNumeric();
00889         switch (mType)
00890         {
00891             case VarType_Sint32:
00892                 ++mValue.mSint32;
00893                 return *this;
00894 
00895             case VarType_Float:
00896                 ++mValue.mFloat;
00897                 return *this;
00898 
00899             case VarType_Null:
00900                 *this = tSint(0);
00901                 ++mValue.mSint32;
00902                 return *this;
00903 
00904             // Include these to avoid a strict warning
00905             case VarType_String:
00906             case VarType_Bool:
00907             case VarType_Array:
00908                 break;
00909         }
00910         // We have idea what to do with this.
00911         throw cBadDataUseException( "cDynVar::asNumeric",
00912             "Internal type is unknown" );
00913         
00914     }
00915 
00916     
00917     /* ********************************************************************** */
00918     const cDynVar & cDynVar::operator --()
00919     {
00920         if (!isNumericType()) mkNumeric();
00921         switch (mType)
00922         {
00923             case VarType_Sint32:
00924                 --mValue.mSint32;
00925                 return *this;
00926 
00927             case VarType_Float:
00928                 --mValue.mFloat;
00929                 return *this;
00930 
00931             case VarType_Null:
00932                 *this = tSint(0);
00933                 --mValue.mSint32;
00934                 return *this;
00935 
00936             // Include these to avoid a strict warning
00937             case VarType_String:
00938             case VarType_Bool:
00939             case VarType_Array:
00940                 break;
00941         }
00942         // We have idea what to do with this.
00943         throw cBadDataUseException( "cDynVar::asNumeric",
00944             "Internal type is unknown" );
00945     }
00946 
00947 
00948     /* ********************************************************************** */
00949     const cDynVar cDynVar::operator ++(int)
00950     {
00951         cDynVar temp(*this);
00952         if (!isNumericType()) mkNumeric();
00953         switch (mType)
00954         {
00955             case VarType_Sint32:
00956                 ++mValue.mSint32;
00957                 return temp;
00958 
00959             case VarType_Float:
00960                 ++mValue.mFloat;
00961                 return temp;
00962 
00963             case VarType_Null:
00964                 *this = tSint(0);
00965                 ++mValue.mSint32;
00966                 return temp;
00967 
00968             // Include these to avoid a strict warning
00969             case VarType_String:
00970             case VarType_Bool:
00971             case VarType_Array:
00972                 break;
00973         }
00974         // We have idea what to do with this.
00975         throw cBadDataUseException( "cDynVar::asNumeric",
00976             "Internal type is unknown" );
00977     }
00978 
00979 
00980     /* ********************************************************************** */
00981     const cDynVar cDynVar::operator --(int)
00982     {
00983         cDynVar temp(*this);
00984         if (!isNumericType()) mkNumeric();
00985         switch (mType)
00986         {
00987             case VarType_Sint32:
00988                 --mValue.mSint32;
00989                 return temp;
00990 
00991             case VarType_Float:
00992                 --mValue.mFloat;
00993                 return temp;
00994 
00995             case VarType_Null:
00996                 *this = tSint(0);
00997                 --mValue.mSint32;
00998                 return temp;
00999 
01000             // Include these to avoid a strict warning
01001             case VarType_String:
01002             case VarType_Bool:
01003             case VarType_Array:
01004                 break;
01005         }
01006         // We have idea what to do with this.
01007         throw cBadDataUseException( "cDynVar::asNumeric",
01008             "Internal type is unknown" );
01009     }
01010 
01011 
01012     /* ********************************************************************** */
01013     cDynVar & cDynVar::operator +=( const cDynVar & iRValue )
01014     {
01015         if (mType==VarType_Array) return *this;
01016         mkNumeric();
01017         cDynVar rSide;
01018         if (iRValue.isNumericType()) rSide = iRValue;
01019         else rSide = iRValue.asNumeric();
01020         if (mType==VarType_Float || rSide.mType==VarType_Float) {
01021             *this = float(*this)+float(rSide);
01022             return *this;
01023         }
01024         // Must be integers, good stuff
01025         *this = tSint32(*this)+tSint32(rSide);
01026         return *this;
01027     }
01028 
01029 
01030     /* ********************************************************************** */
01031     cDynVar & cDynVar::operator -=( const cDynVar & iRValue )
01032     {
01033         if (mType==VarType_Array) return *this;
01034         mkNumeric();
01035         cDynVar rSide;
01036         if (iRValue.isNumericType()) rSide = iRValue;
01037         else rSide = iRValue.asNumeric();
01038         if (mType==VarType_Float || rSide.mType==VarType_Float) {
01039             *this = float(*this)-float(rSide);
01040             return *this;
01041         }
01042         // Must be integers, good stuff
01043         *this = tSint32(*this)-tSint32(rSide);
01044         return *this;
01045     }
01046 
01047 
01048     /* ********************************************************************** */
01049     cDynVar & cDynVar::operator *=( const cDynVar & iRValue )
01050     {
01051         if (mType==VarType_Array) return *this;
01052         mkNumeric();
01053         cDynVar rSide;
01054         if (iRValue.isNumericType()) rSide = iRValue;
01055         else rSide = iRValue.asNumeric();
01056         if (mType==VarType_Float || rSide.mType==VarType_Float) {
01057             *this = float(*this)*float(rSide);
01058             return *this;
01059         }
01060         // Must be integers, good stuff
01061         *this = tSint32(*this)*tSint32(rSide);
01062         return *this;
01063     } 
01064 
01065 
01066     /* ********************************************************************** */
01067     cDynVar & cDynVar::operator /=( const cDynVar & iRValue )
01068     {
01069         if (mType==VarType_Array) return *this;
01070         mkNumeric();
01071         *this = *this / iRValue;
01072         return *this;
01073     }
01074 
01075 
01076     /* ********************************************************************** */
01077     const tString cDynVar::dump( const tString & iIndent ) const
01078     {
01079         tString temp(iIndent+typeStr());
01080         if (mType==VarType_Null) return temp;
01081         temp += '(';
01082         if (mType==VarType_String) {
01083             temp += asString(strlen(mValue.mString));
01084             temp += ") \"";
01085             temp += mValue.mString;
01086             temp += '\"';
01087         } else if (mType==VarType_Array) {
01088             temp += asString(mValue.mArray->size());
01089             temp += ") {";
01090             for (tDynVarArray::const_iterator it=mValue.mArray->begin();
01091                 it!=mValue.mArray->end(); ++it) {
01092                 temp += "\n";
01093                 temp += iIndent;
01094                 temp += "  [";
01095                 temp += tString(it->first);
01096                 temp += "]=>\n";
01097                 temp += it->second.dump( iIndent+"  " );
01098             }
01099             temp += "\n";
01100             temp += iIndent;
01101             temp += "}";
01102         } else {
01103             temp += tString(*this);
01104             temp += ')';
01105         }
01106         return temp;
01107     }
01108 
01109 
01110     /* ********************************************************************** */
01111     const tString cDynVar::serialize() const
01112     {
01113         tString temp;
01114         switch (mType)
01115         {
01116             case VarType_String:
01117                 temp = "s:";
01118                 temp += asString(tUint32(strlen(mValue.mString)));
01119                 temp += ":\"";
01120                 temp += mValue.mString;
01121                 temp += "\";";
01122                 return temp;
01123             
01124             case VarType_Sint32:
01125                 temp = "i:";
01126                 temp += asString(mValue.mSint32);
01127                 temp += ";";
01128                 return temp;
01129 
01130             case VarType_Float:
01131                 temp = "d:";
01132                 temp += asString(mValue.mFloat);
01133                 temp += ";";
01134                 return temp;
01135 
01136             case VarType_Bool:
01137                 temp = "b:";
01138                 temp += asString(mValue.mBool);
01139                 temp += ";";
01140                 return temp;
01141 
01142             case VarType_Array: {
01143                 temp = "a:";
01144                 temp += asString(mValue.mArray->size());
01145                 temp += ":{";
01146                 for (tDynVarArray::const_iterator it=mValue.mArray->begin();
01147                     it!=mValue.mArray->end(); ++it) {
01148                     // Key
01149                     cDynVar key;
01150                     key.eval(it->first);
01151                     temp += key.serialize();
01152                     temp += it->second.serialize();
01153             }
01154                 temp += "}";
01155                 return temp;
01156 
01157             case VarType_Null:
01158                 temp = "N;";
01159                 return temp;
01160             } // Case array
01161         } // switch
01162         // We have idea what to do with this.
01163         throw cBadDataUseException( "cDynVar::serialize",
01164             "Internal type is unknown" );
01165     }
01166 
01167 
01168     /* ********************************************************************** */
01169     void cDynVar::unserialize( const tString &iVarStr )
01170     {
01171         static const tChar *White = "\t\n ";
01172         
01173         if (iVarStr.substr(0,16) == "n2l::cDynVar_100") {
01174             unserialize_raw_100( iVarStr,
01175                 iVarStr.findFirstNotOf( White, 16 ) );
01176             return;
01177         }
01178         unserialize( iVarStr, 0 );
01179     }
01180 
01181     /* ********************************************************************** */
01182     void cDynVar::unserialize( const tString &iVarStr,
01183         const tString::size_type &iSPos )
01184     {
01185         if (iSPos>=iVarStr.size()) {
01186             assign(false); // Empty unserialize in PHP is false instead of null
01187             return;
01188         }
01189         tString::size_type ePos;
01190         unserializeValue( iVarStr,iSPos,*this,ePos );
01191     }
01192 
01193     /**************************************************************************/
01194     void cDynVar::unserialize_raw_100( const tString &iVarStr,
01195         const tString::size_type &iSPos )
01196     {
01197         if (iSPos>=iVarStr.size()) {
01198             assign(false); // Empty unserialize in PHP is false instead of null
01199             return;
01200         }
01201         tString::size_type ePos;
01202         unserializeValue_raw_100( iVarStr,iSPos,*this,ePos );
01203     }
01204 
01205     /* ********************************************************************** */
01206     ostream & operator <<( ostream & ioStream, const cDynVar &iVar )
01207     {
01208         return ioStream << tString(iVar);
01209     }
01210 
01211 
01212     /* ********************************************************************** */
01213     const tSint cDynVar::nextIntegralKey( const tDynVarArray &iArray ) const
01214     {
01215         tSint k(-1);
01216         for (tDynVarArray::const_iterator it=iArray.begin();
01217             it!=iArray.end(); ++it)
01218         {
01219             if (asSint32(it->first)>k) k = asSint32(it->first);
01220         }
01221         return ++k;
01222     }
01223 
01224     /* ********************************************************************** */
01225     const tString cDynVar::getKey( const cDynVar & iVar ) const
01226     {
01227         tString key;
01228         if (iVar.isFloat() || iVar.isBool()) {
01229             key = asString(tSint(iVar));
01230         } else {
01231             key = tString(iVar);
01232         }
01233         return key;
01234     }
01235 
01236 
01237     /* ********************************************************************** */
01238     void cDynVar::unserializeValue( const tString & iVarStr,
01239         const tString::size_type iSPos, cDynVar & oValue,
01240         tString::size_type & oEPos ) const
01241     {
01242         if (&iSPos == &oEPos)
01243             throw cException( "cDynVar::unserializeValue",
01244                 "iSPos and oEPos are the same variable.  Aaron, don\'t make "
01245                 "iSPos a const reference no matter how tempting it is." );
01246         tUint timer(n2lGetTicks());
01247         switch (iVarStr[iSPos])
01248         {
01249             case 's': {
01250                 // Unfortunately, we can't trust the size sent
01251                 // instead we'll just limit by that.
01252                 const tString::size_type SizeColSPos =
01253                     iVarStr.find(':',iSPos+1);
01254 
01255                 const tString::size_type SizeColEPos =
01256                     iVarStr.find(':',SizeColSPos+1);
01257 
01258                 const tString::size_type StrSQuotPos =
01259                     iVarStr.find('\"',SizeColEPos+1);
01260                 
01261                 // If any of the above are npos, the deal is up
01262                 if (SizeColSPos==tString::npos ||
01263                     SizeColEPos==tString::npos ||
01264                     StrSQuotPos==tString::npos)
01265                     throw cParsingException("cDynVar::unserialize",
01266                         "Control char missing from unserialize (decoding str)",
01267                         iVarStr, "char(npos)" );
01268                 // Decode the size
01269                 const tString::size_type DefinedStrLen = asUint32(
01270                     iVarStr.substr(SizeColSPos+1,SizeColEPos-SizeColSPos-1));
01271 
01272                 if (DefinedStrLen+StrSQuotPos+2>iVarStr.size())
01273                     throw cParsingException("cDynVar::unserialize",
01274                         "Defined size is larger then data", iVarStr,"" );
01275                 // Find the equote
01276                 const tString::size_type StrSemiPos =
01277                     iVarStr.rfind(';',DefinedStrLen+StrSQuotPos+2);
01278 
01279                 const tString::size_type StrEQuotPos =
01280                     iVarStr.rfind('\"',StrSemiPos-1);
01281 
01282                 if (DefinedStrLen!=(StrEQuotPos-StrSQuotPos-1))
01283                     throw cParsingException("cDynVar::unserialize",
01284                         "Defined size != Provided Str size (decoding str)",
01285                         iVarStr,"" );
01286                 // Other critical relationships
01287                 if (StrSQuotPos==StrEQuotPos)
01288                     throw cParsingException("cDynVar::unserialize",
01289                         "Start and end quote the same (decoding str)",
01290                         iVarStr, asString(tUint32(StrEQuotPos)) );
01291                 if (StrSemiPos==tString::npos || StrEQuotPos==tString::npos)
01292                     throw cParsingException("cDynVar::unserialize",
01293                         "Control char missing from unserialize (decoding str)",
01294                         iVarStr, "char(npos)" );
01295                 
01296                 oEPos = StrSemiPos;
01297                 oValue.assign(
01298                     iVarStr.substr(StrSQuotPos+1,StrEQuotPos-StrSQuotPos-1) );
01299                 smCount[0] += n2lGetTicks()-timer;
01300                 return;
01301             }
01302             case 'i': {
01303                 const tString::size_type ColPos = iVarStr.find(':',iSPos);
01304                 const tString::size_type StrSemiPos = iVarStr.find(';',iSPos);
01305                 if (ColPos!=iSPos+1)
01306                     throw cParsingException("cDynVar::unserialize",
01307                         "Missing or misplaced \':\" char (decoding int)",
01308                         iVarStr, asString(tUint32(ColPos)) );
01309                 if (StrSemiPos==tString::npos)
01310                     throw cParsingException("cDynVar::unserialize",
01311                         "Missing or misplaced \';\" char (decoding int)",
01312                         iVarStr, asString(tUint32(StrSemiPos)) );
01313                 oEPos = StrSemiPos;
01314                 oValue.assign( asSint32(
01315                     iVarStr.substr(ColPos+1,StrSemiPos-ColPos-1)) );
01316                 smCount[1] += n2lGetTicks()-timer;
01317                 return;
01318             }
01319             case 'd': {
01320                 const tString::size_type ColPos = iVarStr.find(':',iSPos);
01321                 const tString::size_type StrSemiPos = iVarStr.find(';',iSPos);
01322                 if (ColPos!=iSPos+1)
01323                     throw cParsingException("cDynVar::unserialize",
01324                         "Missing or misplaced \':\" char (decoding float)",
01325                         iVarStr, asString(tUint32(ColPos)) );
01326                 if (StrSemiPos==tString::npos)
01327                     throw cParsingException("cDynVar::unserialize",
01328                         "Missing or misplaced \';\" char (decoding float)",
01329                         iVarStr, asString(tUint32(StrSemiPos)) );
01330                 oEPos = StrSemiPos;
01331                 oValue.assign(
01332                     asFloat(iVarStr.substr(ColPos+1,StrSemiPos-ColPos-1)) );
01333                 smCount[2] += n2lGetTicks()-timer;
01334                 return;
01335             }
01336             case 'b': {
01337                 const tString::size_type ColPos = iVarStr.find(':',iSPos);
01338                 const tString::size_type StrSemiPos = iVarStr.find(';',iSPos);
01339                 if (ColPos!=iSPos+1)
01340                     throw cParsingException("cDynVar::unserialize",
01341                         "Missing or misplaced \':\" char (decoding bool)",
01342                         iVarStr, asString(tUint32(ColPos)) );
01343                 if (StrSemiPos==tString::npos)
01344                     throw cParsingException("cDynVar::unserialize",
01345                         "Missing or misplaced \';\" char (decoding bool)",
01346                         iVarStr, asString(tUint32(StrSemiPos)) );
01347                 if (StrSemiPos!=(ColPos+2))
01348                     throw cParsingException("cDynVar::unserialize",
01349                         "Bool value not exactly one character "
01350                         "(decoding bool)",
01351                         iVarStr, asString(tUint32(ColPos+1)) );
01352                 oEPos = StrSemiPos;
01353                 if (iVarStr[ColPos+1] == '0')
01354                     oValue.assign(false);
01355                 else if (iVarStr[ColPos+1] == '1')
01356                     oValue.assign(true);
01357                 else throw cParsingException("cDynVar::unserialize",
01358                     "Bool value not either 1 or 0 (decoding bool)",
01359                     iVarStr, asString(tUint32(ColPos+1)) );
01360                 smCount[3] += n2lGetTicks()-timer;
01361                 return;
01362             }
01363             case 'a': {
01364                 oValue.assign( cDynVar::Array );
01365                 const tString::size_type SizeColSPos =
01366                     iVarStr.find(':',iSPos+1);
01367 
01368                 const tString::size_type SizeColEPos =
01369                     iVarStr.find(':',SizeColSPos+1);
01370 
01371                 const tString::size_type StrSBrakPos =
01372                     iVarStr.find('{',SizeColEPos+1);
01373 
01374                 // If any of the above are npos, the deal is up
01375                 if (SizeColSPos==tString::npos ||
01376                     SizeColEPos==tString::npos ||
01377                     StrSBrakPos==tString::npos)
01378                     throw cParsingException("cDynVar::unserialize",
01379                         "Control char missing from unserialize "
01380                         "(decoding str)",
01381                         iVarStr, "char(npos)" );
01382                 // Decode the size.  We can't trust it, but it might be
01383                 // useful.
01384                 tString::size_type pos( StrSBrakPos+1 );
01385                 cDynVar key,value;
01386                 while (iVarStr[pos]!='}' && pos<iVarStr.size()) {
01387                     unserializeValue( iVarStr, pos, key, pos );
01388                     ++pos;
01389                     if (pos>=iVarStr.size()) 
01390                         throw cParsingException("cDynVar::unserialize",
01391                             "Key with no value", iVarStr, "char(npos)" );
01392                     unserializeValue( iVarStr, pos, value, pos );
01393                     // Hack to not copy the value.  This is dangerous.
01394                     cDynVar &nValue = oValue.insert(key,cDynVar(0));
01395                     nValue.mType = value.mType;
01396                     nValue.mValue = value.mValue;
01397                     // Make sure that dallocation of 'value' does not
01398                     // invalidate the copy we made into nValue.
01399                     value.mType = VarType_Bool;
01400                     value.mValue.mBool = false;
01401                     // I should be shot for this, by the way.
01402                     ++pos;
01403                 }
01404                 if (iVarStr[pos]!='}')
01405                     throw cParsingException("cDynVar::unserialize",
01406                         "Missing terminating \'}\'", iVarStr,
01407                         "char(npos)" );
01408                 oEPos = pos;
01409                 smCount[4] += n2lGetTicks()-timer;
01410                 return;
01411             }
01412             case 'N': {
01413                 const tString::size_type StrSemiPos =
01414                     iVarStr.find(';',iSPos);
01415                 if (StrSemiPos!=iSPos+1)
01416                     throw cParsingException("cDynVar::unserialize",
01417                         "Missing or misplaced \';\" char (decoding NULL)",
01418                         iVarStr, asString(tUint32(iSPos)) );
01419                 oEPos = StrSemiPos;
01420                 oValue.assign( Null );
01421                 smCount[5] += n2lGetTicks()-timer;
01422                 return;
01423             }
01424             default:
01425                 char type[2] = { iVarStr[iSPos], '\0' };
01426                 throw cParsingException( "cDynVar::unserialize",
01427                     tString("Unknown or unsupported type: ") + type,
01428                     iVarStr, "char(1)" );
01429         }
01430     } // void cDynVar::unserializeValue
01431 
01432     /**************************************************************************/
01433     void cDynVar::unserializeValue_raw_100( const tString &iVarStr,
01434         const tString::size_type iSPos, cDynVar &oValue,
01435         tString::size_type &oEPos ) const
01436     {
01437         static const tChar *White = "\t\n ,";
01438 
01439         if (&iSPos == &oEPos)
01440             throw cException( "cDynVar::unserializeValue_raw_100",
01441                 "iSPos and oEPos are the same variable.  Aaron, don\'t make "
01442                 "iSPos a const reference no matter how tempting it is." );
01443 
01444         if (iSPos>=iVarStr.size())
01445             throw cParsingException( "cDynVar::unserializeValue_raw_100",
01446                 "No such position to take a type from", iVarStr,
01447                 asString(iSPos) );
01448 
01449         // Catch special case unary
01450         switch (iVarStr[iSPos]) {
01451             case 'n':
01452                 oValue.unset();
01453                 oEPos = iSPos+1;
01454                 return;
01455 
01456             case '#':
01457                 throw tString("cDynVar::unserializeValue_raw_100: Comment");
01458                 return;
01459 
01460             default:
01461                 break;
01462         }
01463 
01464         // Support shorthand for number types.
01465         if ((iVarStr[iSPos]>=48 && iVarStr[iSPos]<=57) ||
01466             (iVarStr[iSPos]=='-') || (iVarStr[iSPos]=='.'))
01467         {
01468             // It's a straight up number and we'll evaluate it as such.
01469             oEPos = iVarStr.findFirstNotOf("0123456789.", iSPos+1);
01470             if (oEPos == tString::npos) oEPos = iVarStr.size();
01471             oValue.eval( iVarStr.substr(iSPos, oEPos-iSPos) );
01472             return;
01473         }
01474 
01475         const tString::size_type OPos = iVarStr.find( '(', iSPos+1 );
01476         if (OPos==tString::npos)
01477             throw cParsingException( "cDynVar::unserializeValue_raw_100",
01478                 "Missing value block character: \'(\'", iVarStr,
01479                     asString(iSPos+1) );
01480 
01481         switch (iVarStr[iSPos]) {
01482             case 's': {
01483                 const tString::size_type CPos =
01484                     findUnescaped( iVarStr, ')', OPos+1, '\\', '"' );
01485                 if (CPos == tString::npos)
01486                     throw cParsingException(
01487                         "cDynVar::unserializeValue_raw_100",
01488                         "Missing value block character: \')\' "
01489                         "(decoding string)", iVarStr, asString(iSPos+1) );
01490 
01491                 oValue.assign( unescapedString(
01492                     iVarStr.substr( OPos+1, CPos-OPos-1 ), '\\', '"' ) );
01493                 oEPos = CPos+1;
01494                 break;
01495             }
01496 
01497             case 'b': {
01498                 const tString::size_type CPos = iVarStr.find(')', OPos+1);
01499                 if (CPos == tString::npos)
01500                     throw cParsingException(
01501                         "cDynVar::unserializeValue_raw_100",
01502                         "Missing value block character: \')\' "
01503                         "(decoding bool)", iVarStr, asString(iSPos+1) );
01504                 if (CPos == OPos+1)
01505                     oValue.assign(false);
01506 
01507                 else switch (iVarStr[OPos+1]) {
01508                     case '1':
01509                     case 't':
01510                     case 'T':
01511                         oValue.assign(true);
01512                         break;
01513                     default:
01514                         oValue.assign(false);
01515                         break;
01516                 }
01517 
01518                 oEPos = CPos+1;
01519                 break;
01520             }
01521 
01522             case 'i': {
01523                 const tString::size_type CPos = iVarStr.find(')', OPos+1);
01524                 if (CPos == tString::npos)
01525                     throw cParsingException(
01526                         "cDynVar::unserializeValue_raw_100",
01527                         "Missing value block character: \')\' "
01528                         "(decoding integer)", iVarStr, asString(iSPos+1) );
01529                 if (CPos == OPos+1)
01530                     oValue.assign(0);
01531 
01532                 else
01533                     oValue.assign(
01534                         asSint(iVarStr.substr( OPos+1, CPos-OPos-1 )) );
01535 
01536                 oEPos = CPos+1;
01537                 break;
01538                 
01539             }
01540 
01541             case 'f': {
01542                 const tString::size_type CPos = iVarStr.find(')', OPos+1);
01543                 if (CPos == tString::npos)
01544                     throw cParsingException(
01545                         "cDynVar::unserializeValue_raw_100",
01546                         "Missing value block character: \')\' "
01547                         "(decoding integer)", iVarStr, asString(iSPos+1) );
01548                 if (CPos == OPos+1)
01549                     oValue.assign(0);
01550 
01551                 else
01552                     oValue.assign(
01553                         asFloat(iVarStr.substr( OPos+1, CPos-OPos-1 )) );
01554 
01555                 oEPos = CPos+1;
01556                 break;
01557             }
01558 
01559             case 'a': {
01560                 oValue.assign(Array);
01561                 tString::size_type pos =
01562                     iVarStr.findFirstNotOf( White, OPos+1 );
01563                 while (pos!=tString::npos && iVarStr[pos]!=')') {
01564                     tBool incInsert = false;
01565                     pos = iVarStr.findFirstNotOf( White, pos );
01566                     cDynVar k;
01567                     if (pos == tString::npos)
01568                         throw cParsingException(
01569                             "cDynVar::unserializeValue_raw_100",
01570                             "Premature array termination.  No key. "
01571                             "(decoding array)", iVarStr, "end of string" );
01572                     if (iVarStr[pos]=='=') 
01573                         incInsert = true;
01574                     else {
01575                         unserializeValue_raw_100( iVarStr, pos, k, pos );
01576                         pos = iVarStr.find( '=', pos );
01577                         if (pos == tString::npos)
01578                             throw cParsingException(
01579                                 "cDynVar::unserializeValue_raw_100",
01580                                 "Premature array termination.  Key but no "
01581                                 "\'=\'. (decoding array)", iVarStr,
01582                                 "end of string" );
01583                     }
01584                     ++pos;
01585                     pos = iVarStr.findFirstNotOf( White, pos );
01586                     if (pos == tString::npos)
01587                         throw cParsingException(
01588                             "cDynVar::unserializeValue_raw_100",
01589                             "Premature array termination.  Key but no value. "
01590                             "(decoding array)", iVarStr, "end of string" );
01591 
01592                     cDynVar v;
01593                     unserializeValue_raw_100( iVarStr, pos, v, pos );
01594 
01595                     // Hack to not copy the value.  This is dangerous.
01596                     cDynVar &nValue =
01597                         incInsert?oValue.insert(NoKey,cDynVar(0)):
01598                         oValue.insert(k,cDynVar(0));
01599                     nValue.mType = v.mType;
01600                     nValue.mValue = v.mValue;
01601                     // Make sure that dallocation of 'v' does not
01602                     // invalidate the copy we made into nValue.
01603                     v.mType = VarType_Bool;
01604                     v.mValue.mBool = false;
01605                     // I should be shot for this, by the way.
01606 
01607                     pos = iVarStr.findFirstNotOf( White, pos );
01608                 };
01609                 if (pos == tString::npos)
01610                     throw cParsingException(
01611                         "cDynVar::unserializeValue_raw_100",
01612                         "Premature array termination.  Missing \')\'. "
01613                         "(decoding array)", iVarStr, "end of string" );
01614                 oEPos = pos+1;
01615                 break;
01616             }
01617 
01618             default:
01619                 throw cParsingException( "cDynVar::unserializeValue_raw_100",
01620                     "I have no idea what this type is \"" +
01621                     iVarStr.substr(iSPos,1) +
01622                     "\"", iVarStr, asString(iSPos) );
01623         };
01624  
01625     }
01626 
01627     /**************************************************************************/
01628     void cDynVar::unserializeStats( tUint &oDString, tUint &oDInt,
01629         tUint &oDFloat, tUint &oDBool, tUint &oDArray, tUint &oDNull )
01630     {
01631         oDString = smCount[0];
01632         oDInt = smCount[1];
01633         oDFloat = smCount[2];
01634         oDBool = smCount[3];
01635         oDArray = smCount[4];
01636         oDNull = smCount[5];
01637     }
01638 
01639     /**************************************************************************/
01640     void cDynVar::deepMerge( const cDynVar &iDef, const tBool iIntegersCollide )
01641     {
01642         if (&iDef==this) {
01643             cDynVar tmp = iDef;
01644             deepMerge(tmp);
01645             return;
01646         }
01647 
01648         if (mType!=VarType_Array) {
01649             cDynVar tmp = *this;
01650             *this = cDynVar::Array;
01651             insert( tmp );
01652         }
01653         if (!iDef.isArray()) {
01654             insert( iDef );
01655             return;
01656         }
01657         cDynVar::tConstIterator Last = iDef.end();
01658         cDynVar key;
01659         for (cDynVar::tConstIterator i = iDef.begin(); i!=Last; ++i) {
01660             if (!iIntegersCollide) {
01661                 key.eval(i->first);
01662                 if (key.isInt()) {
01663                     insert( i->second );
01664                     continue;
01665                 }
01666             }
01667             cDynVar::tConstIterator a = find(i->first);
01668             if (a!=end()) {
01669                 if (i->second.isArray() && a->second.isArray())
01670                     (*this)[i->first].deepMerge( i->second,iIntegersCollide );
01671                 else (*this)[i->first] = i->second;
01672             } else
01673                 insert( i->first, i->second );
01674         }
01675     }
01676     
01677 
01678 } // namespace
©2012 Aaron Cameron