/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /* * Copyright (C) 2006-2010 - Frictional Games * * This file is part of HPL1 Engine. */ #include "hpl1/engine/system/SerializeClass.h" #include "hpl1/engine/system/low_level_system.h" #include "hpl1/engine/system/String.h" #include "hpl1/engine/graphics/GraphicsTypes.h" #include "hpl1/engine/math/MathTypes.h" #include "hpl1/engine/system/Container.h" #include "common/savefile.h" #include "hpl1/debug.h" #include "hpl1/engine/impl/tinyXML/tinyxml.h" #include "hpl1/hpl1.h" #include "hpl1/serialize.h" namespace hpl { ////////////////////////////////////////////////////////////////////////// // SERIALIZE MEMBER FIELD ITERATOR ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cSerializeMemberFieldIterator::cSerializeMemberFieldIterator(cSerializeSavedClass *apTopClass) { mlFieldNum = 0; mpSavedClass = apTopClass; // Make sure that the first field type is not null if (mpSavedClass && mpSavedClass->mpMemberFields[mlFieldNum].mType == eSerializeType_NULL) { if (mpSavedClass->msParentName[0] != '\0') { cSerializeSavedClass *pClass = cSerializeClass::GetClass(mpSavedClass->msParentName); if (pClass) { mpSavedClass = pClass; mlFieldNum = 0; } } } } //----------------------------------------------------------------------- bool cSerializeMemberFieldIterator::HasNext() { if (mpSavedClass == NULL || mpSavedClass->mpMemberFields[mlFieldNum].mType == eSerializeType_NULL) { return false; } return true; } //----------------------------------------------------------------------- cSerializeMemberField *cSerializeMemberFieldIterator::GetNext() { cSerializeMemberField *pField = &mpSavedClass->mpMemberFields[mlFieldNum]; mlFieldNum++; if (mpSavedClass->mpMemberFields[mlFieldNum].mType == eSerializeType_NULL) { if (mpSavedClass->msParentName[0] != '\0') { cSerializeSavedClass *pClass = cSerializeClass::GetClass(mpSavedClass->msParentName); if (pClass) { mpSavedClass = pClass; mlFieldNum = 0; } } } return pField; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // SERIALIZE CLASS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- // Define static variables tSerializeSavedClassMap *cSerializeClass::m_mapSavedClasses; bool cSerializeClass::mbDataSetup = false; char cSerializeClass::msTempCharArray[2048]; void cSerializeClass::initSaveClassesMap() { cSerializeClass::m_mapSavedClasses = new tSerializeSavedClassMap; } void cSerializeClass::finalizeSaveClassesMap() { delete cSerializeClass::m_mapSavedClasses; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PUBLIC SERIALIZE CLASS METHODS ////////////////////////////////////////////////////////////////////////// static bool gbLog = false; static int glTabs = 0; static const char *gsTabString = ""; const char *GetTabs() { return gsTabString; } //----------------------------------------------------------------------- void cSerializeClass::SetLog(bool abX) { gbLog = abX; } bool cSerializeClass::GetLog() { return gbLog; } //----------------------------------------------------------------------- void cSerializeClass::PrintMembers(iSerializable *apData) { SetUpData(); cSerializeMemberFieldIterator classIt = GetMemberFieldIterator(apData); Log("Members of class '%s':\n", apData->Serialize_GetTopClass().c_str()); while (classIt.HasNext()) { cSerializeMemberField *pField = classIt.GetNext(); Log(" '%s':'%s' type: %d offset: %d\n", pField->msName.c_str(), ValueToString(apData, pField->mlOffset, pField->mType).c_str(), pField->mType, pField->mlOffset); } } //----------------------------------------------------------------------- bool cSerializeClass::SaveToFile(iSerializable *apData, const tWString &saveFile, const tString &asRoot) { SetUpData(); glTabs = 0; Common::String filename(Hpl1::g_engine->createSaveFile(saveFile)); TiXmlDocument pXmlDoc; // Create root TiXmlElement XmlRoot(asRoot.c_str()); TiXmlElement *pRootElem = static_cast(pXmlDoc.InsertEndChild(XmlRoot)); Common::ScopedPtr savefile(g_engine->getSaveFileManager()->openForSaving(filename)); if (!savefile) { Hpl1::logError(Hpl1::kDebugSaves, "could't open file %s for saving\n", filename.c_str()); return false; } SaveToElement(apData, "", pRootElem); if (!pXmlDoc.SaveFile(*savefile)) { Hpl1::logError(Hpl1::kDebugSaves, "couldn't save to file '%s'\n", filename.c_str()); return false; } g_engine->getMetaEngine()->appendExtendedSave(savefile.get(), g_engine->getTotalPlayTime(), saveFile, filename.contains("auto")); return true; } //----------------------------------------------------------------------- void cSerializeClass::SaveToElement(iSerializable *apData, const tString &asName, TiXmlElement *apParent, bool abIsPointer) { SetUpData(); if (apData == NULL) return; // Create element TiXmlElement *pClassElem = NULL; if (abIsPointer) { TiXmlElement XmlClassElem("class_ptr"); pClassElem = static_cast(apParent->InsertEndChild(XmlClassElem)); } else { TiXmlElement XmlClassElem("class"); pClassElem = static_cast(apParent->InsertEndChild(XmlClassElem)); } // Set attributes pClassElem->SetAttribute("type", apData->Serialize_GetTopClass().c_str()); pClassElem->SetAttribute("name", asName.c_str()); if (gbLog) Log("---Saving class '%s'---\n", apData->Serialize_GetTopClass().c_str()); cSerializeMemberFieldIterator classIt = GetMemberFieldIterator(apData); while (classIt.HasNext()) { cSerializeMemberField *pField = classIt.GetNext(); if (gbLog) Log(" Field : '%s'\n", pField->msName.c_str()); switch (pField->mMainType) { // VARIABLE ///////////////////////////////// case eSerializeMainType_Variable: { SaveVariable(pClassElem, pField, apData); break; } // ARRAY //////////////////////////////////// case eSerializeMainType_Array: { SaveArray(pClassElem, pField, apData); break; } // CONTAINER //////////////////////////////////// case eSerializeMainType_Container: { SaveContainer(pClassElem, pField, apData); break; } } } } //----------------------------------------------------------------------- bool cSerializeClass::LoadFromFile(iSerializable *apData, const tWString &asFile) { SetUpData(); glTabs = 0; // Load document TiXmlDocument pXmlDoc; Common::String filename(Hpl1::g_engine->mapInternalSaveToFile(asFile)); Common::ScopedPtr saveFile(g_engine->getSaveFileManager()->openForLoading(filename)); if (!saveFile) { Hpl1::logError(Hpl1::kDebugSaves | Hpl1::kDebugResourceLoading, "save file %s could not be opened\n", filename.c_str()); return false; } ExtendedSavegameHeader header; if (!MetaEngine::readSavegameHeader(saveFile.get(), &header)) { Hpl1::logError(Hpl1::kDebugResourceLoading | Hpl1::kDebugSaves, "couldn't load header from save file %s\n", filename.c_str()); return false; } g_engine->setTotalPlayTime(header.playtime); if (pXmlDoc.LoadFile(*saveFile) == false) { Hpl1::logError(Hpl1::kDebugResourceLoading | Hpl1::kDebugSaves, "Couldn't load saved class file '%S' from %s!\n", asFile.c_str(), pXmlDoc.ErrorDesc()); return false; } // Get root TiXmlElement *pRootElem = pXmlDoc.RootElement(); // Get first, there should only be ONE class at the root. TiXmlElement *pClassElem = pRootElem->FirstChildElement("class"); LoadFromElement(apData, pClassElem); return true; } //----------------------------------------------------------------------- void cSerializeClass::LoadFromElement(iSerializable *apData, TiXmlElement *apElement, bool abIsPointer) { SetUpData(); cSerializeSavedClass *pClass = GetClass(apData->Serialize_GetTopClass()); if (pClass == NULL) return; if (gbLog) { Log("%sBegin class %s\n", GetTabs(), pClass->msName); ++glTabs; } TiXmlElement *pMemberElem = apElement->FirstChildElement(); for (; pMemberElem != NULL; pMemberElem = pMemberElem->NextSiblingElement()) { tString sMainType = pMemberElem->Value(); if (gbLog) Log("%sMember field type %s\n", GetTabs(), sMainType.c_str()); if (sMainType == "var") { LoadVariable(pMemberElem, apData, pClass); } else if (sMainType == "array") { LoadArray(pMemberElem, apData, pClass); } else if (sMainType == "class") { LoadClass(pMemberElem, apData, pClass); } else if (sMainType == "class_ptr") { LoadClassPointer(pMemberElem, apData, pClass); } else if (sMainType == "container") { LoadContainer(pMemberElem, apData, pClass); } } if (gbLog) { --glTabs; Log("%sEnd class %s\n", GetTabs(), pClass->msName); } } //----------------------------------------------------------------------- cSerializeSavedClass *cSerializeClass::GetClass(const tString &asName) { SetUpData(); tSerializeSavedClassMapIt it = m_mapSavedClasses->find(asName.c_str()); if (it == m_mapSavedClasses->end()) { Warning("Serialize class '%s' not found!\n", asName.c_str()); return NULL; } return &it->second; } //----------------------------------------------------------------------- cSerializeMemberFieldIterator cSerializeClass::GetMemberFieldIterator(iSerializable *apData) { cSerializeSavedClass *pClass = GetClass(apData->Serialize_GetTopClass()); return cSerializeMemberFieldIterator(pClass); } //----------------------------------------------------------------------- #define ValueTypePointer(aObject, aOffset, aType) (aType *)(((char *)aObject) + aOffset) #define ValuePointer(aObject, aOffset) (((char *)aObject) + aOffset) #define PointerValue(aPointer, aType) (*((aType *)aPointer)) tString cSerializeClass::ValueToString(void *apData, size_t alOffset, eSerializeType aType) { void *pVal = ValuePointer(apData, alOffset); switch (aType) { /////////// BOOL //////////////////////////////// case eSerializeType_Bool: { if (PointerValue(pVal, bool) == 0) return "false"; else return "true"; break; } /////////// INT 32 //////////////////////////////// case eSerializeType_Int32: { snprintf(msTempCharArray, 2048, "%d", PointerValue(pVal, int)); return msTempCharArray; break; } /////////// FLOAT 32 //////////////////////////////// case eSerializeType_Float32: { snprintf(msTempCharArray, 2048, "%f", PointerValue(pVal, float)); return msTempCharArray; break; } /////////// STRING //////////////////////////////// case eSerializeType_String: { tString &sVal = PointerValue(pVal, tString); return sVal.c_str(); break; } /////////// VECTOR 2L //////////////////////////////// case eSerializeType_Vector2l: { cVector2l &vVec = PointerValue(pVal, cVector2l); snprintf(msTempCharArray, 2048, "%d %d", vVec.x, vVec.y); return msTempCharArray; break; } /////////// VECTOR 2F //////////////////////////////// case eSerializeType_Vector2f: { cVector2f &vVec = PointerValue(pVal, cVector2f); snprintf(msTempCharArray, 2048, "%f %f", vVec.x, vVec.y); return msTempCharArray; break; } /////////// VECTOR 3L //////////////////////////////// case eSerializeType_Vector3l: { cVector3l &vVec = PointerValue(pVal, cVector3l); snprintf(msTempCharArray, 2048, "%d %d %d", vVec.x, vVec.y, vVec.z); return msTempCharArray; break; } /////////// VECTOR 3F //////////////////////////////// case eSerializeType_Vector3f: { cVector3f &vVec = PointerValue(pVal, cVector3f); snprintf(msTempCharArray, 2048, "%f %f %f", vVec.x, vVec.y, vVec.z); return msTempCharArray; break; } /////////// MATRIX F //////////////////////////////// case eSerializeType_Matrixf: { cMatrixf &Mtx = PointerValue(pVal, cMatrixf); snprintf(msTempCharArray, 2048, "%f %f %f %f " "%f %f %f %f " "%f %f %f %f " "%f %f %f %f", Mtx.m[0][0], Mtx.m[0][1], Mtx.m[0][2], Mtx.m[0][3], Mtx.m[1][0], Mtx.m[1][1], Mtx.m[1][2], Mtx.m[1][3], Mtx.m[2][0], Mtx.m[2][1], Mtx.m[2][2], Mtx.m[2][3], Mtx.m[3][0], Mtx.m[3][1], Mtx.m[3][2], Mtx.m[3][3]); return msTempCharArray; break; } /////////// COLOR //////////////////////////////// case eSerializeType_Color: { cColor Col = PointerValue(pVal, cColor); snprintf(msTempCharArray, 2048, "%f %f %f %f", Col.r, Col.g, Col.b, Col.a); return msTempCharArray; break; } /////////// RECT 2L //////////////////////////////// case eSerializeType_Rect2l: { cRect2l &vR = PointerValue(pVal, cRect2l); snprintf(msTempCharArray, 2048, "%d %d %d %d", vR.x, vR.y, vR.w, vR.h); return msTempCharArray; break; } /////////// RECT 2F //////////////////////////////// case eSerializeType_Rect2f: { cRect2f &vR = PointerValue(pVal, cRect2f); snprintf(msTempCharArray, 2048, "%f %f %f %f", vR.x, vR.y, vR.w, vR.h); return msTempCharArray; break; } /////////// PLANE F //////////////////////////////// case eSerializeType_Planef: { cPlanef &vP = PointerValue(pVal, cPlanef); snprintf(msTempCharArray, 2048, "%f %f %f %f", vP.a, vP.b, vP.c, vP.d); return msTempCharArray; break; } /////////// WSTRING //////////////////////////////// case eSerializeType_WString: { tString temp = ""; tWString &wsString = PointerValue(pVal, tWString); for (size_t i = 0; i < wsString.size(); ++i) { temp += cString::ToString((int)wsString[i]) + " "; } return temp; break; } } return ""; } //----------------------------------------------------------------------- void cSerializeClass::StringToValue(void *apData, size_t alOffset, eSerializeType aType, const char *asVal) { void *pVal = ValuePointer(apData, alOffset); switch (aType) { /////////// BOOL //////////////////////////////// case eSerializeType_Bool: { PointerValue(pVal, bool) = cString::ToBool(asVal, false); break; } ////////// INT 32 //////////////////////////////// case eSerializeType_Int32: { PointerValue(pVal, int) = cString::ToInt(asVal, 0); break; } ////////// FLOAT 32 //////////////////////////////// case eSerializeType_Float32: { PointerValue(pVal, float) = cString::ToFloat(asVal, 0); break; } ////////// STRING //////////////////////////////// case eSerializeType_String: { PointerValue(pVal, tString) = cString::ToString(asVal, ""); break; } /////////// VECTOR 2L //////////////////////////////// case eSerializeType_Vector2l: { tIntVec vVals; vVals.reserve(2); cString::GetIntVec(asVal, vVals, NULL); PointerValue(pVal, cVector2l).FromVec(&vVals[0]); break; } /////////// VECTOR 2F //////////////////////////////// case eSerializeType_Vector2f: { tFloatVec vVals; vVals.reserve(2); cString::GetFloatVec(asVal, vVals, NULL); PointerValue(pVal, cVector2f).FromVec(&vVals[0]); break; } /////////// VECTOR 3L //////////////////////////////// case eSerializeType_Vector3l: { tIntVec vVals; vVals.reserve(3); cString::GetIntVec(asVal, vVals, NULL); PointerValue(pVal, cVector3l).FromVec(&vVals[0]); break; } /////////// VECTOR 3F //////////////////////////////// case eSerializeType_Vector3f: { tFloatVec vVals; vVals.reserve(3); cString::GetFloatVec(asVal, vVals, NULL); PointerValue(pVal, cVector3f).FromVec(&vVals[0]); break; } /////////// MATRIX F //////////////////////////////// case eSerializeType_Matrixf: { tFloatVec vVals; vVals.reserve(16); cString::GetFloatVec(asVal, vVals, NULL); PointerValue(pVal, cMatrixf).FromVec(&vVals[0]); break; } /////////// COLOR //////////////////////////////// case eSerializeType_Color: { tFloatVec vVals; vVals.reserve(4); cString::GetFloatVec(asVal, vVals, NULL); PointerValue(pVal, cColor).FromVec(&vVals[0]); break; } /////////// RECT 2L //////////////////////////////// case eSerializeType_Rect2l: { tIntVec vVals; vVals.reserve(4); cString::GetIntVec(asVal, vVals, NULL); PointerValue(pVal, cRect2l).FromVec(&vVals[0]); break; } /////////// RECT 2F //////////////////////////////// case eSerializeType_Rect2f: { tFloatVec vVals; vVals.reserve(4); cString::GetFloatVec(asVal, vVals, NULL); PointerValue(pVal, cRect2f).FromVec(&vVals[0]); break; } /////////// PLANE 2F //////////////////////////////// case eSerializeType_Planef: { tFloatVec vVals; vVals.reserve(4); cString::GetFloatVec(asVal, vVals, NULL); PointerValue(pVal, cPlanef).FromVec(&vVals[0]); break; } /////////// WSTRING //////////////////////////////// case eSerializeType_WString: { PointerValue(pVal, tWString) = cString::Get16BitFromArray(asVal); break; } } } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PUBLIC SERIALIZE CLASS METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cSerializeClass::SaveVariable(TiXmlElement *apElement, cSerializeMemberField *apField, iSerializable *apData) { // CLASS if (apField->mType == eSerializeType_Class) { void *pClassData = ValuePointer(apData, apField->mlOffset); SaveToElement((iSerializable *)pClassData, apField->msName.c_str(), apElement); } // CLASS POINTER else if (apField->mType == eSerializeType_ClassPointer) { iSerializable **pFieldData = (iSerializable **)ValuePointer(apData, apField->mlOffset); SaveToElement(*pFieldData, apField->msName.c_str(), apElement, true); } // NORMAL VAR else { TiXmlElement XmlVarElem("var"); TiXmlElement *pVarElem = static_cast(apElement->InsertEndChild(XmlVarElem)); pVarElem->SetAttribute("type", apField->mType); pVarElem->SetAttribute("name", apField->msName.c_str()); pVarElem->SetAttribute("val", ValueToString(apData, apField->mlOffset, apField->mType).c_str()); } } //----------------------------------------------------------------------- void cSerializeClass::SaveArray(TiXmlElement *apElement, cSerializeMemberField *apField, iSerializable *apData) { void *pArrayData = ValuePointer(apData, apField->mlOffset); TiXmlElement XmlArrayElem("array"); TiXmlElement *pArrayElem = static_cast(apElement->InsertEndChild(XmlArrayElem)); pArrayElem->SetAttribute("type", apField->mType); pArrayElem->SetAttribute("name", apField->msName.c_str()); pArrayElem->SetAttribute("size", (int)apField->mlArraySize); // CLASS //////////////////////////////////////////// if (apField->mType == eSerializeType_Class) { cSerializeSavedClass *pClass = GetClass(((iSerializable *)pArrayData)->Serialize_GetTopClass()); size_t lClassSize = pClass->mlSize; for (size_t i = 0; i < apField->mlArraySize; i++) { size_t lOffset = lClassSize * i; SaveToElement((iSerializable *)ValuePointer(pArrayData, lOffset), "", pArrayElem); } } // CLASS POINTER ///////////////////////////////////// else if (apField->mType == eSerializeType_ClassPointer) { iSerializable **pClassDataPtr = (iSerializable **)pArrayData; if (*pClassDataPtr == NULL) { Warning("Array %s is NULL!\n", apField->msName.c_str()); return; } pArrayElem->SetAttribute("class_type", (*pClassDataPtr)->Serialize_GetTopClass().c_str()); for (size_t i = 0; i < apField->mlArraySize; i++) { size_t lOffset = sizeof(void *) * i; iSerializable **pValue = (iSerializable **)ValuePointer(pArrayData, lOffset); SaveToElement(*pValue, "", pArrayElem, true); } } // VARIABLE ///////////////////////////////////////// else { for (size_t i = 0; i < apField->mlArraySize; i++) { size_t lOffset = SizeOfType(apField->mType) * i; TiXmlElement XmlClassElem("var"); TiXmlElement *pVarElem = static_cast(pArrayElem->InsertEndChild(XmlClassElem)); pVarElem->SetAttribute("val", ValueToString(pArrayData, lOffset, apField->mType).c_str()); } } } //----------------------------------------------------------------------- void cSerializeClass::SaveContainer(TiXmlElement *apElement, cSerializeMemberField *apField, iSerializable *apData) { iContainer *pCont = (iContainer *)ValuePointer(apData, apField->mlOffset); iContainerIterator *pContIt = pCont->CreateIteratorPtr(); TiXmlElement XmlArrayElem("container"); TiXmlElement *pArrayElem = static_cast(apElement->InsertEndChild(XmlArrayElem)); pArrayElem->SetAttribute("type", apField->mType); pArrayElem->SetAttribute("name", apField->msName.c_str()); // CLASS //////////////////////////////////////////// if (apField->mType == eSerializeType_Class) { pArrayElem->SetAttribute("class_type", apField->msClassName.c_str()); while (pContIt->HasNext()) { iSerializable *pData = (iSerializable *)pContIt->NextPtr(); SaveToElement(pData, "", pArrayElem); } } // CLASS POINTER ///////////////////////////////////// else if (apField->mType == eSerializeType_ClassPointer) { while (pContIt->HasNext()) { iSerializable **pData = (iSerializable **)pContIt->NextPtr(); SaveToElement(*pData, "", pArrayElem, true); } } // VARIABLE ///////////////////////////////////////// else { while (pContIt->HasNext()) { TiXmlElement XmlClassElem("var"); TiXmlElement *pVarElem = static_cast(pArrayElem->InsertEndChild(XmlClassElem)); void *pData = const_cast(pContIt->NextPtr()); pVarElem->SetAttribute("val", ValueToString(pData, 0, apField->mType).c_str()); } } hplDelete(pContIt); } //----------------------------------------------------------------------- void cSerializeClass::LoadVariable(TiXmlElement *apElement, iSerializable *apData, cSerializeSavedClass *apClass) { tString sName = cString::ToString(apElement->Attribute("name"), ""); const char *sVal = apElement->Attribute("val"); eSerializeType type = cString::ToInt(apElement->Attribute("type"), eSerializeMainType_NULL); if (gbLog) Log("%s Saving variable: %s val: %s type: %d\n", GetTabs(), sName.c_str(), sVal, (int)type); cSerializeMemberField *pField = GetMemberField(sName, apClass); if (pField == NULL) return; StringToValue(apData, pField->mlOffset, type, sVal); } //----------------------------------------------------------------------- void cSerializeClass::LoadArray(TiXmlElement *apElement, iSerializable *apData, cSerializeSavedClass *apClass) { tString sName = cString::ToString(apElement->Attribute("name"), ""); tString sClassType = cString::ToString(apElement->Attribute("class_type"), ""); eSerializeType type = cString::ToInt(apElement->Attribute("type"), eSerializeMainType_NULL); // size_t lSize = cString::ToInt(apElement->Attribute("size"), 0); if (gbLog) { Log("%s Begin Saving array: '%s' classtype: %s type %d\n", GetTabs(), sName.c_str(), sClassType.c_str(), type); ++glTabs; } cSerializeMemberField *pField = GetMemberField(sName, apClass); if (pField == NULL) return; void *pArrayData = ValuePointer(apData, pField->mlOffset); // CLASS //////////////////////////////////////////// if (pField->mType == eSerializeType_Class) { cSerializeSavedClass *pClass = GetClass(((iSerializable *)pArrayData)->Serialize_GetTopClass()); size_t lClassSize = pClass->mlSize; size_t lCount = 0; TiXmlElement *pVarElem = apElement->FirstChildElement(); for (; pVarElem != NULL; pVarElem = pVarElem->NextSiblingElement(), ++lCount) { size_t lOffset = lCount * lClassSize; LoadFromElement((iSerializable *)ValuePointer(pArrayData, lOffset), pVarElem); } } // CLASS POINTER //////////////////////////////////////////// else if (pField->mType == eSerializeType_ClassPointer) { size_t lCount = 0; TiXmlElement *pVarElem = apElement->FirstChildElement(); for (; pVarElem != NULL; pVarElem = pVarElem->NextSiblingElement(), ++lCount) { size_t lOffset = sizeof(void *) * lCount; iSerializable **pValuePtr = (iSerializable **)ValuePointer(pArrayData, lOffset); tString sClassType2 = cString::ToString(pVarElem->Attribute("type"), ""); cSerializeSavedClass *pSavedClass = GetClass(sClassType2); if (pSavedClass == NULL) continue; if (gbLog) Log("%s Element Class pointer: %s\n", GetTabs(), sClassType2.c_str()); // If NULL, then just create else delete and then create- // virtual pointers here...yes yes... if (*pValuePtr == NULL) { *pValuePtr = pSavedClass->mpCreateFunc(); } else { hplDelete(*pValuePtr); *pValuePtr = pSavedClass->mpCreateFunc(); } LoadFromElement(*pValuePtr, pVarElem); } } // VARIABLE ///////////////////////////////////////// else { size_t lCount = 0; TiXmlElement *pVarElem = apElement->FirstChildElement(); for (; pVarElem != NULL; pVarElem = pVarElem->NextSiblingElement(), ++lCount) { const char *sVal = pVarElem->Attribute("val"); if (gbLog) Log("%s Element variable val '%s'\n", GetTabs(), sVal); StringToValue(pArrayData, lCount * SizeOfType(type), type, sVal); } } if (gbLog) { --glTabs; Log("%s End Saving array: %s\n", GetTabs(), sName.c_str()); } } //----------------------------------------------------------------------- void cSerializeClass::LoadClass(TiXmlElement *apElement, iSerializable *apData, cSerializeSavedClass *apClass) { tString sName = cString::ToString(apElement->Attribute("name"), ""); cSerializeMemberField *pField = GetMemberField(sName, apClass); if (pField == NULL) return; iSerializable *pClassData = (iSerializable *)ValuePointer(apData, pField->mlOffset); if (gbLog) Log("%s Saving class name: '%s' top class: '%s'\n", GetTabs(), sName.c_str(), pClassData->Serialize_GetTopClass().c_str()); LoadFromElement(pClassData, apElement); } //----------------------------------------------------------------------- void cSerializeClass::LoadClassPointer(TiXmlElement *apElement, iSerializable *apData, cSerializeSavedClass *apClass) { tString sName = cString::ToString(apElement->Attribute("name"), ""); tString sType = cString::ToString(apElement->Attribute("type"), ""); bool bNull = cString::ToBool(apElement->Attribute("null"), false); cSerializeMemberField *pField = GetMemberField(sName, apClass); if (pField == NULL) return; iSerializable **pClassDataPtr = (iSerializable **)ValuePointer(apData, pField->mlOffset); if (gbLog) Log("%s Saving classpointer name: '%s' type: '%s' null: %d\n", GetTabs(), sName.c_str(), sType.c_str(), bNull ? 1 : 0); // TODO: Question is here if previous data should be deleted. if (bNull) { *pClassDataPtr = NULL; return; } // If it is NULL create new, else assume it is already created. if (*pClassDataPtr == NULL) { cSerializeSavedClass *pNewClass = GetClass(sType); *pClassDataPtr = pNewClass->mpCreateFunc(); } LoadFromElement(*pClassDataPtr, apElement); } //----------------------------------------------------------------------- void cSerializeClass::LoadContainer(TiXmlElement *apElement, iSerializable *apData, cSerializeSavedClass *apClass) { tString sName = cString::ToString(apElement->Attribute("name"), ""); eSerializeType type = cString::ToInt(apElement->Attribute("type"), eSerializeMainType_NULL); cSerializeMemberField *pField = GetMemberField(sName, apClass); if (pField == NULL) return; iContainer *pCont = (iContainer *)ValuePointer(apData, pField->mlOffset); if (gbLog) { Log("%s Begin save container name: '%s' type %d\n", GetTabs(), sName.c_str(), type); ++glTabs; } // CLASS //////////////////////////////////////////// if (pField->mType == eSerializeType_Class) { tString sClassType = cString::ToString(apElement->Attribute("class_type"), ""); pCont->Clear(); cSerializeSavedClass *pSavedClass = GetClass(sClassType); if (pSavedClass == NULL) return; TiXmlElement *pVarElem = apElement->FirstChildElement(); for (; pVarElem != NULL; pVarElem = pVarElem->NextSiblingElement()) { if (gbLog) Log("%sCreating element class %s\n", GetTabs(), sClassType.c_str()); iSerializable *pData = pSavedClass->mpCreateFunc(); LoadFromElement(pData, pVarElem); pCont->AddVoidClass(pData); hplDelete(pData); } } // CLASS POINTER //////////////////////////////////////////// else if (pField->mType == eSerializeType_ClassPointer) { // This should really be smart pointers. // Delete all and clear if (gbLog) Log("%sClearing container and deleting elements\n", GetTabs()); iContainerIterator *pContIt = pCont->CreateIteratorPtr(); while (pContIt->HasNext()) { iSerializable *pContData = (iSerializable *)pContIt->NextPtr(); hplDelete(pContData); } hplDelete(pContIt); pCont->Clear(); TiXmlElement *pVarElem = apElement->FirstChildElement(); for (; pVarElem != NULL; pVarElem = pVarElem->NextSiblingElement()) { tString sClassType = cString::ToString(pVarElem->Attribute("type"), ""); cSerializeSavedClass *pSavedClass = GetClass(sClassType); if (pSavedClass == NULL) continue; if (gbLog) Log("%s Container member class pointer '%s'\n", GetTabs(), sClassType.c_str()); iSerializable *pData = pSavedClass->mpCreateFunc(); LoadFromElement(pData, pVarElem, true); pCont->AddVoidPtr((void **)&pData); } } // VARIABLE ///////////////////////////////////////// else { pCont->Clear(); TiXmlElement *pVarElem = apElement->FirstChildElement(); for (; pVarElem != NULL; pVarElem = pVarElem->NextSiblingElement()) { const char *sVal = pVarElem->Attribute("val"); void *pData = hplMalloc(SizeOfType(type)); if (gbLog) Log("%s Element var val '%s' type: %d\n", GetTabs(), sVal, type); StringToValue(pData, 0, type, sVal); pCont->AddVoidClass(pData); hplFree(pData); } } if (gbLog) { --glTabs; Log("%s End save container name: '%s'\n", GetTabs(), sName.c_str()); } } //----------------------------------------------------------------------- cSerializeMemberField *cSerializeClass::GetMemberField(const tString &asName, cSerializeSavedClass *apClass) { cSerializeMemberFieldIterator classIt = cSerializeMemberFieldIterator(apClass); while (classIt.HasNext()) { cSerializeMemberField *pField = classIt.GetNext(); if (asName == pField->msName.c_str()) return pField; } Warning("Couldn't find member field '%s' in class '%s'\n", asName.c_str(), apClass->msName); return NULL; } //----------------------------------------------------------------------- size_t cSerializeClass::SizeOfType(eSerializeType aType) { switch (aType) { case eSerializeType_Bool: return sizeof(bool); case eSerializeType_Int32: return sizeof(int); case eSerializeType_Float32: return sizeof(float); case eSerializeType_String: return sizeof(tString); case eSerializeType_Vector2l: return sizeof(cVector2l); case eSerializeType_Vector2f: return sizeof(cVector2f); case eSerializeType_Vector3l: return sizeof(cVector3l); case eSerializeType_Vector3f: return sizeof(cVector3f); case eSerializeType_Matrixf: return sizeof(cMatrixf); case eSerializeType_Color: return sizeof(cColor); case eSerializeType_Rect2l: return sizeof(cRect2l); case eSerializeType_Rect2f: return sizeof(cRect2f); case eSerializeType_Planef: return sizeof(cPlanef); case eSerializeType_WString: return sizeof(tWString); } return 0; } //----------------------------------------------------------------------- void cSerializeClass::SetUpData() { if (mbDataSetup) return; mbDataSetup = true; for (int i = 0; i < Hpl1::nSerializeTempClasses; i++) { m_mapSavedClasses->insert(tSerializeSavedClassMap::value_type( Hpl1::serializeTempClasses[i].msName, Hpl1::serializeTempClasses[i])); } } //----------------------------------------------------------------------- void cSerializeClass::FillSaveClassMembersList(tSerializeSavedClassList *apList, cSerializeSavedClass *apClass) { if (apClass == NULL) return; apList->push_back(apClass); FillSaveClassMembersList(apList, GetClass(apClass->msParentName)); } //----------------------------------------------------------------------- } // namespace hpl