![[]](/images/special/trans.gif)
LibN2L-4 Library Code ReferenceClassesCompounds Files Members Method Index Full Reference cDynVar.cppGo 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 |