Files
scummvm-cursorfix/engines/hpl1/engine/system/SerializeClass.cpp
2026-02-02 04:50:13 +01:00

1065 lines
32 KiB
C++

/* 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 <http://www.gnu.org/licenses/>.
*
*/
/*
* 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<TiXmlElement *>(pXmlDoc.InsertEndChild(XmlRoot));
Common::ScopedPtr<Common::OutSaveFile> 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<TiXmlElement *>(apParent->InsertEndChild(XmlClassElem));
} else {
TiXmlElement XmlClassElem("class");
pClassElem = static_cast<TiXmlElement *>(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<Common::InSaveFile> 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<TiXmlElement *>(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<TiXmlElement *>(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<TiXmlElement *>(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<TiXmlElement *>(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<TiXmlElement *>(pArrayElem->InsertEndChild(XmlClassElem));
void *pData = const_cast<void *>(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