// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . //----------------------------------------------------------------------------- // inlines CPersistentDataRecord //----------------------------------------------------------------------------- inline void CPersistentDataRecord::addString(const std::string& name,uint16 &result) { // check whether the value of 'result' is already correct if (result<_StringTable.size()) if (_StringTable[result]==name) return; // no luck so do the full work... result= addString(name); } inline void CPersistentDataRecord::addString(const char* name,uint16 &result) { // check whether the value of 'result' is already correct if (result<_StringTable.size()) if (strcmp(_StringTable[result].c_str(),name)==0) return; // no luck so do the full work... result= addString(name); } inline void CPersistentDataRecord::push(TToken token,const CArg& arg) { arg.push(token,_TokenTable,_ArgTable); } inline void CPersistentDataRecord::push(TToken token,bool val) { // make sure the token is valid #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); #endif // store the token and value to the relavent data buffers _TokenTable.push_back((token<<3)+CArg::SINT_TOKEN); _ArgTable.push_back((sint32)val); } inline void CPersistentDataRecord::push(TToken token,sint8 val) { // make sure the token is valid #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); #endif // store the token and value to the relavent data buffers _TokenTable.push_back((token<<3)+CArg::SINT_TOKEN); _ArgTable.push_back((sint32)val); } inline void CPersistentDataRecord::push(TToken token,sint16 val) { // make sure the token is valid #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); #endif // store the token and value to the relavent data buffers _TokenTable.push_back((token<<3)+CArg::SINT_TOKEN); _ArgTable.push_back((sint32)val); } inline void CPersistentDataRecord::push(TToken token,sint32 val) { // make sure the token is valid #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); #endif // store the token and value to the relavent data buffers _TokenTable.push_back((token<<3)+CArg::SINT_TOKEN); _ArgTable.push_back(val); } inline void CPersistentDataRecord::push(TToken token,sint64 val) { // create a union for splitting the i64 value into 2 32bit parts and map the union onto the input value struct C64BitParts { uint32 i32_1; uint32 i32_2; } &valueInBits= *(C64BitParts*)&val; // make sure the token is valid #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); #endif // store the token and value to the relavent data buffers _TokenTable.push_back((token<<3)+CArg::EXTEND_TOKEN); _ArgTable.push_back(valueInBits.i32_1); _TokenTable.push_back((token<<3)+CArg::SINT_TOKEN); _ArgTable.push_back(valueInBits.i32_2); } inline void CPersistentDataRecord::push(TToken token,uint8 val) { // make sure the token is valid #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); #endif // store the token and value to the relavent data buffers _TokenTable.push_back((token<<3)+CArg::UINT_TOKEN); _ArgTable.push_back(val); } inline void CPersistentDataRecord::push(TToken token,uint16 val) { // make sure the token is valid #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); #endif // store the token and value to the relavent data buffers _TokenTable.push_back((token<<3)+CArg::UINT_TOKEN); _ArgTable.push_back(val); } inline void CPersistentDataRecord::push(TToken token,uint32 val) { // make sure the token is valid #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); #endif // store the token and value to the relavent data buffers _TokenTable.push_back((token<<3)+CArg::UINT_TOKEN); _ArgTable.push_back(val); } inline void CPersistentDataRecord::push(TToken token,uint64 val) { // create a union for splitting the i64 value into 2 32bit parts and map the union onto the input value struct C64BitParts { uint32 i32_1; uint32 i32_2; } &valueInBits= *(C64BitParts*)&val; // make sure the token is valid #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); #endif // store the token and value to the relavent data buffers _TokenTable.push_back((token<<3)+CArg::EXTEND_TOKEN); _ArgTable.push_back(valueInBits.i32_1); _TokenTable.push_back((token<<3)+CArg::UINT_TOKEN); _ArgTable.push_back(valueInBits.i32_2); } inline void CPersistentDataRecord::push(TToken token,float val) { // make sure the token is valid #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); #endif // store the token and value to the relavent data buffers _TokenTable.push_back((token<<3)+CArg::FLOAT_TOKEN); _ArgTable.push_back(*(sint32*)&val); } inline void CPersistentDataRecord::push(TToken token,double val) { // create a union for splitting the i64 value into 2 32bit parts and map the union onto the input value struct C64BitParts { uint32 i32_1; uint32 i32_2; } &valueInBits= *(C64BitParts*)&val; // make sure the token is valid #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); #endif // store the token and value to the relavent data buffers _TokenTable.push_back((token<<3)+CArg::EXTEND_TOKEN); _ArgTable.push_back(valueInBits.i32_1); _TokenTable.push_back((token<<3)+CArg::FLOAT_TOKEN); _ArgTable.push_back(valueInBits.i32_2); } inline void CPersistentDataRecord::push(TToken token,const std::string& val) { // make sure the token is valid #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); #endif // store the token and value to the relavent data buffers _TokenTable.push_back((token<<3)+CArg::STRING_TOKEN); _ArgTable.push_back(addString(val)); } inline void CPersistentDataRecord::push(TToken token,const ucstring& val) { // treat ucstrings as strings push(token,val.toUtf8()); } inline void CPersistentDataRecord::push(TToken token,NLMISC::CSheetId val) { // make sure the token is valid #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); #endif // store the token and value to the relavent data buffers _TokenTable.push_back((token<<3)+CArg::EXTEND_TOKEN); _ArgTable.push_back(CArg::ET_SHEET_ID); _TokenTable.push_back((token<<3)+CArg::STRING_TOKEN); _ArgTable.push_back(val.asInt()); } inline void CPersistentDataRecord::push(TToken token,const NLMISC::CEntityId& val) { // this one is a bit complictaed to unrole by hand - better leave it to standard CArg::push() CArg::EntityId(val).push(token,_TokenTable,_ArgTable); } inline void CPersistentDataRecord::push(TToken token) { // make sure the token is valid #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); #endif // store the token to the relavent data buffer _TokenTable.push_back((token<<3)+CArg::FLAG_TOKEN); } inline void CPersistentDataRecord::pushStructBegin(TToken token) { // make sure the token is valid #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); #endif _TokenTable.push_back(token<<3|CArg::STRUCT_BEGIN); _WritingStructStack.push_back(token); } inline void CPersistentDataRecord::pushStructEnd(TToken token) { #ifdef NL_DEBUG BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); BOMB_IF(_WritingStructStack.empty(),"Trying to pop past end of stack",return); BOMB_IF(_WritingStructStack.back()!=token,"Attempting to end a structure with the wrong delimiting token",return); #endif _WritingStructStack.pop_back(); _TokenTable.push_back(token<<3|CArg::STRUCT_END); } //------------------------------------------------------------------------- // set of accessors for retrieving data from a CPersistentDataRecord //------------------------------------------------------------------------- inline bool CPersistentDataRecord::isEndOfData() const { DROP_IF( (_TokenOffset==_TokenTable.size()) && !(_ArgOffset==_ArgTable.size()),"Argument table and token table sizes don't match", return true); DROP_IF( _TokenOffset>_TokenTable.size(),"Attempt to access beyond end of data...", return true); return _TokenOffset==_TokenTable.size(); } inline bool CPersistentDataRecord::isEndOfStruct() const { if (isEndOfData()) return true; if (_ReadingStructStack.empty()) return false; if (peekNextTokenType()!=CArg::STRUCT_END) return false; DROP_IF(_ReadingStructStack.back()!=peekNextToken(),"Opening and closing structure tokens don't match",return false) return true; } inline bool CPersistentDataRecord::isStartOfStruct() const { // DROP_IF(isEndOfData(),"Attempt to read past end of input data",return 0); return (peekNextTokenType()==CArg::STRUCT_BEGIN); } inline bool CPersistentDataRecord::isTokenWithNoData() const { // DROP_IF(isEndOfData(),"Attempt to read past end of input data",return 0); return (peekNextTokenType()==CArg::FLAG); } inline CPersistentDataRecord::TToken CPersistentDataRecord::peekNextToken() const { DROP_IF(isEndOfData(),"Attempt to read past end of input data",return 0); // the 3 low bits contain arg type information - uninteresting here return _TokenTable[_TokenOffset]>>3; } inline const NLMISC::CSString& CPersistentDataRecord::peekNextTokenName() const { TToken t= peekNextToken(); return _StringTable[t]; } inline CPersistentDataRecord::CArg::TType CPersistentDataRecord::peekNextTokenType() const { DROP_IF(isEndOfData(),"Attempt to read past end of input data",return CArg::TType(0)); uint32 tokenType= _TokenTable[_TokenOffset]&7; if (tokenType==CArg::EXTEND_TOKEN) { DROP_IF(_TokenOffset+1>=_TokenTable.size(),"Attempt to read past end of input data",return CArg::TType(0)); return CArg::token2Type(_TokenTable[_TokenOffset+1]&7,true); } return CArg::token2Type(_TokenTable[_TokenOffset]&7,false); } inline const CPersistentDataRecord::CArg& CPersistentDataRecord::peekNextArg() const { CPersistentDataRecord::peekNextArg(TempArg); return TempArg; } inline void CPersistentDataRecord::peekNextArg(CPersistentDataRecord::CArg& result) const { result.setType(peekNextTokenType()); if (result.isExtended()) { BOMB_IF(_ArgOffset+1>=_ArgTable.size(),"Attempt to overrun end of input data",return); DROP_IF((_TokenTable[_TokenOffset+0]&~7)!=(_TokenTable[_TokenOffset+1]&~7),"2 dwords of 64 bit have non-matching identifiers",return); result._Value.i32_1 = _ArgTable[_ArgOffset+0]; result._Value.i32_2 = _ArgTable[_ArgOffset+1]; nlassert(result._Value.ExType == result._Value.i32_1); nlassert(result._Value.i32_2 == result._Value.ex32_1); nlassert(result._Value.ExData32 == result._Value.ex32_1); if (result._Type == CArg::EXTEND_TYPE && result._Value.ExType >= CArg::ET_64_BIT_EXTENDED_TYPES) { // this is a 96 bit extended type, read one more value BOMB_IF(_ArgOffset+2>=_ArgTable.size(),"Attempt to overrun end of input data",return); BOMB_IF((_TokenTable[_TokenOffset+0]&~7)!=(_TokenTable[_TokenOffset+2]&~7),"3 dwords of 96 bit have non-matching identifiers",return); result._Value.ex32_2 = _ArgTable[_ArgOffset+2]; nlassert((uint64(result._Value.ex32_2)<<32|result._Value.ex32_1) == result._Value.ExData64); } } else if (!result.isFlag()) { result._Value.i32_1 = _ArgTable[_ArgOffset]; } if (result._Type==CArg::STRING) { result._String=lookupString(result._Value.i32_1); } return; } //inline CPersistentDataRecord::CArg CPersistentDataRecord::peekNextArg() const //{ // CArg arg; // arg.setType(peekNextTokenType()); // if (arg.isExtended()) // { // BOMB_IF(_ArgOffset+1>=_ArgTable.size(),"Attempt to overrun end of input data",return arg); // DROP_IF((_TokenTable[_TokenOffset+0]&~7)!=(_TokenTable[_TokenOffset+1]&~7),"2 dwords of 64 bit have non-matching identifiers",return arg); // arg._Value.i32_1 = _ArgTable[_ArgOffset+0]; // arg._Value.i32_2 = _ArgTable[_ArgOffset+1]; // nlassert(arg._Value.ExType == arg._Value.i32_1); // nlassert(arg._Value.i32_2 == arg._Value.ex32_1); // nlassert(arg._Value.ExData32 == arg._Value.ex32_1); // // if (arg._Type == CArg::EXTEND_TYPE && arg._Value.ExType >= CArg::ET_64_BIT_EXTENDED_TYPES) // { // // this is a 96 bit extended type, read one more value // BOMB_IF(_ArgOffset+2>=_ArgTable.size(),"Attempt to overrun end of input data",return arg); // BOMB_IF((_TokenTable[_TokenOffset+0]&~7)!=(_TokenTable[_TokenOffset+2]&~7),"3 dwords of 96 bit have non-matching identifiers",return arg); // arg._Value.ex32_2 = _ArgTable[_ArgOffset+2]; // // nlassert((uint64(arg._Value.ex32_2)<<32|arg._Value.ex32_1) == arg._Value.ExData64); // } // } // else if (!arg.isFlag()) // { // arg._Value.i32_1 = _ArgTable[_ArgOffset]; // } // if (arg._Type==CArg::STRING) // { // arg._String=lookupString(arg._Value.i32_1); // } // return arg; //} inline const CPersistentDataRecord::CArg& CPersistentDataRecord::popNextArg(TToken token) { CPersistentDataRecord::popNextArg(token,TempArg); return TempArg; } inline void CPersistentDataRecord::popNextArg(TToken token,CPersistentDataRecord::CArg& result) { #ifdef NL_DEBUG BOMB_IF(peekNextToken()!=token,"Error on read code - token requested doesn't match token found",return); #endif peekNextArg(result); if (result.isFlag()) { ++_TokenOffset; } else if (result.isExtended()) { _ArgOffset+=2; _TokenOffset+=2; if (result._Type == CArg::EXTEND_TYPE && result._Value.ExType >= CArg::ET_64_BIT_EXTENDED_TYPES) { // this is a 96 bit extended type, skip another pair _ArgOffset++; _TokenOffset++; } } else { ++_ArgOffset; ++_TokenOffset; } return; } //inline CPersistentDataRecord::CArg CPersistentDataRecord::popNextArg(TToken token) //{ // CArg arg; // DROP_IF(peekNextToken()!=token,"Error on read code - token requested doesn't match token found",return arg); // arg= peekNextArg(); // if (arg.isFlag()) // { // ++_TokenOffset; // } // else if (arg.isExtended()) // { // _ArgOffset+=2; // _TokenOffset+=2; // // if (arg._Type == CArg::EXTEND_TYPE && arg._Value.ExType >= CArg::ET_64_BIT_EXTENDED_TYPES) // { // // this is a 96 bit extended type, skip another pair // _ArgOffset++; // _TokenOffset++; // } // } // else // { // ++_ArgOffset; // ++_TokenOffset; // } // return arg; //} inline void CPersistentDataRecord::pop(TToken token,bool& result) { popNextArg(token,TempArg); result= (TempArg.asSint()!=0); } inline void CPersistentDataRecord::pop(TToken token,sint8& result) { popNextArg(token,TempArg); result= (sint8)TempArg.asSint(); } inline void CPersistentDataRecord::pop(TToken token,sint16& result) { popNextArg(token,TempArg); result= (sint16)TempArg.asSint(); } inline void CPersistentDataRecord::pop(TToken token,sint32& result) { popNextArg(token,TempArg); result= (sint32)TempArg.asSint(); } inline void CPersistentDataRecord::pop(TToken token,sint64& result) { popNextArg(token,TempArg); result= (sint64)TempArg.asSint(); } inline void CPersistentDataRecord::pop(TToken token,uint8& result) { popNextArg(token,TempArg); result= (uint8)TempArg.asUint(); } inline void CPersistentDataRecord::pop(TToken token,uint16& result) { popNextArg(token,TempArg); result= (uint16)TempArg.asUint(); } inline void CPersistentDataRecord::pop(TToken token,uint32& result) { popNextArg(token,TempArg); result= (uint32)TempArg.asUint(); } inline void CPersistentDataRecord::pop(TToken token,uint64& result) { popNextArg(token,TempArg); result= (uint64)TempArg.asUint(); } inline void CPersistentDataRecord::pop(TToken token,float& result) { popNextArg(token,TempArg); result= TempArg.asFloat(); } inline void CPersistentDataRecord::pop(TToken token,double& result) { popNextArg(token,TempArg); result= TempArg.asDouble(); } inline void CPersistentDataRecord::pop(TToken token,std::string& result) { popNextArg(token,TempArg); result= TempArg.asString(); } inline void CPersistentDataRecord::pop(TToken token,ucstring& result) { popNextArg(token,TempArg); result= TempArg.asUCString(); } inline void CPersistentDataRecord::pop(TToken token,NLMISC::CSheetId& result) { popNextArg(token,TempArg); result= TempArg.asSheetId(); } inline void CPersistentDataRecord::pop(TToken token,NLMISC::CEntityId& result) { popNextArg(token,TempArg); result= TempArg.asEntityId(); } inline void CPersistentDataRecord::pop(TToken /* token */) { ++_TokenOffset; } inline void CPersistentDataRecord::popStructBegin(TToken token) { DROP_IF(peekNextToken()!=token,"Attempting to enter a structure with the wrong delimiting token",return); DROP_IF(peekNextTokenType()!=CArg::STRUCT_BEGIN,"Attempting to enter a structure with the wrong delimiting token type",return); _ReadingStructStack.push_back(token); ++_TokenOffset; } inline void CPersistentDataRecord::popStructEnd(TToken token) { DROP_IF(_ReadingStructStack.empty(),"Attempting to pop end of a structure with nothing left in the open structure stack",return); TToken nextToken=peekNextToken(); TToken topToken=_ReadingStructStack.back(); DROP_IF(topToken!=token,"Attempting to pop end of a structure with the wrong delimiting token",return); DROP_IF(nextToken!=token,"Attempting to pop end of a structure with the wrong delimiting token",return); DROP_IF(peekNextTokenType()!=CArg::STRUCT_END,"Attempting to leave a structure with the wrong delimiting token type",return); _ReadingStructStack.pop_back(); ++_TokenOffset; } //------------------------------------------------------------------------- // methods CPersistentDataRecord::CArg //------------------------------------------------------------------------- inline CPersistentDataRecord::CArg::CArg() { _Type= STRING; _Value.i64= 0; } inline CPersistentDataRecord::CArg::CArg(const std::string& type,const std::string& value,CPersistentDataRecord& pdr) { if (setType(type)==false) return; switch (_Type) { case SINT32: _Value.i32=NLMISC::CSString(value).atoi(); break; case UINT32: _Value.i32=NLMISC::CSString(value).atoi(); break; case SINT64: _Value.i64=NLMISC::atoiInt64(value.c_str()); break; case UINT64: _Value.i64=NLMISC::atoiInt64(value.c_str()); break; case FLOAT32: NLMISC::fromString(value, _Value.f32); break; case FLOAT64: NLMISC::fromString(value, _Value.f64); break; case STRING: _Value.i32=pdr.addString(value); _String=value; break; case EXTEND_TYPE: switch(_Value.ExType) { case ET_SHEET_ID: { // Cf. CArg::asString() if (value.size() != 0 && value[0] == '#') { _Value.ex32_1 = NLMISC::CSString(value.c_str()+1).atoi(); } else { NLMISC::CSheetId sheetId(value); STOP_IF( (sheetId == NLMISC::CSheetId::Unknown && value != "unknown.unknown"), "sheet_id.bin version does not match save game version" ); _Value.ExData32 = sheetId.asInt(); } } break; case ET_ENTITY_ID: { NLMISC::CEntityId entityId(value); _Value.ExData64 = entityId.getRawId(); } break; default: STOP("This should never happen!"); break; } break; case FLAG: break; default: STOP("This should never happen!"); break; } } inline uint64 CPersistentDataRecord::CArg::asUint() const { switch (_Type) { case STRUCT_BEGIN: case STRUCT_END: BOMB("Can't extract a value from a structure delimiter", return 0); case SINT32: return (uint64)(sint32)_Value.i32; case UINT32: return (uint64)(uint32)_Value.i32; // 2 casts to ensure no sign extend case SINT64: return (uint64)_Value.i64; case UINT64: return (uint64)_Value.i64; case FLOAT32: return (uint64)_Value.f32; case FLOAT64: return (uint64)_Value.f64; case STRING: return (uint64)NLMISC::atoiInt64(_String.c_str()); case FLAG: return 1; case EXTEND_TYPE: switch(_Value.ExType) { case ET_SHEET_ID: return _Value.ExData32; case ET_ENTITY_ID: return _Value.ExData64; default: break; } default: break; } STOP("This should never happen!"); return 0; } inline sint64 CPersistentDataRecord::CArg::asSint() const { switch (_Type) { case STRUCT_BEGIN: case STRUCT_END: BOMB("Can't extract a value from a structure delimiter", return 0); case SINT32: return (sint64)(sint32)_Value.i32; case UINT32: return (sint64)(uint32)_Value.i32; case SINT64: return (sint64)_Value.i64; case UINT64: return (sint64)_Value.i64; case FLOAT32: return (sint64)_Value.f32; case FLOAT64: return (sint64)_Value.f64; case STRING: return (sint64)NLMISC::atoiInt64(_String.c_str()); case FLAG: return 1; case EXTEND_TYPE: switch(_Value.ExType) { case ET_SHEET_ID: return _Value.ExData32; case ET_ENTITY_ID: return _Value.ExData64; default: break; } default: break; } STOP("This should never happen!"); return 0; } inline float CPersistentDataRecord::CArg::asFloat() const { switch (_Type) { case STRUCT_BEGIN: case STRUCT_END: BOMB("Can't extract a value from a structure delimiter", return 0); case SINT32: return (float)(sint32)_Value.i32; case UINT32: return (float)(uint32)_Value.i32; case SINT64: return (float)(sint64)_Value.i64; case UINT64: return (float)(uint64)_Value.i64; case FLOAT32: return (float)_Value.f32; case FLOAT64: return (float)_Value.f64; case STRING: return (float)atof(_String.c_str()); case FLAG: return 1.0f; case EXTEND_TYPE: switch(_Value.ExType) { case ET_SHEET_ID: return float(_Value.ExData32); case ET_ENTITY_ID: return float(_Value.ExData64); default: break; } default: break; } STOP("This should never happen!"); return 0.0f; } inline double CPersistentDataRecord::CArg::asDouble() const { switch (_Type) { case STRUCT_BEGIN: case STRUCT_END: BOMB("Can't extract a value from a structure delimiter", return 0); case SINT32: return (double)(sint32)_Value.i32; case UINT32: return (double)(uint32)_Value.i32; case SINT64: return (double)(sint64)_Value.i64; case UINT64: return (double)(uint64)_Value.i64; case FLOAT32: return (double)_Value.f32; case FLOAT64: return (double)_Value.f64; case STRING: return (double)atof(_String.c_str()); case FLAG: return 1.0; case EXTEND_TYPE: switch(_Value.ExType) { case ET_SHEET_ID: return double(_Value.ExData32); case ET_ENTITY_ID: return double(_Value.ExData64); default: break; } default: break; } STOP("This should never happen!"); return 0.0; } inline NLMISC::CSString CPersistentDataRecord::CArg::asString() const { switch (_Type) { case STRUCT_BEGIN: case STRUCT_END: BOMB("Can't extract a value from a structure delimiter", return 0); case SINT32: return NLMISC::toString((sint32)_Value.i32); case UINT32: return NLMISC::toString((uint32)_Value.i32); case SINT64: return NLMISC::toString((sint64)_Value.i64); case UINT64: return NLMISC::toString((uint64)_Value.i64); case FLOAT32: return NLMISC::toString(_Value.f32); case FLOAT64: return NLMISC::toString(_Value.f64); case STRING: return _String; case FLAG: return "1"; case EXTEND_TYPE: switch(_Value.ExType) { case ET_SHEET_ID: { NLMISC::CSheetId sheetId(_Value.ExData32); return sheetId.toString(true); } case ET_ENTITY_ID: { NLMISC::CEntityId entityId(_Value.ExData64); return entityId.toString(); } default: break; } default: break; } STOP("This should never happen!"); return ""; } inline ucstring CPersistentDataRecord::CArg::asUCString() const { switch (_Type) { case STRUCT_BEGIN: case STRUCT_END: BOMB("Can't extract a value from a structure delimiter", return ucstring()); case SINT32: return (ucstring)NLMISC::toString((sint32)_Value.i32); case UINT32: return (ucstring)NLMISC::toString((uint32)_Value.i32); case SINT64: return (ucstring)NLMISC::toString((sint64)_Value.i64); case UINT64: return (ucstring)NLMISC::toString((uint64)_Value.i64); case FLOAT32: return (ucstring)NLMISC::toString(_Value.f32); case FLOAT64: return (ucstring)NLMISC::toString(_Value.f64); case STRING: { ucstring s; s.fromUtf8(_String); return s; } case FLAG: return (ucstring)"1"; case EXTEND_TYPE: switch(_Value.ExType) { case ET_SHEET_ID: { NLMISC::CSheetId sheetId(_Value.ExData32); return sheetId.toString(true); } case ET_ENTITY_ID: { NLMISC::CEntityId entityId(_Value.ExData64); return entityId.toString(); } default: break; } default: break; } STOP("This should never happen!"); return ucstring(""); } inline NLMISC::CEntityId CPersistentDataRecord::CArg::asEntityId() const { switch (_Type) { case STRUCT_BEGIN: case STRUCT_END: BOMB("Can't extract a value from a structure delimiter", return NLMISC::CEntityId()); case SINT32: return NLMISC::CEntityId((uint64)_Value.i32); case UINT32: return NLMISC::CEntityId((uint64)_Value.i32); case SINT64: return NLMISC::CEntityId((uint64)_Value.i64); case UINT64: return NLMISC::CEntityId((uint64)_Value.i64); case FLOAT32: return NLMISC::CEntityId((uint64)_Value.f32); case FLOAT64: return NLMISC::CEntityId((uint64)_Value.f64); case STRING: { // try a convertion from '(0x000000000000000:00:00:00)' format NLMISC::CEntityId result(_String); // if the convertion returned '0' then check for decimal format if (result.asUint64()==0) { result= asUint(); } // return whatever we found return result; } case FLAG: return NLMISC::CEntityId(); case EXTEND_TYPE: switch(_Value.ExType) { case ET_SHEET_ID: { return NLMISC::CEntityId(); } case ET_ENTITY_ID: return NLMISC::CEntityId(_Value.ExData64); default: break; } default: break; } STOP("This should never happen!"); return NLMISC::CEntityId(); } inline NLMISC::CSheetId CPersistentDataRecord::CArg::asSheetId() const { switch (_Type) { case STRUCT_BEGIN: case STRUCT_END: BOMB("Can't extract a value from a structure delimiter", return NLMISC::CSheetId(0u)); case SINT32: return NLMISC::CSheetId((uint32)_Value.i32); case UINT32: return NLMISC::CSheetId((uint32)_Value.i32); case SINT64: return NLMISC::CSheetId((uint32)_Value.i64); case UINT64: return NLMISC::CSheetId((uint32)_Value.i64); case FLOAT32: return NLMISC::CSheetId((uint32)_Value.f32); case FLOAT64: return NLMISC::CSheetId((uint32)_Value.f64); case STRING: return NLMISC::CSheetId(_String); case FLAG: return NLMISC::CSheetId(); case EXTEND_TYPE: switch(_Value.ExType) { case ET_SHEET_ID: { return NLMISC::CSheetId (_Value.ExData32); } case ET_ENTITY_ID: return NLMISC::CSheetId(); default: break; } default: break; } STOP("This should never happen!"); return NLMISC::CSheetId(); } inline NLMISC::CSString CPersistentDataRecord::CArg::typeName() const { switch (_Type) { case STRUCT_BEGIN: case STRUCT_END: BOMB("Can't extract a value from a structure delimiter", return 0); case SINT32: return "SINT32"; case UINT32: return "UINT32"; case SINT64: return "SINT64"; case UINT64: return "UINT64"; case FLOAT32: return "FLOAT"; case FLOAT64: return "DOUBLE"; case STRING: return "STRING";; case FLAG: return "FLAG"; case EXTEND_TYPE: switch(_Value.ExType) { case ET_SHEET_ID: return "SHEET_ID"; case ET_ENTITY_ID: return "ENTITY_ID"; default: break; } default: break; } STOP("This should never happen!"); return ""; } inline bool CPersistentDataRecord::CArg::setType(const std::string &name) { _Type=SINT32; if (typeName()==name) return true; _Type=UINT32; if (typeName()==name) return true; _Type=SINT64; if (typeName()==name) return true; _Type=UINT64; if (typeName()==name) return true; _Type=FLOAT32; if (typeName()==name) return true; _Type=FLOAT64; if (typeName()==name) return true; _Type=FLAG; if (typeName()==name) return true; _Type=STRING; if (typeName()==name) return true; // special case for extended types _Type=EXTEND_TYPE; { _Value.ExType = ET_SHEET_ID; if (typeName()==name) return true; _Value.ExType = ET_ENTITY_ID; if (typeName()==name) return true; } DROP(("Failed to find match for type name '"+name+"' => defaulting to string").c_str(),return false); } inline void CPersistentDataRecord::CArg::setType(CPersistentDataRecord::CArg::TType value) { BOMB_IF(value<0 || value>=CArg::NB_TYPE,"Invalid argument type",return); _Type=value; } inline bool CPersistentDataRecord::CArg::isFlag() const { return _Type==FLAG; } inline bool CPersistentDataRecord::CArg::isExtended() const { return isTypeExtended(_Type); } inline void CPersistentDataRecord::CArg::push(TToken token, std::vector& tokenTable, std::vector& argTable) const { BOMB_IF( ((token<<3)>>3)!= token, "Invalid token - Insufficient numeric precision", return); switch (_Type) { case FLAG: tokenTable.push_back((token<<3)+CArg::type2Token(_Type)); break; case STRING: // drop though to INT32 case FLOAT32: // drop though to INT32 case SINT32: case UINT32: tokenTable.push_back((token<<3)+CArg::type2Token(_Type)); argTable.push_back(_Value.i32); break; case FLOAT64: // drop though to INT64 case SINT64: case UINT64: case EXTEND_TYPE: tokenTable.push_back((token<<3)+CArg::EXTEND_TOKEN); argTable.push_back(_Value.i32_1); tokenTable.push_back((token<<3)+CArg::type2Token(_Type)); argTable.push_back(_Value.i32_2); if (_Type == EXTEND_TYPE && _Value.ExType >= ET_64_BIT_EXTENDED_TYPES) { // 96 bit extended type, add another 32 bit value tokenTable.push_back((token<<3)+CArg::type2Token(_Type)); argTable.push_back(_Value.ex32_2); } break; default: BOMB("This should never happen!!!",return); } } inline CPersistentDataRecord::CArg CPersistentDataRecord::CArg::EntityId(NLMISC::CEntityId val) { CArg arg; arg._Type= EXTEND_TYPE; arg._Value.ExType = ET_ENTITY_ID; arg._Value.ExData64 = val.getRawId(); return arg; } inline CPersistentDataRecord::CArg CPersistentDataRecord::CArg::SheetId(NLMISC::CSheetId val) { CArg arg; arg._Type= EXTEND_TYPE; arg._Value.ExType = ET_SHEET_ID; arg._Value.ExData32 = val.asInt(); return arg; } inline CPersistentDataRecord::CArg CPersistentDataRecord::CArg::Int32(sint32 val) { CArg arg; arg._Type= SINT32; arg._Value.i32= val; return arg; } inline CPersistentDataRecord::CArg CPersistentDataRecord::CArg::Int32(uint32 val) { CArg arg; arg._Type= UINT32; arg._Value.i32= val; return arg; } inline CPersistentDataRecord::CArg CPersistentDataRecord::CArg::Int64(sint64 val) { CArg arg; arg._Type= SINT64; arg._Value.i64= val; return arg; } inline CPersistentDataRecord::CArg CPersistentDataRecord::CArg::Int64(uint64 val) { CArg arg; arg._Type= UINT64; arg._Value.i64= val; return arg; } inline CPersistentDataRecord::CArg CPersistentDataRecord::CArg::Float32(float val) { CArg arg; arg._Type= FLOAT32; arg._Value.f32= val; return arg; } inline CPersistentDataRecord::CArg CPersistentDataRecord::CArg::Float64(double val) { CArg arg; arg._Type= FLOAT64; arg._Value.f64= val; return arg; } inline CPersistentDataRecord::CArg CPersistentDataRecord::CArg::String(const std::string& value,CPersistentDataRecord& pdr) { CArg arg; arg._Type= STRING; arg._Value.i32= pdr.addString(value); arg._String= value; return arg; } inline CPersistentDataRecord::CArg CPersistentDataRecord::CArg::UCString(const ucstring& value,CPersistentDataRecord& pdr) { NLMISC::CSString s = value.toUtf8(); CArg arg; arg._Type= STRING; arg._Value.i32= pdr.addString(s); arg._String= s; return arg; } inline CPersistentDataRecord::CArg CPersistentDataRecord::CArg::Flag() { CArg arg; arg._Type= FLAG; arg._Value.i32= 1; return arg; } inline CPersistentDataRecord::CArg::TType CPersistentDataRecord::CArg::token2Type(uint32 token,bool extend) { switch (token) { case BEGIN_TOKEN: return STRUCT_BEGIN; case END_TOKEN: return STRUCT_END; case FLAG_TOKEN: return FLAG; case SINT_TOKEN: return extend? SINT64: SINT32; case UINT_TOKEN: return extend? UINT64: UINT32; case FLOAT_TOKEN: return extend? FLOAT64: FLOAT32; case STRING_TOKEN: return extend? EXTEND_TYPE: STRING; } STOP("This should never happen!"); return CArg::TType(0); } inline CPersistentDataRecord::TToken CPersistentDataRecord::CArg::type2Token(uint32 type) { switch (type) { case STRUCT_BEGIN: return BEGIN_TOKEN; case STRUCT_END: return END_TOKEN; case FLAG: return FLAG_TOKEN; case SINT32: return SINT_TOKEN; case UINT32: return UINT_TOKEN; case FLOAT32: return FLOAT_TOKEN; case STRING: return STRING_TOKEN; case SINT64: return SINT_TOKEN; case UINT64: return UINT_TOKEN; case FLOAT64: return FLOAT_TOKEN; case EXTEND_TYPE: return STRING_TOKEN; } STOP("This should never happen!"); return 0; } inline bool CPersistentDataRecord::CArg::isTypeExtended(uint32 type) { switch (type) { case STRUCT_BEGIN: case STRUCT_END: BOMB("Can't extract a value from a structure delimiter", return 0); case SINT32: case UINT32: case FLOAT32: case STRING: case FLAG: return false; case SINT64: case UINT64: case FLOAT64: case EXTEND_TYPE: return true; } STOP("This should never happen!"); return false; }