Legacy code cleanup - part 3 (#3903)
* Legacy cleanup - part 3 Not much is left that can be easily removed, so I think this will be last cleanup before the legacy functionality is replaced. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * fix windows build, remove a few more things, re-add one file Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Remove legacy RenderBus + more cleanups Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Remove MaterialOwnerBus.h Clean-up in Cry_Matrix34/33 Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>
This commit is contained in:
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_XML_READWRITEXMLSINK_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_XML_READWRITEXMLSINK_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <ISystem.h>
|
||||
#include <IReadWriteXMLSink.h>
|
||||
|
||||
class CReadWriteXMLSink
|
||||
: public IReadWriteXMLSink
|
||||
{
|
||||
public:
|
||||
bool ReadXML(const char* definitionFile, const char* dataFile, IReadXMLSink* pSink);
|
||||
bool ReadXML(const char* definitionFile, XmlNodeRef node, IReadXMLSink* pSink);
|
||||
bool ReadXML(XmlNodeRef definition, const char* dataFile, IReadXMLSink* pSink);
|
||||
bool ReadXML(XmlNodeRef definition, XmlNodeRef node, IReadXMLSink* pSink);
|
||||
|
||||
XmlNodeRef CreateXMLFromSource(const char* definitionFile, IWriteXMLSource* pSource);
|
||||
bool WriteXML(const char* definitionFile, const char* dataFile, IWriteXMLSource* pSource);
|
||||
};
|
||||
|
||||
|
||||
// helper to define the if/else chain that we need in a few locations...
|
||||
// types must match IReadXMLSink::TValueTypes
|
||||
#define XML_SET_PROPERTY_HELPER(ELSE_LOAD_PROPERTY) \
|
||||
if (false) {; } \
|
||||
ELSE_LOAD_PROPERTY(Vec3); \
|
||||
ELSE_LOAD_PROPERTY(int); \
|
||||
ELSE_LOAD_PROPERTY(float); \
|
||||
ELSE_LOAD_PROPERTY(AZStd::string); \
|
||||
ELSE_LOAD_PROPERTY(bool);
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_XML_READWRITEXMLSINK_H
|
||||
@@ -1,683 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include "ReadWriteXMLSink.h"
|
||||
|
||||
#include <ISystem.h>
|
||||
#include <stack>
|
||||
|
||||
typedef std::map<AZStd::string, XmlNodeRef> IdTable;
|
||||
struct SParseParams
|
||||
{
|
||||
IdTable idTable;
|
||||
XmlNodeRef useAlways;
|
||||
bool strict;
|
||||
|
||||
SParseParams()
|
||||
{
|
||||
strict = true;
|
||||
}
|
||||
};
|
||||
|
||||
static XmlNodeRef Clone(XmlNodeRef source);
|
||||
static void CopyAttributes(const XmlNodeRef& source, XmlNodeRef& dest);
|
||||
static bool IsOptionalReadXML(const SParseParams& parseParams, XmlNodeRef& definition);
|
||||
static bool CheckEnum(const SParseParams& parseParams, const char* name, XmlNodeRef& definition, XmlNodeRef& data);
|
||||
|
||||
static bool LoadTableInner(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink);
|
||||
static bool LoadArray(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink);
|
||||
static bool LoadProperty(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink);
|
||||
static bool LoadTable(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink);
|
||||
static bool LoadReferencedId(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink);
|
||||
static bool LoadSomething(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink);
|
||||
static bool LoadArraySetValueTable(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink, int elem);
|
||||
|
||||
typedef bool (* LoadArraySetValue)(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink, int elem);
|
||||
typedef bool (* LoadDefinitionFunction)(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink);
|
||||
|
||||
|
||||
template <class T>
|
||||
struct ReadPropertyTyped;
|
||||
|
||||
template <class T>
|
||||
struct ReadPropertyTyped
|
||||
{
|
||||
static bool Load(const SParseParams& parseParams, const char* name, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink)
|
||||
{
|
||||
T value;
|
||||
memset(&value, 0, sizeof(T));
|
||||
|
||||
if (!pSink->IsCreationMode())
|
||||
{
|
||||
if (!data->haveAttr(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!data->getAttr(name, value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!CheckEnum(parseParams, name, definition, data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
IReadXMLSink::TValue vvalue(value);
|
||||
pSink->SetValue(name, vvalue, definition);
|
||||
return true;
|
||||
}
|
||||
static bool LoadArray([[maybe_unused]] const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink, int elem)
|
||||
{
|
||||
T value;
|
||||
memset(&value, 0, sizeof(T));
|
||||
|
||||
if (!pSink->IsCreationMode())
|
||||
{
|
||||
if (!data->haveAttr("value"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!data->getAttr("value", value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
IReadXMLSink::TValue vvalue(value);
|
||||
pSink->SetAt(elem, vvalue, definition);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ReadPropertyTyped<AZStd::string>
|
||||
{
|
||||
static bool Load(const SParseParams& parseParams, const char* name, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink)
|
||||
{
|
||||
const char* value = 0;
|
||||
|
||||
if (!pSink->IsCreationMode())
|
||||
{
|
||||
if (!data->haveAttr(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!CheckEnum(parseParams, name, definition, data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
value = data->getAttr(name);
|
||||
}
|
||||
|
||||
IReadXMLSink::TValue vvalue(value);
|
||||
pSink->SetValue(name, vvalue, definition);
|
||||
return true;
|
||||
}
|
||||
static bool LoadArray([[maybe_unused]] const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink, int elem)
|
||||
{
|
||||
const char* value = 0;
|
||||
|
||||
if (!pSink->IsCreationMode())
|
||||
{
|
||||
if (!data->haveAttr("value"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
value = data->getAttr("value");
|
||||
}
|
||||
|
||||
IReadXMLSink::TValue vvalue(value);
|
||||
pSink->SetAt(elem, vvalue, definition);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
XmlNodeRef Clone(XmlNodeRef source)
|
||||
{
|
||||
assert(source != (IXmlNode*)NULL);
|
||||
|
||||
// Can't use clone() on XmlNodeRef objects since they can contain a CXMLBinaryNode, which doesn't support
|
||||
// clone(). Instead we just create a regular xml node and manually copy content, tag, attributes and children
|
||||
XmlNodeRef cloned = GetISystem()->CreateXmlNode(source->getTag());
|
||||
cloned->setContent(source->getContent());
|
||||
CopyAttributes(source, cloned);
|
||||
const int iChildCount = source->getChildCount();
|
||||
for (int i = 0; i < iChildCount; ++i)
|
||||
{
|
||||
cloned->addChild(Clone(source->getChild(i)));
|
||||
}
|
||||
|
||||
return cloned;
|
||||
}
|
||||
|
||||
void CopyAttributes(const XmlNodeRef& source, XmlNodeRef& dest)
|
||||
{
|
||||
// Not as fast as CXmlNode::copyAttributes(), but that method will have undefined behavior if the XmlNodeRef contains
|
||||
// a CBinaryXmlNode object
|
||||
int nNumAttributes = source->getNumAttributes();
|
||||
for (int i = 0; i < nNumAttributes; ++i)
|
||||
{
|
||||
const char* key = NULL;
|
||||
const char* value = NULL;
|
||||
if (source->getAttributeByIndex(i, &key, &value))
|
||||
{
|
||||
dest->setAttr(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsOptionalReadXML(const SParseParams& parseParams, XmlNodeRef& definition)
|
||||
{
|
||||
// If strict mode is off, then everything is optional
|
||||
if (parseParams.strict == false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool optional = false;
|
||||
definition->getAttr("optional", optional);
|
||||
return optional;
|
||||
}
|
||||
|
||||
bool CheckEnum([[maybe_unused]] const SParseParams& parseParams, [[maybe_unused]] const char* name, XmlNodeRef& definition, [[maybe_unused]] XmlNodeRef& data)
|
||||
{
|
||||
if (XmlNodeRef enumNode = definition->findChild("Enum"))
|
||||
{
|
||||
// If strict mode is off, then no need to check the enum value
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadProperty(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink)
|
||||
{
|
||||
const char* name = definition->getAttr("name");
|
||||
if (0 == strlen(name))
|
||||
{
|
||||
CryLog("Property has no name");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* type = definition->getAttr("type");
|
||||
if (0 == strlen(type))
|
||||
{
|
||||
CryLog("Property '%s' has no type", type);
|
||||
return false;
|
||||
}
|
||||
|
||||
XmlNodeRef dataToRead = data;
|
||||
if (!pSink->IsCreationMode())
|
||||
{
|
||||
// This check is done so the data xml can specify child elements instead of attributes if desired,
|
||||
// since the rest of the code assume only attributes
|
||||
if (XmlNodeRef childRef = data->findChild(name))
|
||||
{
|
||||
if (data->haveAttr(name))
|
||||
{
|
||||
CryLog("Duplicate definition (attribute and element) for %s", name);
|
||||
return false;
|
||||
}
|
||||
if (childRef->getChildCount())
|
||||
{
|
||||
CryLog("Property-style elements can not have children (property was %s)", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
dataToRead = GetISystem()->CreateXmlNode(data->getTag());
|
||||
|
||||
AZStd::string content = childRef->getContent();
|
||||
AZ::StringFunc::TrimWhiteSpace(content, true, true);
|
||||
dataToRead->setAttr(name, content.c_str());
|
||||
}
|
||||
|
||||
if (!dataToRead->haveAttr(name))
|
||||
{
|
||||
if (!IsOptionalReadXML(parseParams, definition))
|
||||
{
|
||||
CryLog("Failed to load property %s", name);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
#define LOAD_PROPERTY(whichType) else if (0 == strcmp(type, #whichType)) ok = ReadPropertyTyped<whichType>::Load(parseParams, name, definition, dataToRead, pSink)
|
||||
XML_SET_PROPERTY_HELPER(LOAD_PROPERTY);
|
||||
#undef LOAD_PROPERTY
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
CryLog("Failed loading attribute %s of type %s", name, type);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool LoadArraySetValueTable(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink, int elem)
|
||||
{
|
||||
IReadXMLSinkPtr pChildSink = pSink->BeginTableAt(elem, definition);
|
||||
|
||||
if (pSink->IsCreationMode() && definition->haveAttr("type"))
|
||||
{
|
||||
if (!LoadSomething(parseParams, definition, data, &*pChildSink))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!LoadTableInner(parseParams, definition, data, &*pChildSink))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pChildSink->EndTableAt(elem))
|
||||
{
|
||||
CryLog("Failed to finish table at element %d", elem);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadArray(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink)
|
||||
{
|
||||
const char* name = definition->getAttr("name");
|
||||
if (0 == strlen(name))
|
||||
{
|
||||
CryLog("Array has no name");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* elementName = definition->getAttr("elementName");
|
||||
if (0 == strlen(elementName))
|
||||
{
|
||||
elementName = "element";
|
||||
}
|
||||
|
||||
bool validateArray = true;
|
||||
if (definition->haveAttr(elementName))
|
||||
{
|
||||
definition->getAttr("validate", validateArray);
|
||||
}
|
||||
|
||||
|
||||
XmlNodeRef childData;
|
||||
|
||||
if (!pSink->IsCreationMode())
|
||||
{
|
||||
childData = data->findChild(name);
|
||||
if (!childData)
|
||||
{
|
||||
bool ok = IsOptionalReadXML(parseParams, definition);
|
||||
if (!ok)
|
||||
{
|
||||
CryLog("Failed to load child table %s", name);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
|
||||
IReadXMLSinkPtr childSink = pSink->BeginArray(name, definition);
|
||||
if (!childSink)
|
||||
{
|
||||
CryLog("Failed to begin array named %s", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
LoadArraySetValue setter = NULL;
|
||||
if (definition->haveAttr("type"))
|
||||
{
|
||||
setter = NULL;
|
||||
const char* type = definition->getAttr("type");
|
||||
#define SETTER_PROPERTY(whichType) else if (0 == strcmp(type, #whichType)) setter = ReadPropertyTyped<whichType>::LoadArray
|
||||
XML_SET_PROPERTY_HELPER(SETTER_PROPERTY);
|
||||
#undef SETTER_PROPERTY
|
||||
if (!setter)
|
||||
{
|
||||
CryLog("Unknown type %s in array %s", type, name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setter = LoadArraySetValueTable;
|
||||
}
|
||||
|
||||
if (!pSink->IsCreationMode())
|
||||
{
|
||||
int numElems = childData->getChildCount();
|
||||
int elem = 1;
|
||||
for (int i = 0; i < numElems; i++)
|
||||
{
|
||||
XmlNodeRef elemData = childData->getChild(i);
|
||||
if (0 == strcmp(elemData->getTag(), elementName))
|
||||
{
|
||||
int increment = 1;
|
||||
if (elemData->haveAttr("_index"))
|
||||
{
|
||||
if (!elemData->getAttr("_index", elem))
|
||||
{
|
||||
CryLog("_index is not an integer in array %s (pos hint=%d)", name, elem);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!setter(parseParams, definition, elemData, &*childSink, elem))
|
||||
{
|
||||
CryLog("Failed loading element %d of array %s", elem, name);
|
||||
return false;
|
||||
}
|
||||
elem += increment;
|
||||
}
|
||||
else if (validateArray)
|
||||
{
|
||||
CryLog("Invalid node %s in array %s", elemData->getTag(), name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// only process array content for the array being created
|
||||
if (0 == strcmp(name, pSink->GetCreationNode()->getAttr("name")))
|
||||
{
|
||||
if (!setter(parseParams, definition, data, &*childSink, 1))
|
||||
{
|
||||
CryLog("[ReadXML CreationMode]: Failed loading element %d of array %s", 1, name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pSink->EndArray(name))
|
||||
{
|
||||
CryLog("Failed to finish array named %s", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadTable(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink)
|
||||
{
|
||||
const char* name = definition->getAttr("name");
|
||||
if (0 == strlen(name))
|
||||
{
|
||||
CryLog("Child-table has no name");
|
||||
return false;
|
||||
}
|
||||
|
||||
XmlNodeRef childData;
|
||||
|
||||
if (!pSink->IsCreationMode())
|
||||
{
|
||||
childData = data->findChild(name);
|
||||
if (!childData)
|
||||
{
|
||||
bool ok = IsOptionalReadXML(parseParams, definition);
|
||||
if (!ok)
|
||||
{
|
||||
CryLog("Failed to load child table %s", name);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
|
||||
IReadXMLSinkPtr childSink = pSink->BeginTable(name, definition);
|
||||
if (!childSink)
|
||||
{
|
||||
CryLog("Sink creation failed for table %s", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (!LoadTableInner(parseParams, definition, childData, childSink))
|
||||
{
|
||||
CryLog("Failed to load data for child table %s", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pSink->EndTable(name))
|
||||
{
|
||||
CryLog("Table %s failed to complete in sink", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadSomething(const SParseParams& parseParams, XmlNodeRef& nodeDefinition, XmlNodeRef& data, IReadXMLSink* pSink)
|
||||
{
|
||||
// Ignore if it's the useAlways array
|
||||
if (parseParams.useAlways == nodeDefinition)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct
|
||||
{
|
||||
const char* name;
|
||||
LoadDefinitionFunction loader;
|
||||
} loaderTypes[] = {
|
||||
{"Property", &LoadProperty},
|
||||
{"Array", &LoadArray},
|
||||
{"Table", &LoadTable},
|
||||
{"Use", &LoadReferencedId},
|
||||
};
|
||||
static const int numLoaderTypes = sizeof(loaderTypes) / sizeof(*loaderTypes);
|
||||
|
||||
const char* nodeDefinitionTag = nodeDefinition->getTag();
|
||||
bool ok = false;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < numLoaderTypes; i++)
|
||||
{
|
||||
if (0 == strcmp(loaderTypes[i].name, nodeDefinitionTag))
|
||||
{
|
||||
ok = loaderTypes[i].loader(parseParams, nodeDefinition, data, pSink);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == _stricmp("Settings", nodeDefinitionTag))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
if (i == numLoaderTypes)
|
||||
{
|
||||
CryLog("Invalid definition node type %s, line %d", nodeDefinitionTag, nodeDefinition->getLine());
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool LoadReferencedId(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink)
|
||||
{
|
||||
IdTable::const_iterator iter = parseParams.idTable.find(definition->getAttr("id"));
|
||||
if (iter == parseParams.idTable.end())
|
||||
{
|
||||
CryLog("No definition with id '%s'", definition->getAttr("id"));
|
||||
return false;
|
||||
}
|
||||
XmlNodeRef useDefinition = Clone(iter->second);
|
||||
CopyAttributes(definition, useDefinition);
|
||||
|
||||
return LoadSomething(parseParams, useDefinition, data, pSink);
|
||||
}
|
||||
|
||||
bool LoadTableInner(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink)
|
||||
{
|
||||
const int nChildrenDefinition = definition->getChildCount();
|
||||
|
||||
for (int nChildDefinition = 0; nChildDefinition < nChildrenDefinition; nChildDefinition++)
|
||||
{
|
||||
XmlNodeRef nodeDefinition = definition->getChild(nChildDefinition);
|
||||
|
||||
if (!LoadSomething(parseParams, nodeDefinition, data, pSink))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (parseParams.useAlways != (IXmlNode*)NULL)
|
||||
{
|
||||
assert(!definition->haveAttr("type"));
|
||||
|
||||
const int nUseAlwaysDefCount = parseParams.useAlways->getChildCount();
|
||||
for (int i = 0; i < nUseAlwaysDefCount; ++i)
|
||||
{
|
||||
XmlNodeRef nodeDefinition = parseParams.useAlways->getChild(i);
|
||||
|
||||
// Don't continue loading useAlways nodes in creation mode
|
||||
if (!pSink->IsCreationMode())
|
||||
{
|
||||
if (!LoadSomething(parseParams, nodeDefinition, data, pSink))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CReadWriteXMLSink::ReadXML(XmlNodeRef rootDefinition, XmlNodeRef rootData, IReadXMLSink* pSink)
|
||||
{
|
||||
if (!pSink->IsCreationMode())
|
||||
{
|
||||
if (0 == rootData)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 != strcmp(rootDefinition->getTag(), "Definition"))
|
||||
{
|
||||
CryLog("Root tag of definition file was %s; expected Definition", rootDefinition->getTag());
|
||||
return false;
|
||||
}
|
||||
if (rootDefinition->haveAttr("root"))
|
||||
{
|
||||
if (0 != strcmp(rootDefinition->getAttr("root"), rootData->getTag()))
|
||||
{
|
||||
CryLog("Root data has wrong tag; was %s expected %s", rootData->getTag(), rootDefinition->getAttr("root"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SParseParams parseParams;
|
||||
parseParams.useAlways = rootDefinition->findChild("AllowAlways");
|
||||
|
||||
if (XmlNodeRef settingsParams = rootDefinition->findChild("Settings"))
|
||||
{
|
||||
settingsParams->getAttr("strict", parseParams.strict);
|
||||
}
|
||||
|
||||
// scan for id's in the structure (for the Use member)
|
||||
std::stack<XmlNodeRef> scanStack;
|
||||
scanStack.push(rootDefinition);
|
||||
while (!scanStack.empty())
|
||||
{
|
||||
XmlNodeRef refNode = scanStack.top();
|
||||
scanStack.pop();
|
||||
|
||||
int numChildren = refNode->getChildCount();
|
||||
const char* tag = refNode->getTag();
|
||||
|
||||
for (int i = 0; i < numChildren; i++)
|
||||
{
|
||||
const XmlNodeRef& childNodeRef = refNode->getChild(i);
|
||||
if (parseParams.useAlways != childNodeRef)
|
||||
{
|
||||
scanStack.push(childNodeRef);
|
||||
}
|
||||
}
|
||||
|
||||
// If the element has an attribute id="" and is not a "<Use>" element add it to the idTable map
|
||||
if (refNode->haveAttr("id") && 0 != strcmp("Use", tag))
|
||||
{
|
||||
parseParams.idTable[refNode->getAttr("id")] = refNode;
|
||||
}
|
||||
}
|
||||
|
||||
if (pSink->IsCreationMode() && rootDefinition->haveAttr("type"))
|
||||
{
|
||||
// if creating from a 0-child definition node, load itself
|
||||
if (!LoadSomething(parseParams, rootDefinition, rootData, pSink))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// load content
|
||||
if (!LoadTableInner(parseParams, rootDefinition, rootData, pSink))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ok = pSink->Complete();
|
||||
if (!ok)
|
||||
{
|
||||
CryLog("Warning: sink failed to complete reading");
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool CReadWriteXMLSink::ReadXML(XmlNodeRef definition, const char* dataFile, IReadXMLSink* pSink)
|
||||
{
|
||||
XmlNodeRef rootData = GetISystem()->LoadXmlFromFile(dataFile);
|
||||
if (!rootData)
|
||||
{
|
||||
CryLog("Unable to load XML-Lua data file: %s", dataFile);
|
||||
return false;
|
||||
}
|
||||
return ReadXML(definition, rootData, pSink);
|
||||
}
|
||||
|
||||
bool CReadWriteXMLSink::ReadXML(const char* definitionFile, XmlNodeRef rootData, IReadXMLSink* pSink)
|
||||
{
|
||||
XmlNodeRef rootDefinition = GetISystem()->LoadXmlFromFile(definitionFile);
|
||||
if (!rootDefinition)
|
||||
{
|
||||
CryLog("Unable to load XML-Lua definition file: %s", definitionFile);
|
||||
return false;
|
||||
}
|
||||
return ReadXML(rootDefinition, rootData, pSink);
|
||||
}
|
||||
|
||||
bool CReadWriteXMLSink::ReadXML(const char* definitionFile, const char* dataFile, IReadXMLSink* pSink)
|
||||
{
|
||||
XmlNodeRef rootData = GetISystem()->LoadXmlFromFile(dataFile);
|
||||
if (!rootData)
|
||||
{
|
||||
CryLog("Unable to load XML-Lua data file: %s", dataFile);
|
||||
return false;
|
||||
}
|
||||
if (!ReadXML(definitionFile, rootData, pSink))
|
||||
{
|
||||
CryLog("Unable to load file %s", dataFile);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -104,23 +104,6 @@ bool CSerializeXMLReaderImpl::Value(const char* name, CTimeValue& value)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSerializeXMLReaderImpl::Value(const char* name, XmlNodeRef& value)
|
||||
{
|
||||
DefaultValue(value); // Set input value to default.
|
||||
if (m_nErrors)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (BeginOptionalGroup(name, true))
|
||||
{
|
||||
value = CurNode()->getChild(0);
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSerializeXMLReaderImpl::BeginGroup(const char* szName)
|
||||
{
|
||||
if (m_nErrors)
|
||||
@@ -173,32 +156,3 @@ void CSerializeXMLReaderImpl::EndGroup()
|
||||
}
|
||||
assert(!m_nodeStack.empty());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
AZStd::string CSerializeXMLReaderImpl::GetStackInfo() const
|
||||
{
|
||||
AZStd::string str;
|
||||
for (int i = 0; i < (int)m_nodeStack.size(); i++)
|
||||
{
|
||||
const char* name = m_nodeStack[i].m_node->getAttr(TAG_SCRIPT_NAME);
|
||||
if (name && name[0])
|
||||
{
|
||||
str += name;
|
||||
}
|
||||
else
|
||||
{
|
||||
str += m_nodeStack[i].m_node->getTag();
|
||||
}
|
||||
if (i != m_nodeStack.size() - 1)
|
||||
{
|
||||
str += "/";
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
void CSerializeXMLReaderImpl::GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->Add(*this);
|
||||
pSizer->AddContainer(m_nodeStack);
|
||||
}
|
||||
|
||||
@@ -6,22 +6,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_XML_SERIALIZEXMLREADER_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_XML_SERIALIZEXMLREADER_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "SimpleSerialize.h"
|
||||
#include <stack>
|
||||
#include <IXml.h>
|
||||
#include <ITimer.h>
|
||||
#include <IValidator.h>
|
||||
#include <ISystem.h>
|
||||
#include "xml.h"
|
||||
|
||||
class CSerializeXMLReaderImpl
|
||||
: public CSimpleSerializeImpl<true, eST_SaveGame>
|
||||
: public CSimpleSerializeImpl<true, ESerializationTarget::eST_SaveGame>
|
||||
{
|
||||
public:
|
||||
CSerializeXMLReaderImpl(const XmlNodeRef& nodeRef);
|
||||
@@ -41,7 +35,7 @@ public:
|
||||
g_pXmlStrCmp = &strcmp; // Do case-sensitive compare
|
||||
bool bReturn = node->haveAttr(name);
|
||||
if (bReturn)
|
||||
{
|
||||
{
|
||||
value = node->getAttr(name);
|
||||
}
|
||||
g_pXmlStrCmp = pPrevCmpFunc;
|
||||
@@ -51,10 +45,6 @@ public:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ILINE bool GetAttr([[maybe_unused]] const XmlNodeRef& node, [[maybe_unused]] const char* name, [[maybe_unused]] SNetObjectID& value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T_Value>
|
||||
bool Value(const char* name, T_Value& value)
|
||||
@@ -77,23 +67,12 @@ public:
|
||||
bool Value(const char* name, int8& value);
|
||||
bool Value(const char* name, AZStd::string& value);
|
||||
bool Value(const char* name, CTimeValue& value);
|
||||
bool Value(const char* name, XmlNodeRef& value);
|
||||
|
||||
template <class T_Value, class T_Policy>
|
||||
bool Value(const char* name, T_Value& value, [[maybe_unused]] const T_Policy& policy)
|
||||
{
|
||||
return Value(name, value);
|
||||
}
|
||||
|
||||
void BeginGroup(const char* szName);
|
||||
bool BeginOptionalGroup(const char* szName, bool condition);
|
||||
void EndGroup();
|
||||
AZStd::string GetStackInfo() const;
|
||||
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const;
|
||||
|
||||
private:
|
||||
//CTimeValue m_curTime;
|
||||
XmlNodeRef CurNode() { return m_nodeStack.back().m_node; }
|
||||
XmlNodeRef NextOf(const char* name)
|
||||
{
|
||||
@@ -171,13 +150,9 @@ private:
|
||||
void DefaultValue(Ang3& v) const { v.x = 0; v.y = 0; v.z = 0; }
|
||||
void DefaultValue(Quat& v) const { v.w = 1.0f; v.v.x = 0; v.v.y = 0; v.v.z = 0; }
|
||||
void DefaultValue(CTimeValue& v) const { v.SetValue(0); }
|
||||
//void DefaultValue( char *str ) const { if (str) str[0] = 0; }
|
||||
void DefaultValue(AZStd::string& str) const { str = ""; }
|
||||
void DefaultValue([[maybe_unused]] const AZStd::string& str) const {}
|
||||
void DefaultValue([[maybe_unused]] SNetObjectID& id) const {}
|
||||
void DefaultValue([[maybe_unused]] SSerializeString& str) const {}
|
||||
void DefaultValue(XmlNodeRef& ref) const { ref = NULL; }
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_XML_SERIALIZEXMLREADER_H
|
||||
|
||||
@@ -49,16 +49,6 @@ bool CSerializeXMLWriterImpl::Value(const char* name, CTimeValue value)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSerializeXMLWriterImpl::Value(const char* name, XmlNodeRef& value)
|
||||
{
|
||||
if (BeginOptionalGroup(name, value != NULL))
|
||||
{
|
||||
CurNode()->addChild(value);
|
||||
EndGroup();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSerializeXMLWriterImpl::BeginGroup(const char* szName)
|
||||
{
|
||||
if (strchr(szName, ' ') != 0)
|
||||
@@ -104,13 +94,6 @@ void CSerializeXMLWriterImpl::EndGroup()
|
||||
assert(!m_nodeStack.empty());
|
||||
}
|
||||
|
||||
void CSerializeXMLWriterImpl::GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->Add(*this);
|
||||
pSizer->AddObject(m_nodeStack);
|
||||
pSizer->AddContainer(m_luaSaveStack);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
AZStd::string CSerializeXMLWriterImpl::GetStackInfo() const
|
||||
{
|
||||
|
||||
@@ -15,11 +15,10 @@
|
||||
#include <ISystem.h>
|
||||
#include <ITimer.h>
|
||||
#include <IXml.h>
|
||||
#include "IValidator.h"
|
||||
#include "SimpleSerialize.h"
|
||||
|
||||
class CSerializeXMLWriterImpl
|
||||
: public CSimpleSerializeImpl<false, eST_SaveGame>
|
||||
: public CSimpleSerializeImpl<false, ESerializationTarget::eST_SaveGame>
|
||||
{
|
||||
public:
|
||||
CSerializeXMLWriterImpl(const XmlNodeRef& nodeRef);
|
||||
@@ -32,21 +31,12 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T_Value, class T_Policy>
|
||||
bool Value(const char* name, T_Value& value, [[maybe_unused]] const T_Policy& policy)
|
||||
{
|
||||
return Value(name, value);
|
||||
}
|
||||
|
||||
bool Value(const char* name, CTimeValue value);
|
||||
bool Value(const char* name, XmlNodeRef& value);
|
||||
|
||||
void BeginGroup(const char* szName);
|
||||
bool BeginOptionalGroup(const char* szName, bool condition);
|
||||
void EndGroup();
|
||||
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const;
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Vars.
|
||||
@@ -99,10 +89,6 @@ private:
|
||||
{
|
||||
AddValue(name, value.c_str());
|
||||
}
|
||||
void AddValue([[maybe_unused]] const char* name, [[maybe_unused]] const SNetObjectID& value)
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
template <class T>
|
||||
void AddTypedValue(const char* name, const T& value, const char* type)
|
||||
{
|
||||
|
||||
@@ -1,432 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include "ReadWriteXMLSink.h"
|
||||
|
||||
#include <stack>
|
||||
|
||||
typedef std::map<AZStd::string, XmlNodeRef> IdTable;
|
||||
|
||||
static bool IsOptionalWriteXML(XmlNodeRef& definition);
|
||||
|
||||
static bool SaveTableInner(const IdTable&, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource);
|
||||
static bool SaveReferencedId(const IdTable&, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource);
|
||||
static bool SaveSomething(const IdTable&, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource);
|
||||
static bool SaveArray(const IdTable&, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource);
|
||||
static bool SaveProperty(const IdTable&, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource);
|
||||
static bool SaveTable(const IdTable&, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource);
|
||||
static bool SaveArraySetValueTable(const IdTable&, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource, int elem);
|
||||
|
||||
typedef bool (* SaveArraySetValue)(const IdTable&, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource, int elem);
|
||||
typedef bool (* SaveDefinitionFunction)(const IdTable&, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource);
|
||||
|
||||
template <class T>
|
||||
struct WritePropertyTyped;
|
||||
|
||||
template <class T>
|
||||
struct WritePropertyTyped
|
||||
{
|
||||
static bool Save(const char* name, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource)
|
||||
{
|
||||
IWriteXMLSource::TValue vvalue((T()));
|
||||
if (!pSource->GetValue(name, vvalue, definition))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
T* pValue = AZStd::get_if<T>(&vvalue);
|
||||
if (!pValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
data->setAttr(name, *pValue);
|
||||
return true;
|
||||
}
|
||||
static bool SaveArray([[maybe_unused]] const IdTable& idTable, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource, int elem)
|
||||
{
|
||||
IWriteXMLSource::TValue vvalue((T()));
|
||||
if (!pSource->GetAt(elem, vvalue, definition))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
T* pValue = AZStd::get_if<T>(&vvalue);
|
||||
if (!pValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
data->setAttr("value", *pValue);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct WritePropertyTyped<AZStd::string>
|
||||
: public WritePropertyTyped<const char*>
|
||||
{
|
||||
};
|
||||
|
||||
bool IsOptionalWriteXML(XmlNodeRef& definition)
|
||||
{
|
||||
bool optional = false;
|
||||
definition->getAttr("optional", optional);
|
||||
return optional;
|
||||
}
|
||||
|
||||
bool SaveProperty([[maybe_unused]] const IdTable& idTable, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource)
|
||||
{
|
||||
const char* name = definition->getAttr("name");
|
||||
if (0 == strlen(name))
|
||||
{
|
||||
CryLog("Property has no name");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* type = definition->getAttr("type");
|
||||
if (0 == strlen(type))
|
||||
{
|
||||
CryLog("Property '%s' has no type", type);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsOptionalWriteXML(definition) && !pSource->HaveValue(name))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
#define SAVE_PROPERTY(whichType) else if (0 == strcmp(type, #whichType)) ok = WritePropertyTyped<whichType>::Save(name, definition, data, pSource)
|
||||
XML_SET_PROPERTY_HELPER(SAVE_PROPERTY);
|
||||
#undef SAVE_PROPERTY
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
CryLog("Failed loading attribute %s of type %s", name, type);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool SaveArraySetValueTable(const IdTable& idTable, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource, int elem)
|
||||
{
|
||||
IWriteXMLSourcePtr pChildSource = pSource->BeginTableAt(elem);
|
||||
if (!pChildSource)
|
||||
{
|
||||
CryLog("Failed to find source table at %d", elem);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SaveTableInner(idTable, definition, data, &*pChildSource))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pChildSource->EndTableAt(elem))
|
||||
{
|
||||
CryLog("Failed to finish table at element %d", elem);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveArray(const IdTable& idTable, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource)
|
||||
{
|
||||
const char* name = definition->getAttr("name");
|
||||
if (0 == strlen(name))
|
||||
{
|
||||
CryLog("Array has no name");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* elementName = definition->getAttr("elementName");
|
||||
if (0 == strlen(elementName))
|
||||
{
|
||||
elementName = "element";
|
||||
}
|
||||
|
||||
bool validateArray = true;
|
||||
if (definition->haveAttr(elementName))
|
||||
{
|
||||
definition->getAttr("validate", validateArray);
|
||||
}
|
||||
|
||||
size_t numElems = 0;
|
||||
IWriteXMLSourcePtr childSource = pSource->BeginArray(name, &numElems, definition);
|
||||
if (!childSource)
|
||||
{
|
||||
bool ok = IsOptionalWriteXML(definition);
|
||||
if (!ok)
|
||||
{
|
||||
CryLog("Failed to begin array named %s", name);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
XmlNodeRef childData = data->createNode(name);
|
||||
|
||||
SaveArraySetValue setter = NULL;
|
||||
if (definition->haveAttr("type"))
|
||||
{
|
||||
setter = NULL;
|
||||
const char* type = definition->getAttr("type");
|
||||
#define SETTER_PROPERTY(whichType) else if (0 == strcmp(type, #whichType)) setter = WritePropertyTyped<whichType>::SaveArray
|
||||
XML_SET_PROPERTY_HELPER(SETTER_PROPERTY);
|
||||
#undef SETTER_PROPERTY
|
||||
if (!setter)
|
||||
{
|
||||
CryLog("Unknown type %s in array %s", type, name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setter = SaveArraySetValueTable;
|
||||
}
|
||||
|
||||
bool needIndex = false;
|
||||
for (size_t sizei = 1; sizei <= numElems; sizei++)
|
||||
{
|
||||
const int i = static_cast<int>(sizei);
|
||||
if (!childSource->HaveElemAt(i))
|
||||
{
|
||||
needIndex = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
XmlNodeRef elemData = childData->createNode(elementName);
|
||||
if (needIndex)
|
||||
{
|
||||
elemData->setAttr("_index", i);
|
||||
}
|
||||
needIndex = false;
|
||||
|
||||
if (!setter(idTable, definition, elemData, &*childSource, i))
|
||||
{
|
||||
CryLog("Failed saving element %d of array %s", int(i), name);
|
||||
return false;
|
||||
}
|
||||
|
||||
childData->addChild(elemData);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pSource->EndArray(name))
|
||||
{
|
||||
CryLog("Failed to finish array named %s", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
data->addChild(childData);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveTable(const IdTable& idTable, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource)
|
||||
{
|
||||
const char* name = definition->getAttr("name");
|
||||
if (0 == strlen(name))
|
||||
{
|
||||
CryLog("Child-table has no name");
|
||||
return false;
|
||||
}
|
||||
|
||||
IWriteXMLSourcePtr childSource = pSource->BeginTable(name);
|
||||
if (!childSource)
|
||||
{
|
||||
bool ok = IsOptionalWriteXML(definition);
|
||||
if (!ok)
|
||||
{
|
||||
CryLog("Source creation failed for table %s", name);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
XmlNodeRef childData = data->createNode(name);
|
||||
|
||||
if (!SaveTableInner(idTable, definition, childData, childSource))
|
||||
{
|
||||
CryLog("Failed to load data for child table %s", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pSource->EndTable(name))
|
||||
{
|
||||
CryLog("Table %s failed to complete in sink", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
data->addChild(childData);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveSomething(const IdTable& idTable, XmlNodeRef& nodeDefinition, XmlNodeRef& data, IWriteXMLSource* pSource)
|
||||
{
|
||||
static struct
|
||||
{
|
||||
const char* name;
|
||||
SaveDefinitionFunction saver;
|
||||
} saverTypes[] = {
|
||||
{"Property", &SaveProperty},
|
||||
{"Array", &SaveArray},
|
||||
{"Table", &SaveTable},
|
||||
{"Use", &SaveReferencedId},
|
||||
};
|
||||
static const int numSaverTypes = sizeof(saverTypes) / sizeof(*saverTypes);
|
||||
|
||||
const char* nodeDefinitionTag = nodeDefinition->getTag();
|
||||
bool ok = false;
|
||||
int i;
|
||||
for (i = 0; i < numSaverTypes; i++)
|
||||
{
|
||||
if (0 == strcmp(saverTypes[i].name, nodeDefinitionTag))
|
||||
{
|
||||
ok = saverTypes[i].saver(idTable, nodeDefinition, data, pSource);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
if (i == numSaverTypes)
|
||||
{
|
||||
CryLog("Invalid definition node type %s", nodeDefinitionTag);
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool SaveReferencedId(const IdTable& idTable, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource)
|
||||
{
|
||||
IdTable::const_iterator iter = idTable.find(definition->getAttr("id"));
|
||||
if (iter == idTable.end())
|
||||
{
|
||||
CryLog("No definition with id '%s'", definition->getAttr("id"));
|
||||
return false;
|
||||
}
|
||||
XmlNodeRef useDefinition = iter->second;
|
||||
useDefinition = useDefinition->clone();
|
||||
int numAttrs = definition->getNumAttributes();
|
||||
for (int i = 0; i < numAttrs; i++)
|
||||
{
|
||||
const char* key, * value;
|
||||
definition->getAttributeByIndex(i, &key, &value);
|
||||
useDefinition->setAttr(key, value);
|
||||
}
|
||||
return SaveSomething(idTable, useDefinition, data, pSource);
|
||||
}
|
||||
|
||||
bool SaveTableInner(const IdTable& idTable, XmlNodeRef& definition, XmlNodeRef& data, IWriteXMLSource* pSource)
|
||||
{
|
||||
const int nChildrenDefinition = definition->getChildCount();
|
||||
for (int nChildDefinition = 0; nChildDefinition < nChildrenDefinition; nChildDefinition++)
|
||||
{
|
||||
XmlNodeRef nodeDefinition = definition->getChild(nChildDefinition);
|
||||
|
||||
if (!SaveSomething(idTable, nodeDefinition, data, pSource))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
XmlNodeRef CReadWriteXMLSink::CreateXMLFromSource(const char* definitionFile, IWriteXMLSource* pSource)
|
||||
{
|
||||
XmlNodeRef rootDefinition = GetISystem()->LoadXmlFromFile(definitionFile);
|
||||
if (!rootDefinition)
|
||||
{
|
||||
CryLog("Unable to load XML-Lua definition file: %s", definitionFile);
|
||||
return 0;
|
||||
}
|
||||
if (0 != strcmp(rootDefinition->getTag(), "Definition"))
|
||||
{
|
||||
CryLog("Root tag of definition file was %s; expected Definition", rootDefinition->getTag());
|
||||
return 0;
|
||||
}
|
||||
const char* rootNode = "Root";
|
||||
if (rootDefinition->haveAttr("root"))
|
||||
{
|
||||
rootNode = rootDefinition->getAttr("root");
|
||||
}
|
||||
XmlNodeRef rootData = GetISystem()->CreateXmlNode(rootNode);
|
||||
|
||||
XmlNodeRef allowAlways = rootDefinition->findChild("AllowAlways");
|
||||
if (allowAlways != 0)
|
||||
{
|
||||
rootDefinition->removeChild(allowAlways);
|
||||
}
|
||||
|
||||
XmlNodeRef settingsParams = rootDefinition->findChild("Settings");
|
||||
if (settingsParams != 0)
|
||||
{
|
||||
rootDefinition->removeChild(settingsParams);
|
||||
}
|
||||
|
||||
// scan for id's in the structure (for the Use member)
|
||||
IdTable idTable;
|
||||
std::stack<XmlNodeRef> scanStack;
|
||||
scanStack.push(rootDefinition);
|
||||
while (!scanStack.empty())
|
||||
{
|
||||
XmlNodeRef refNode = scanStack.top();
|
||||
scanStack.pop();
|
||||
|
||||
int numChildren = refNode->getChildCount();
|
||||
const char* tag = refNode->getTag();
|
||||
|
||||
for (int i = 0; i < numChildren; i++)
|
||||
{
|
||||
scanStack.push(refNode->getChild(i));
|
||||
}
|
||||
|
||||
if (refNode->haveAttr("id") && 0 != strcmp("Use", tag))
|
||||
{
|
||||
idTable[refNode->getAttr("id")] = refNode;
|
||||
}
|
||||
|
||||
if (allowAlways != 0 && (!strcmp("Table", tag) || !strcmp("Array", tag)))
|
||||
{
|
||||
for (int i = 0; i < allowAlways->getChildCount(); ++i)
|
||||
{
|
||||
refNode->addChild(allowAlways->getChild(i)->clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!SaveTableInner(idTable, rootDefinition, rootData, pSource))
|
||||
{
|
||||
CryLog("Error createing xml using definition %s", definitionFile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ok = pSource->Complete();
|
||||
if (!ok)
|
||||
{
|
||||
CryLog("Warning: sink failed to complete writing");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return rootData;
|
||||
}
|
||||
|
||||
bool CReadWriteXMLSink::WriteXML(const char* definitionFile, const char* dataFile, IWriteXMLSource* pSource)
|
||||
{
|
||||
XmlNodeRef data = CreateXMLFromSource(definitionFile, pSource);
|
||||
if (!data)
|
||||
{
|
||||
CryLog("Failed creating %s", dataFile);
|
||||
return false;
|
||||
}
|
||||
if (!data->saveToFile(dataFile))
|
||||
{
|
||||
CryLog("Failed saving %s", dataFile);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
|
||||
#include <platform.h>
|
||||
#include "Cry_Color.h"
|
||||
#include "XMLBinaryNode.h"
|
||||
#include <CrySizer.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CBinaryXmlData::CBinaryXmlData()
|
||||
@@ -38,24 +38,10 @@ CBinaryXmlData::~CBinaryXmlData()
|
||||
pBinaryNodes = 0;
|
||||
}
|
||||
|
||||
void CBinaryXmlData::GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(pFileContents, nFileSize);
|
||||
const XMLBinary::BinaryFileHeader* pHeader = reinterpret_cast<const XMLBinary::BinaryFileHeader*>(pFileContents);
|
||||
pSizer->AddObject(pBinaryNodes, sizeof(CBinaryXmlNode) * pHeader->nNodeCount);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CBinaryXmlNode implementation.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// collect allocated memory informations
|
||||
void CBinaryXmlNode::GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(m_pData);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
XmlNodeRef CBinaryXmlNode::getParent() const
|
||||
{
|
||||
@@ -244,21 +230,6 @@ bool CBinaryXmlNode::getAttr(const char* key, Vec4& value) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBinaryXmlNode::getAttr(const char* key, Vec3d& value) const
|
||||
{
|
||||
const char* svalue = GetValue(key);
|
||||
if (svalue)
|
||||
{
|
||||
double x, y, z;
|
||||
if (azsscanf(svalue, "%lf,%lf,%lf", &x, &y, &z) == 3)
|
||||
{
|
||||
value = Vec3d(x, y, z);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CBinaryXmlNode::getAttr(const char* key, Vec2& value) const
|
||||
{
|
||||
@@ -275,22 +246,6 @@ bool CBinaryXmlNode::getAttr(const char* key, Vec2& value) const
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CBinaryXmlNode::getAttr(const char* key, Vec2d& value) const
|
||||
{
|
||||
const char* svalue = GetValue(key);
|
||||
if (svalue)
|
||||
{
|
||||
double x, y;
|
||||
if (azsscanf(svalue, "%lf,%lf", &x, &y) == 2)
|
||||
{
|
||||
value = Vec2d(x, y);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CBinaryXmlNode::getAttr(const char* key, Quat& value) const
|
||||
{
|
||||
|
||||
@@ -41,8 +41,6 @@ public:
|
||||
|
||||
CBinaryXmlData();
|
||||
~CBinaryXmlData();
|
||||
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const;
|
||||
};
|
||||
|
||||
// forward declaration
|
||||
@@ -59,9 +57,6 @@ class CBinaryXmlNode
|
||||
{
|
||||
public:
|
||||
|
||||
// collect allocated memory informations
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Custom new/delete with pool allocator.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -163,11 +158,9 @@ public:
|
||||
void setAttr([[maybe_unused]] const char* key, [[maybe_unused]] float value) { assert(0); };
|
||||
void setAttr([[maybe_unused]] const char* key, [[maybe_unused]] f64 value) { assert(0); };
|
||||
void setAttr([[maybe_unused]] const char* key, [[maybe_unused]] const Vec2& value) { assert(0); };
|
||||
void setAttr([[maybe_unused]] const char* key, [[maybe_unused]] const Vec2d& value) { assert(0); };
|
||||
void setAttr([[maybe_unused]] const char* key, [[maybe_unused]] const Ang3& value) { assert(0); };
|
||||
void setAttr([[maybe_unused]] const char* key, [[maybe_unused]] const Vec3& value) { assert(0); };
|
||||
void setAttr([[maybe_unused]] const char* key, [[maybe_unused]] const Vec4& value) { assert(0); };
|
||||
void setAttr([[maybe_unused]] const char* key, [[maybe_unused]] const Vec3d& value) { assert(0); };
|
||||
void setAttr([[maybe_unused]] const char* key, [[maybe_unused]] const Quat& value) { assert(0); };
|
||||
void delAttr([[maybe_unused]] const char* key) { assert(0); };
|
||||
void removeAllAttributes() { assert(0); };
|
||||
@@ -182,11 +175,9 @@ public:
|
||||
bool getAttr(const char* key, bool& value) const;
|
||||
bool getAttr(const char* key, XmlString& value) const {const char* v(NULL); bool boHasAttribute(getAttr(key, &v)); value = v; return boHasAttribute; }
|
||||
bool getAttr(const char* key, Vec2& value) const;
|
||||
bool getAttr(const char* key, Vec2d& value) const;
|
||||
bool getAttr(const char* key, Ang3& value) const;
|
||||
bool getAttr(const char* key, Vec3& value) const;
|
||||
bool getAttr(const char* key, Vec4& value) const;
|
||||
bool getAttr(const char* key, Vec3d& value) const;
|
||||
bool getAttr(const char* key, Quat& value) const;
|
||||
bool getAttr(const char* key, ColorB& value) const;
|
||||
|
||||
|
||||
@@ -12,40 +12,6 @@
|
||||
#include "CryEndian.h"
|
||||
#include <string.h> // memcpy()
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
namespace XMLBinary
|
||||
{
|
||||
void SwapEndianness_Node(Node& t)
|
||||
{
|
||||
SwapEndian(t.nTagStringOffset, true);
|
||||
SwapEndian(t.nContentStringOffset, true);
|
||||
SwapEndian(t.nAttributeCount, true);
|
||||
SwapEndian(t.nChildCount, true);
|
||||
SwapEndian(t.nParentIndex, true);
|
||||
SwapEndian(t.nFirstAttributeIndex, true);
|
||||
SwapEndian(t.nFirstChildIndex, true);
|
||||
}
|
||||
|
||||
void SwapEndianness_Attribute(Attribute& t)
|
||||
{
|
||||
SwapEndian(t.nKeyStringOffset, true);
|
||||
SwapEndian(t.nValueStringOffset, true);
|
||||
}
|
||||
|
||||
void SwapEndianness_Header(BinaryFileHeader& t)
|
||||
{
|
||||
SwapEndian(t.nXMLSize, true);
|
||||
SwapEndian(t.nNodeTablePosition, true);
|
||||
SwapEndian(t.nNodeCount, true);
|
||||
SwapEndian(t.nAttributeTablePosition, true);
|
||||
SwapEndian(t.nAttributeCount, true);
|
||||
SwapEndian(t.nChildTablePosition, true);
|
||||
SwapEndian(t.nChildCount, true);
|
||||
SwapEndian(t.nStringDataPosition, true);
|
||||
SwapEndian(t.nStringDataSize, true);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
XMLBinary::CXMLBinaryWriter::CXMLBinaryWriter()
|
||||
{
|
||||
@@ -84,7 +50,7 @@ static void write(XMLBinary::IDataWriter* const pFile, size_t& nPosition, const
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool XMLBinary::CXMLBinaryWriter::WriteNode(IDataWriter* pFile, XmlNodeRef node, bool bNeedSwapEndian, XMLBinary::IFilter* pFilter, AZStd::string& error)
|
||||
bool XMLBinary::CXMLBinaryWriter::WriteNode(IDataWriter* pFile, XmlNodeRef node, XMLBinary::IFilter* pFilter, AZStd::string& error)
|
||||
{
|
||||
error = "";
|
||||
|
||||
@@ -135,24 +101,6 @@ bool XMLBinary::CXMLBinaryWriter::WriteNode(IDataWriter* pFile, XmlNodeRef node,
|
||||
|
||||
header.nXMLSize = static_cast<uint32>(nTheoreticalPosition);
|
||||
|
||||
// Swap endianness of the data structures
|
||||
if (bNeedSwapEndian)
|
||||
{
|
||||
SwapEndianness_Header(header);
|
||||
for (size_t i = 0, iCount = m_nodes.size(); i < iCount; ++i)
|
||||
{
|
||||
SwapEndianness_Node(m_nodes[i]);
|
||||
}
|
||||
for (size_t i = 0, iCount = m_attributes.size(); i < iCount; ++i)
|
||||
{
|
||||
SwapEndianness_Attribute(m_attributes[i]);
|
||||
}
|
||||
for (size_t i = 0, iCount = m_childs.size(); i < iCount; ++i)
|
||||
{
|
||||
SwapEndian(m_childs[i], true);
|
||||
}
|
||||
}
|
||||
|
||||
// Write file
|
||||
{
|
||||
nTheoreticalPosition = 0;
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace XMLBinary
|
||||
{
|
||||
public:
|
||||
CXMLBinaryWriter();
|
||||
bool WriteNode(IDataWriter* pFile, XmlNodeRef node, bool bNeedSwapEndian, XMLBinary::IFilter* pFilter, AZStd::string & error);
|
||||
bool WriteNode(IDataWriter* pFile, XmlNodeRef node, XMLBinary::IFilter* pFilter, AZStd::string & error);
|
||||
|
||||
private:
|
||||
bool CompileTables(XmlNodeRef node, XMLBinary::IFilter* pFilter, AZStd::string& error);
|
||||
|
||||
@@ -1,423 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include "XMLPatcher.h"
|
||||
|
||||
CXMLPatcher::CXMLPatcher(XmlNodeRef& patchXML)
|
||||
{
|
||||
m_patchXML = patchXML;
|
||||
|
||||
#if DATA_PATCH_DEBUG
|
||||
m_pDumpFilesCVar = REGISTER_INT("g_datapatcher_dumpfiles", 0, NULL, "will dump a copy of every file data patched, before and after patching");
|
||||
#endif
|
||||
}
|
||||
|
||||
CXMLPatcher::~CXMLPatcher()
|
||||
{
|
||||
#if DATA_PATCH_DEBUG
|
||||
if (IConsole* pIC = gEnv->pConsole)
|
||||
{
|
||||
pIC->UnregisterVariable(m_pDumpFilesCVar->GetName());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
XmlNodeRef CXMLPatcher::DuplicateForPatching(
|
||||
const XmlNodeRef& inOrig,
|
||||
bool inShareChildren)
|
||||
{
|
||||
XmlNodeRef newNode(0);
|
||||
|
||||
if (m_patchXML)
|
||||
{
|
||||
newNode = m_patchXML->createNode(inOrig->getTag());
|
||||
if (newNode)
|
||||
{
|
||||
// copy attributes in a safe way, copyAttributes() itself assumes the node being copied from is of the same type
|
||||
int numAttr = inOrig->getNumAttributes();
|
||||
|
||||
for (int i = 0; i < numAttr; i++)
|
||||
{
|
||||
const char* pKey, * pValue;
|
||||
if (inOrig->getAttributeByIndex(i, &pKey, &pValue))
|
||||
{
|
||||
newNode->setAttr(pKey, pValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (inShareChildren)
|
||||
{
|
||||
newNode->shareChildren(inOrig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
void CXMLPatcher::PatchFail(
|
||||
const char* pInReason)
|
||||
{
|
||||
CryLogAlways("Failed to apply data patch for file '%s' - reason '%s'", m_pFileBeingPatched, pInReason);
|
||||
}
|
||||
|
||||
XmlNodeRef CXMLPatcher::FindPatchForFile(
|
||||
const char* pInFileToPatch)
|
||||
{
|
||||
XmlNodeRef result;
|
||||
|
||||
if (m_patchXML)
|
||||
{
|
||||
for (int i = 0, m = m_patchXML->getChildCount(); i < m; i++)
|
||||
{
|
||||
XmlNodeRef child = m_patchXML->getChild(i);
|
||||
|
||||
if (child->isTag("patch"))
|
||||
{
|
||||
const char* pForFile = child->getAttr("forfile");
|
||||
|
||||
if (pForFile && AZ::StringFunc::Find(pForFile, pInFileToPatch) != AZStd::string::npos)
|
||||
{
|
||||
result = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
XmlNodeRef CXMLPatcher::ApplyPatchToNode(
|
||||
const XmlNodeRef& inNode,
|
||||
const XmlNodeRef& inPatch)
|
||||
{
|
||||
XmlNodeRef result = inNode;
|
||||
|
||||
for (int i = 0, m = inPatch->getChildCount(); i < m; i++)
|
||||
{
|
||||
XmlNodeRef patchNode = inPatch->getChild(i);
|
||||
if (!patchNode || _stricmp(patchNode->getTag(), "patchnode") != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int indexToPatch;
|
||||
if (!patchNode->getAttr("index", indexToPatch))
|
||||
{
|
||||
PatchFail("found patchnode missing index");
|
||||
continue;
|
||||
}
|
||||
|
||||
int maxChildren = result->getChildCount();
|
||||
|
||||
if ((indexToPatch < 0 || indexToPatch >= maxChildren) && indexToPatch != -1)
|
||||
{
|
||||
PatchFail("patchnode index out of valid range");
|
||||
continue;
|
||||
}
|
||||
|
||||
XmlNodeRef childToPatch = (indexToPatch != -1) ? result->getChild(indexToPatch) : XmlNodeRef(0);
|
||||
XmlNodeRef matchTag = GetMatchTag(patchNode);
|
||||
|
||||
if (childToPatch && matchTag && !CompareTags(matchTag, childToPatch))
|
||||
{
|
||||
PatchFail("patch failed to apply, data did not match what was expected");
|
||||
continue;
|
||||
}
|
||||
|
||||
// we need to apply a patch to this child, make it patchable by duplicating the node
|
||||
|
||||
if (inNode == result)
|
||||
{
|
||||
// make parent patchable if not already
|
||||
result = DuplicateForPatching(inNode, true);
|
||||
}
|
||||
|
||||
if (XmlNodeRef insertTag = GetInsertTag(patchNode))
|
||||
{
|
||||
// insert a new child after this node
|
||||
XmlNodeRef newChild = DuplicateForPatching(insertTag, true); // have to duplicate it as we don't have an 'insert shared child' function
|
||||
result->insertChild(indexToPatch + 1, newChild);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (indexToPatch == -1)
|
||||
{
|
||||
PatchFail("child indices of -1 can only be used when inserting new nodes");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bool shouldReplaceChildren = false;
|
||||
|
||||
if (XmlNodeRef replaceTag = GetReplaceTag(patchNode, &shouldReplaceChildren))
|
||||
{
|
||||
XmlNodeRef newChild = DuplicateForPatching(replaceTag, false);
|
||||
|
||||
if (!shouldReplaceChildren)
|
||||
{
|
||||
newChild->shareChildren(childToPatch);
|
||||
}
|
||||
else
|
||||
{
|
||||
// note: this is inserting children that belong to the data patcher into the data being patched
|
||||
// this is fine to do, as long as the caller doesn't make any permanent changes to the xml tree
|
||||
// returned. if they did they would alter the patcher's nodes and thus affect future patches
|
||||
// applied using the same patch
|
||||
// as most callers are working with binary xmls they don't try and modify them - as this is not
|
||||
// a supported operation
|
||||
// note, if a second patch was applied to this patched tree containing the patch nodes, it
|
||||
// wouldn't mess up the patch, as patching a tree never modifies it, it always returns a new tree
|
||||
// that may share parts of the original tree
|
||||
newChild->shareChildren(replaceTag);
|
||||
}
|
||||
|
||||
result->replaceChild(indexToPatch, newChild);
|
||||
|
||||
childToPatch = newChild;
|
||||
}
|
||||
|
||||
if (XmlNodeRef deleteTag = GetDeleteTag(patchNode))
|
||||
{
|
||||
result->deleteChildAt(indexToPatch);
|
||||
childToPatch = 0; // deleted - don't recurse into it
|
||||
}
|
||||
|
||||
if (childToPatch)
|
||||
{
|
||||
// Apply recursively
|
||||
XmlNodeRef newChild = ApplyPatchToNode(childToPatch, patchNode);
|
||||
|
||||
// child has been patched, insert new child into parent
|
||||
if (newChild != childToPatch)
|
||||
{
|
||||
result->replaceChild(indexToPatch, newChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
XmlNodeRef CXMLPatcher::ApplyXMLDataPatch(
|
||||
const XmlNodeRef& inNode,
|
||||
const char* pInXMLFileName)
|
||||
{
|
||||
XmlNodeRef result = inNode;
|
||||
|
||||
if (m_patchingEnabled)
|
||||
{
|
||||
if (m_patchXML)
|
||||
{
|
||||
XmlNodeRef patchForFile = FindPatchForFile(pInXMLFileName);
|
||||
if (patchForFile)
|
||||
{
|
||||
m_pFileBeingPatched = pInXMLFileName;
|
||||
CryLog("Applying game data patch to %s", pInXMLFileName);
|
||||
XmlNodeRef containerNode = m_patchXML->createNode("");
|
||||
containerNode->addChild(inNode);
|
||||
containerNode = ApplyPatchToNode(containerNode, patchForFile);
|
||||
result = containerNode->getChild(0);
|
||||
m_pFileBeingPatched = NULL;
|
||||
|
||||
#if DATA_PATCH_DEBUG
|
||||
if (inNode != result)
|
||||
{
|
||||
DumpFiles(pInXMLFileName, inNode, result);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
XmlNodeRef CXMLPatcher::GetMatchTag(
|
||||
const XmlNodeRef& inNode)
|
||||
{
|
||||
XmlNodeRef result;
|
||||
XmlNodeRef nr = inNode->findChild("match");
|
||||
if (nr && nr->getChildCount() == 1)
|
||||
{
|
||||
result = nr->getChild(0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
XmlNodeRef CXMLPatcher::GetReplaceTag(
|
||||
const XmlNodeRef& inNode,
|
||||
bool* outShouldReplaceChildren)
|
||||
{
|
||||
XmlNodeRef result;
|
||||
XmlNodeRef nr = inNode->findChild("replacewith");
|
||||
if (nr && nr->getChildCount() == 1)
|
||||
{
|
||||
if (!nr->getAttr("replaceChildren", *outShouldReplaceChildren))
|
||||
{
|
||||
*outShouldReplaceChildren = false;
|
||||
}
|
||||
result = nr->getChild(0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
XmlNodeRef CXMLPatcher::GetInsertTag(
|
||||
const XmlNodeRef& inNode)
|
||||
{
|
||||
XmlNodeRef result;
|
||||
XmlNodeRef nr = inNode->findChild("insertAfter");
|
||||
if (nr && nr->getChildCount() == 1)
|
||||
{
|
||||
result = nr->getChild(0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
XmlNodeRef CXMLPatcher::GetDeleteTag(
|
||||
const XmlNodeRef& inNode)
|
||||
{
|
||||
XmlNodeRef result = inNode->findChild("delete");
|
||||
return result;
|
||||
}
|
||||
|
||||
// compares the two tags for equality of tag and attributes
|
||||
// used to ensure the source data being patched meets the patches expectations
|
||||
// only compares tag and attribs, doesn't do deep compare of children
|
||||
bool CXMLPatcher::CompareTags(
|
||||
const XmlNodeRef& inA,
|
||||
const XmlNodeRef& inB)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
if (inA != inB)
|
||||
{
|
||||
result = false;
|
||||
|
||||
if (_stricmp(inA->getTag(), inB->getTag()) == 0)
|
||||
{
|
||||
if (inA->getNumAttributes() == inB->getNumAttributes())
|
||||
{
|
||||
result = true;
|
||||
|
||||
for (int i = 0, m = inA->getNumAttributes(); i < m; i++)
|
||||
{
|
||||
const char* pAKey, * pBKey;
|
||||
const char* pAValue, * pBValue;
|
||||
|
||||
inA->getAttributeByIndex(i, &pAKey, &pAValue);
|
||||
inB->getAttributeByIndex(i, &pBKey, &pBValue);
|
||||
|
||||
if (_stricmp(pAKey, pBKey) || _stricmp(pAValue, pBValue))
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if DATA_PATCH_DEBUG
|
||||
|
||||
static const char* k_lotsOfTabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
|
||||
|
||||
#define INDENT() \
|
||||
if (inIndent > 0) \
|
||||
{ \
|
||||
pPak->FWrite(k_lotsOfTabs, inIndent, inFileHandle); \
|
||||
}
|
||||
|
||||
void CXMLPatcher::DumpXMLNodes(
|
||||
AZ::IO::HandleType inFileHandle,
|
||||
int inIndent,
|
||||
const XmlNodeRef& inNode,
|
||||
AZStd::fixed_string<512>* ioTempString)
|
||||
{
|
||||
auto pPak = gEnv->pCryPak;
|
||||
|
||||
inIndent = min(inIndent, int(sizeof(k_lotsOfTabs) - 1));
|
||||
|
||||
INDENT();
|
||||
|
||||
*ioTempString = AZStd::fixed_string<512>::format("<%s ", inNode->getTag());
|
||||
|
||||
pPak->FWrite(ioTempString->c_str(), ioTempString->length(), inFileHandle);
|
||||
|
||||
for (int i = 0, m = inNode->getNumAttributes(); i < m; i++)
|
||||
{
|
||||
const char* pKey, * pVal;
|
||||
inNode->getAttributeByIndex(i, &pKey, &pVal);
|
||||
*ioTempString = AZStd::fixed_string<512>::format("%s=\"%s\" ", pKey, pVal);
|
||||
pPak->FWrite(ioTempString->c_str(), ioTempString->length(), inFileHandle);
|
||||
}
|
||||
pPak->FWrite(">\n", 2, inFileHandle);
|
||||
|
||||
for (int i = 0, m = inNode->getChildCount(); i < m; i++)
|
||||
{
|
||||
DumpXMLNodes(inFileHandle, inIndent + 1, inNode->getChild(i), ioTempString);
|
||||
}
|
||||
|
||||
INDENT();
|
||||
*ioTempString = AZStd::fixed_string<512>::format("</%s>\n", inNode->getTag());
|
||||
pPak->FWrite(ioTempString->c_str(), ioTempString->length(), inFileHandle);
|
||||
}
|
||||
|
||||
|
||||
void CXMLPatcher::DumpFiles(
|
||||
const char* pInXMLFileName,
|
||||
const XmlNodeRef& inBefore,
|
||||
const XmlNodeRef& inAfter)
|
||||
{
|
||||
if (m_pDumpFilesCVar->GetIVal())
|
||||
{
|
||||
CryLog("Dumping before and after data files for '%s'", pInXMLFileName);
|
||||
|
||||
const char* pOrigFileName = strrchr(pInXMLFileName, '/');
|
||||
if (pOrigFileName)
|
||||
{
|
||||
pOrigFileName++;
|
||||
|
||||
DumpXMLFile(AZStd::string::format("PATCH_%s", pOrigFileName).c_str(), inBefore);
|
||||
|
||||
AZStd::string newFileName(pOrigFileName);
|
||||
AZ::StringFunc::Replace(newFileName, ".xml", "_patched.xml");
|
||||
|
||||
DumpXMLFile(AZStd::string::format("PATCH_%s", newFileName.c_str()).c_str(), inAfter);
|
||||
}
|
||||
else
|
||||
{
|
||||
CryLog("Couldn't determine file name for path '%s' can't output diffs", pInXMLFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CXMLPatcher::DumpXMLFile(
|
||||
const char* pInFilePath,
|
||||
const XmlNodeRef& inNode)
|
||||
{
|
||||
auto pIPak = GetISystem()->GetIPak();
|
||||
AZ::IO::HandleType fileHandle = pIPak->FOpen(pInFilePath, "wb");
|
||||
|
||||
if (fileHandle != AZ::IO::InvalidHandle)
|
||||
{
|
||||
AZStd::fixed_string<512> tempStr;
|
||||
|
||||
DumpXMLNodes(fileHandle, 0, inNode, &tempStr);
|
||||
|
||||
pIPak->FClose(fileHandle);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_XML_XMLPATCHER_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_XML_XMLPATCHER_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#if defined(WIN32) && !defined(_RELEASE)
|
||||
#define DATA_PATCH_DEBUG 1
|
||||
#else
|
||||
#define DATA_PATCH_DEBUG 0
|
||||
#endif
|
||||
|
||||
class CXMLPatcher
|
||||
{
|
||||
protected:
|
||||
#if DATA_PATCH_DEBUG
|
||||
ICVar * m_pDumpFilesCVar;
|
||||
#endif
|
||||
|
||||
XmlNodeRef m_patchXML;
|
||||
const char* m_pFileBeingPatched;
|
||||
bool m_patchingEnabled;
|
||||
|
||||
void PatchFail(
|
||||
const char* pInReason);
|
||||
XmlNodeRef ApplyPatchToNode(
|
||||
const XmlNodeRef& inNode,
|
||||
const XmlNodeRef& inPatch);
|
||||
|
||||
XmlNodeRef DuplicateForPatching(
|
||||
const XmlNodeRef& inOrig,
|
||||
bool inShareChildren);
|
||||
|
||||
bool CompareTags(
|
||||
const XmlNodeRef& inA,
|
||||
const XmlNodeRef& inB);
|
||||
XmlNodeRef GetMatchTag(
|
||||
const XmlNodeRef& inNode);
|
||||
XmlNodeRef GetReplaceTag(
|
||||
const XmlNodeRef& inNode,
|
||||
bool* outShouldReplaceChildren);
|
||||
XmlNodeRef GetInsertTag(
|
||||
const XmlNodeRef& inNode);
|
||||
XmlNodeRef GetDeleteTag(
|
||||
const XmlNodeRef& inNode);
|
||||
XmlNodeRef FindPatchForFile(
|
||||
const char* pInFileToPatch);
|
||||
|
||||
#if DATA_PATCH_DEBUG
|
||||
void DumpXMLNodes(
|
||||
AZ::IO::HandleType inFileHandle,
|
||||
int inIndent,
|
||||
const XmlNodeRef& inNode,
|
||||
AZStd::fixed_string<512>* ioTempString);
|
||||
void DumpFiles(
|
||||
const char* pInXMLFileName,
|
||||
const XmlNodeRef& inBefore,
|
||||
const XmlNodeRef& inAfter);
|
||||
void DumpXMLFile(
|
||||
const char* pInFilePath,
|
||||
const XmlNodeRef& inNode);
|
||||
#endif
|
||||
|
||||
public:
|
||||
CXMLPatcher(XmlNodeRef& patchXML);
|
||||
~CXMLPatcher();
|
||||
|
||||
XmlNodeRef ApplyXMLDataPatch(
|
||||
const XmlNodeRef& inNode,
|
||||
const char* pInXMLFileName);
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_XML_XMLPATCHER_H
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <IXml.h>
|
||||
#include "xml.h"
|
||||
#include "XmlUtils.h"
|
||||
#include "ReadWriteXMLSink.h"
|
||||
|
||||
#include "../SimpleStringPool.h"
|
||||
#include "SerializeXMLReader.h"
|
||||
@@ -20,7 +19,6 @@
|
||||
#include "XMLBinaryWriter.h"
|
||||
#include "XMLBinaryReader.h"
|
||||
|
||||
#include "XMLPatcher.h"
|
||||
#include <md5.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -28,23 +26,14 @@
|
||||
SXmlNodeStats* g_pCXmlNode_Stats = 0;
|
||||
#endif
|
||||
|
||||
extern bool g_bEnableBinaryXmlLoading;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CXmlUtils::CXmlUtils(ISystem* pSystem)
|
||||
{
|
||||
m_pSystem = pSystem;
|
||||
|
||||
// create IReadWriteXMLSink object
|
||||
m_pReadWriteXMLSink = new CReadWriteXMLSink();
|
||||
#ifdef CRY_COLLECT_XML_NODE_STATS
|
||||
g_pCXmlNode_Stats = new SXmlNodeStats();
|
||||
#endif
|
||||
m_pStatsXmlNodePool = 0;
|
||||
#ifndef _RELEASE
|
||||
m_statsThreadOwner = CryGetCurrentThreadId();
|
||||
#endif
|
||||
m_pXMLPatcher = NULL;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -53,8 +42,6 @@ CXmlUtils::~CXmlUtils()
|
||||
#ifdef CRY_COLLECT_XML_NODE_STATS
|
||||
delete g_pCXmlNode_Stats;
|
||||
#endif
|
||||
SAFE_DELETE(m_pStatsXmlNodePool);
|
||||
SAFE_DELETE(m_pXMLPatcher);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -65,21 +52,13 @@ IXmlParser* CXmlUtils::CreateXmlParser()
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
XmlNodeRef CXmlUtils::LoadXmlFromFile(const char* sFilename, bool bReuseStrings, bool bEnablePatching)
|
||||
XmlNodeRef CXmlUtils::LoadXmlFromFile(const char* sFilename, bool bReuseStrings)
|
||||
{
|
||||
XmlParser parser(bReuseStrings);
|
||||
XmlNodeRef node = parser.ParseFile(sFilename, true);
|
||||
|
||||
// XmlParser is supposed to log warnings and errors (if any),
|
||||
// so we don't need to call parser.getErrorString(),
|
||||
// CryLog() etc here.
|
||||
|
||||
if (node && bEnablePatching && m_pXMLPatcher)
|
||||
{
|
||||
node = m_pXMLPatcher->ApplyXMLDataPatch(node, sFilename);
|
||||
}
|
||||
|
||||
return node;
|
||||
XmlParser parser(bReuseStrings);
|
||||
return parser.ParseFile(sFilename, true);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -99,29 +78,6 @@ void GetMD5(const char* pSrcBuffer, int nSrcSize, char signatureMD5[16])
|
||||
MD5Final((unsigned char*)signatureMD5, &md5c);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
const char* CXmlUtils::HashXml(XmlNodeRef node)
|
||||
{
|
||||
static char signature[16 * 2 + 1];
|
||||
static char temp[16];
|
||||
static const char* hex = "0123456789abcdef";
|
||||
XmlString str = node->getXML();
|
||||
GetMD5(str.data(), static_cast<int>(str.length()), temp);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
signature[2 * i + 0] = hex[((uint8)temp[i]) >> 4];
|
||||
signature[2 * i + 1] = hex[((uint8)temp[i]) & 0xf];
|
||||
}
|
||||
signature[16 * 2] = 0;
|
||||
return signature;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
IReadWriteXMLSink* CXmlUtils::GetIReadWriteXMLSink()
|
||||
{
|
||||
return m_pReadWriteXMLSink;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CXmlSerializer
|
||||
: public IXmlSerializer
|
||||
@@ -172,12 +128,6 @@ public:
|
||||
return m_pReaderSer;
|
||||
}
|
||||
|
||||
virtual void GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->Add(*this);
|
||||
pSizer->AddObject(m_pReaderImpl);
|
||||
pSizer->AddObject(m_pWriterImpl);
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
private:
|
||||
int m_nRefCount;
|
||||
@@ -194,62 +144,6 @@ IXmlSerializer* CXmlUtils::CreateXmlSerializer()
|
||||
return new CXmlSerializer;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CXmlUtils::GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer)
|
||||
{
|
||||
#ifdef CRY_COLLECT_XML_NODE_STATS
|
||||
// yes, slow
|
||||
std::vector<const CXmlNode*> rootNodes;
|
||||
{
|
||||
TXmlNodeSet::const_iterator iter = g_pCXmlNode_Stats->nodeSet.begin();
|
||||
TXmlNodeSet::const_iterator iterEnd = g_pCXmlNode_Stats->nodeSet.end();
|
||||
while (iter != iterEnd)
|
||||
{
|
||||
const CXmlNode* pNode = *iter;
|
||||
if (pNode->getParent() == 0)
|
||||
{
|
||||
rootNodes.push_back(pNode);
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
// use the following to log to console
|
||||
#if 0
|
||||
CryLogAlways("NumXMLRootNodes=%d NumXMLNodes=%d TotalAllocs=%d TotalFrees=%d",
|
||||
rootNodes.size(), g_pCXmlNode_Stats->nodeSet.size(),
|
||||
g_pCXmlNode_Stats->nAllocs, g_pCXmlNode_Stats->nFrees);
|
||||
#endif
|
||||
|
||||
|
||||
// use the following to debug the nodes in the system
|
||||
#if 0
|
||||
{
|
||||
std::vector<const CXmlNode*>::const_iterator iter = rootNodes.begin();
|
||||
std::vector<const CXmlNode*>::const_iterator iterEnd = rootNodes.end();
|
||||
while (iter != iterEnd)
|
||||
{
|
||||
const CXmlNode* pNode = *iter;
|
||||
CryLogAlways("Node 0x%p Tag='%s'", pNode, pNode->getTag());
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// only for debugging, add it as pseudo numbers to the CrySizer.
|
||||
// shift it by 10, so we get the actual number
|
||||
{
|
||||
SIZER_COMPONENT_NAME(pSizer, "#NumTotalNodes");
|
||||
pSizer->Add("#NumTotalNodes", g_pCXmlNode_Stats->nodeSet.size() << 10);
|
||||
}
|
||||
|
||||
{
|
||||
SIZER_COMPONENT_NAME(pSizer, "#NumRootNodes");
|
||||
pSizer->Add("#NumRootNodes", rootNodes.size() << 10);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CXmlBinaryDataWriterFile
|
||||
: public XMLBinary::IDataWriter
|
||||
@@ -282,49 +176,13 @@ private:
|
||||
AZ::IO::HandleType m_fileHandle;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CXmlUtils::SaveBinaryXmlFile(const char* filename, XmlNodeRef root)
|
||||
{
|
||||
CXmlBinaryDataWriterFile fileSink(filename);
|
||||
if (!fileSink.IsOk())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
XMLBinary::CXMLBinaryWriter writer;
|
||||
AZStd::string error;
|
||||
return writer.WriteNode(&fileSink, root, false, 0, error);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
XmlNodeRef CXmlUtils::LoadBinaryXmlFile(const char* filename, bool bEnablePatching)
|
||||
{
|
||||
XMLBinary::XMLBinaryReader reader;
|
||||
XMLBinary::XMLBinaryReader::EResult result;
|
||||
XmlNodeRef root = reader.LoadFromFile(filename, result);
|
||||
|
||||
if (result == XMLBinary::XMLBinaryReader::eResult_Success && bEnablePatching == true && m_pXMLPatcher != NULL)
|
||||
{
|
||||
root = m_pXMLPatcher->ApplyXMLDataPatch(root, filename);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CXmlUtils::EnableBinaryXmlLoading(bool bEnable)
|
||||
{
|
||||
bool bPrev = g_bEnableBinaryXmlLoading;
|
||||
g_bEnableBinaryXmlLoading = bEnable;
|
||||
return bPrev;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CXmlTableReader
|
||||
: public IXmlTableReader
|
||||
{
|
||||
public:
|
||||
CXmlTableReader();
|
||||
virtual ~CXmlTableReader();
|
||||
~CXmlTableReader() override;
|
||||
|
||||
virtual void Release();
|
||||
|
||||
@@ -332,7 +190,6 @@ public:
|
||||
virtual int GetEstimatedRowCount();
|
||||
virtual bool ReadRow(int& rowIndex);
|
||||
virtual bool ReadCell(int& columnIndex, const char*& pContent, size_t& contentSize);
|
||||
float GetCurrentRowHeight() override;
|
||||
|
||||
private:
|
||||
bool m_bExcel;
|
||||
@@ -341,7 +198,6 @@ private:
|
||||
|
||||
XmlNodeRef m_rowNode;
|
||||
|
||||
float m_currentRowHeight;
|
||||
int m_rowNodeIndex;
|
||||
int m_row;
|
||||
|
||||
@@ -411,7 +267,6 @@ int CXmlTableReader::GetEstimatedRowCount()
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CXmlTableReader::ReadRow(int& rowIndex)
|
||||
{
|
||||
m_currentRowHeight = 0.0f;
|
||||
if (!m_tableNode)
|
||||
{
|
||||
return false;
|
||||
@@ -459,12 +314,6 @@ bool CXmlTableReader::ReadRow(int& rowIndex)
|
||||
}
|
||||
m_row = index;
|
||||
}
|
||||
float height;
|
||||
if (m_rowNode->getAttr("ss:Height", height))
|
||||
{
|
||||
m_currentRowHeight = height;
|
||||
}
|
||||
|
||||
rowIndex = m_row;
|
||||
return true;
|
||||
}
|
||||
@@ -617,75 +466,8 @@ bool CXmlTableReader::ReadCell(int& columnIndex, const char*& pContent, size_t&
|
||||
}
|
||||
}
|
||||
|
||||
float CXmlTableReader::GetCurrentRowHeight()
|
||||
{
|
||||
return m_currentRowHeight;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
IXmlTableReader* CXmlUtils::CreateXmlTableReader()
|
||||
{
|
||||
return new CXmlTableReader;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Init xml stats nodes pool
|
||||
void CXmlUtils::InitStatsXmlNodePool(uint32 nPoolSize)
|
||||
{
|
||||
CHECK_STATS_THREAD_OWNERSHIP();
|
||||
if (0 == m_pStatsXmlNodePool)
|
||||
{
|
||||
// create special xml node pools for game statistics
|
||||
|
||||
const bool bReuseStrings = true; // TODO parameterise?
|
||||
m_pStatsXmlNodePool = new CXmlNodePool(nPoolSize, bReuseStrings);
|
||||
assert(m_pStatsXmlNodePool);
|
||||
}
|
||||
else
|
||||
{
|
||||
CryLog("[CXmlNodePool]: Xml stats nodes pool already initialized");
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Creates new xml node for statistics.
|
||||
XmlNodeRef CXmlUtils::CreateStatsXmlNode(const char* sNodeName)
|
||||
{
|
||||
CHECK_STATS_THREAD_OWNERSHIP();
|
||||
if (0 == m_pStatsXmlNodePool)
|
||||
{
|
||||
CryLog("[CXmlNodePool]: Xml stats nodes pool isn't initialized. Perform default initialization.");
|
||||
InitStatsXmlNodePool();
|
||||
}
|
||||
return m_pStatsXmlNodePool->GetXmlNode(sNodeName);
|
||||
}
|
||||
|
||||
void CXmlUtils::SetStatsOwnerThread([[maybe_unused]] threadID threadId)
|
||||
{
|
||||
#ifndef _RELEASE
|
||||
m_statsThreadOwner = threadId;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CXmlUtils::FlushStatsXmlNodePool()
|
||||
{
|
||||
CHECK_STATS_THREAD_OWNERSHIP();
|
||||
if (m_pStatsXmlNodePool)
|
||||
{
|
||||
if (m_pStatsXmlNodePool->empty())
|
||||
{
|
||||
SAFE_DELETE(m_pStatsXmlNodePool);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CXmlUtils::SetXMLPatcher(XmlNodeRef* pPatcher)
|
||||
{
|
||||
SAFE_DELETE(m_pXMLPatcher);
|
||||
|
||||
if (pPatcher != NULL)
|
||||
{
|
||||
m_pXMLPatcher = new CXMLPatcher(*pPatcher);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#endif
|
||||
|
||||
class CXmlNodePool;
|
||||
class CXMLPatcher;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Implements IXmlUtils interface.
|
||||
@@ -39,57 +38,17 @@ public:
|
||||
virtual IXmlParser* CreateXmlParser();
|
||||
|
||||
// Load xml from file, returns 0 if load failed.
|
||||
virtual XmlNodeRef LoadXmlFromFile(const char* sFilename, bool bReuseStrings = false, bool bEnablePatching = true);
|
||||
virtual XmlNodeRef LoadXmlFromFile(const char* sFilename, bool bReuseStrings = false);
|
||||
// Load xml from memory buffer, returns 0 if load failed.
|
||||
virtual XmlNodeRef LoadXmlFromBuffer(const char* buffer, size_t size, bool bReuseStrings = false, bool bSuppressWarnings = false);
|
||||
|
||||
// create an MD5 hash of an XML file
|
||||
virtual const char* HashXml(XmlNodeRef node);
|
||||
|
||||
// Get an object that can read a xml into a IReadXMLSink
|
||||
// and write a xml from a IWriteXMLSource
|
||||
virtual IReadWriteXMLSink* GetIReadWriteXMLSink();
|
||||
|
||||
virtual IXmlSerializer* CreateXmlSerializer();
|
||||
|
||||
virtual bool SaveBinaryXmlFile(const char* sFilename, XmlNodeRef root);
|
||||
virtual XmlNodeRef LoadBinaryXmlFile(const char* sFilename, bool bEnablePatching = true);
|
||||
|
||||
virtual bool EnableBinaryXmlLoading(bool bEnable);
|
||||
|
||||
// Create XML Table reader.
|
||||
virtual IXmlTableReader* CreateXmlTableReader();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual void GetMemoryUsage(ICrySizer* pSizer);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Init xml stats nodes pool
|
||||
virtual void InitStatsXmlNodePool(uint32 nPoolSize = 1024*1024);
|
||||
|
||||
// Create new xml node for statistics
|
||||
virtual XmlNodeRef CreateStatsXmlNode(const char* sNodeName = "");
|
||||
|
||||
// Set owner thread
|
||||
virtual void SetStatsOwnerThread(threadID threadId);
|
||||
|
||||
// Free memory if stats xml node pool is empty
|
||||
virtual void FlushStatsXmlNodePool();
|
||||
|
||||
// Set the XML Patcher. This is an XML object that modifies named XML files as they are loaded
|
||||
// EXCEPT for xml files loaded from a buffer, for which names aren't passed in
|
||||
virtual void SetXMLPatcher(XmlNodeRef* pPatcher);
|
||||
|
||||
private:
|
||||
ISystem* m_pSystem;
|
||||
IReadWriteXMLSink* m_pReadWriteXMLSink;
|
||||
CXmlNodePool* m_pStatsXmlNodePool;
|
||||
CXMLPatcher* m_pXMLPatcher; //If set, applies data patches to any XML file that is loaded by this class
|
||||
#ifndef _RELEASE
|
||||
threadID m_statsThreadOwner;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_XML_XMLUTILS_H
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
|
||||
//#define _CRT_SECURE_NO_DEPRECATE 1
|
||||
//#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#include <stdlib.h>
|
||||
|
||||
#define XML_STATIC // Alternative to defining this here would be setting it project-wide
|
||||
@@ -19,6 +17,7 @@
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <AzFramework/Archive/IArchive.h>
|
||||
#include <CryCommon/Cry_Color.h>
|
||||
#include "XMLBinaryReader.h"
|
||||
|
||||
#define FLOAT_FMT "%.8g"
|
||||
@@ -77,7 +76,6 @@ static int __cdecl ascii_stricmp(const char* dst, const char* src)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
XmlStrCmpFunc g_pXmlStrCmp = &ascii_stricmp;
|
||||
bool g_bEnableBinaryXmlLoading = true;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CXmlStringData
|
||||
@@ -113,10 +111,6 @@ public:
|
||||
void Clear() { m_stringPool.Clear(); }
|
||||
void SetBlockSize(unsigned int nBlockSize) { m_stringPool.SetBlockSize(nBlockSize); }
|
||||
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(m_stringPool);
|
||||
}
|
||||
private:
|
||||
CSimpleStringPool m_stringPool;
|
||||
};
|
||||
@@ -174,23 +168,6 @@ CXmlNode::CXmlNode(const char* tag, bool bReuseStrings, bool bIsProcessingInstru
|
||||
m_tag = m_pStringPool->AddString(tag);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// collect allocated memory informations
|
||||
void CXmlNode::GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(this, sizeof(*this));
|
||||
pSizer->AddObject(m_pStringPool);
|
||||
|
||||
if (m_pChilds)
|
||||
{
|
||||
pSizer->AddObject(*m_pChilds);
|
||||
}
|
||||
if (m_pAttributes)
|
||||
{
|
||||
pSizer->AddContainer(*m_pAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
XmlNodeRef CXmlNode::createNode(const char* tag)
|
||||
{
|
||||
@@ -378,13 +355,6 @@ void CXmlNode::setAttr(const char* key, const Vec4& value)
|
||||
setAttr(key, str);
|
||||
}
|
||||
|
||||
void CXmlNode::setAttr(const char* key, const Vec3d& value)
|
||||
{
|
||||
char str[128];
|
||||
SCOPED_LOCALE_RESETTER;
|
||||
sprintf_s(str, DOUBLE_FMT "," DOUBLE_FMT "," DOUBLE_FMT, value.x, value.y, value.z);
|
||||
setAttr(key, str);
|
||||
}
|
||||
void CXmlNode::setAttr(const char* key, const Vec2& value)
|
||||
{
|
||||
char str[128];
|
||||
@@ -392,13 +362,6 @@ void CXmlNode::setAttr(const char* key, const Vec2& value)
|
||||
sprintf_s(str, FLOAT_FMT "," FLOAT_FMT, value.x, value.y);
|
||||
setAttr(key, str);
|
||||
}
|
||||
void CXmlNode::setAttr(const char* key, const Vec2d& value)
|
||||
{
|
||||
char str[128];
|
||||
SCOPED_LOCALE_RESETTER;
|
||||
sprintf_s(str, DOUBLE_FMT "," DOUBLE_FMT, value.x, value.y);
|
||||
setAttr(key, str);
|
||||
}
|
||||
|
||||
void CXmlNode::setAttr(const char* key, const Quat& value)
|
||||
{
|
||||
@@ -557,22 +520,6 @@ bool CXmlNode::getAttr(const char* key, Vec4& value) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CXmlNode::getAttr(const char* key, Vec3d& value) const
|
||||
{
|
||||
const char* svalue = GetValue(key);
|
||||
if (svalue)
|
||||
{
|
||||
SCOPED_LOCALE_RESETTER;
|
||||
double x, y, z;
|
||||
if (azsscanf(svalue, "%lf,%lf,%lf", &x, &y, &z) == 3)
|
||||
{
|
||||
value = Vec3d(x, y, z);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CXmlNode::getAttr(const char* key, Vec2& value) const
|
||||
{
|
||||
@@ -590,22 +537,6 @@ bool CXmlNode::getAttr(const char* key, Vec2& value) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CXmlNode::getAttr(const char* key, Vec2d& value) const
|
||||
{
|
||||
const char* svalue = GetValue(key);
|
||||
if (svalue)
|
||||
{
|
||||
SCOPED_LOCALE_RESETTER;
|
||||
double x, y;
|
||||
if (azsscanf(svalue, "%lf,%lf", &x, &y) == 2)
|
||||
{
|
||||
value = Vec2d(x, y);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CXmlNode::getAttr(const char* key, Quat& value) const
|
||||
{
|
||||
@@ -1369,14 +1300,6 @@ public:
|
||||
|
||||
// Add new string to pool.
|
||||
const char* AddString(const char* str) { return m_stringPool.Append(str, (int)strlen(str)); }
|
||||
//char* AddString( const char *str ) { return (char*)str; }
|
||||
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(this, sizeof(*this));
|
||||
pSizer->AddObject(m_stringPool);
|
||||
pSizer->AddObject(m_nodeStack);
|
||||
}
|
||||
protected:
|
||||
void onStartElement(const char* tagName, const char** atts);
|
||||
void onEndElement(const char* tagName);
|
||||
@@ -1410,12 +1333,6 @@ protected:
|
||||
{
|
||||
XmlNodeRef node;
|
||||
std::vector<IXmlNode*> childs; //TODO: is it worth lazily initializing this, like CXmlNode::m_pChilds?
|
||||
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(node);
|
||||
pSizer->AddObject(childs);
|
||||
}
|
||||
};
|
||||
|
||||
// First node will become root node.
|
||||
@@ -1735,38 +1652,35 @@ XmlNodeRef XmlParserImp::ParseFile(const char* filename, XmlString& errorString,
|
||||
AZStd::replace(pakPath.begin(), pakPath.end(), '\\', '/');
|
||||
}
|
||||
|
||||
if (g_bEnableBinaryXmlLoading)
|
||||
XMLBinary::XMLBinaryReader reader;
|
||||
XMLBinary::XMLBinaryReader::EResult result;
|
||||
root = reader.LoadFromBuffer(XMLBinary::XMLBinaryReader::eBufferMemoryHandling_TakeOwnership, pFileContents, fileSize, result);
|
||||
if (root)
|
||||
{
|
||||
XMLBinary::XMLBinaryReader reader;
|
||||
XMLBinary::XMLBinaryReader::EResult result;
|
||||
root = reader.LoadFromBuffer(XMLBinary::XMLBinaryReader::eBufferMemoryHandling_TakeOwnership, pFileContents, fileSize, result);
|
||||
if (root)
|
||||
return root;
|
||||
}
|
||||
if (result != XMLBinary::XMLBinaryReader::eResult_NotBinXml)
|
||||
{
|
||||
delete [] pFileContents;
|
||||
sprintf_s(str, "%s%s (%s)", errorPrefix, reader.GetErrorDescription(), filename);
|
||||
errorString = str;
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "%s", str);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// not binary XML - refuse to load if in scripts dir and not in bin xml to help reduce hacking
|
||||
// wish we could compile the text xml parser out, but too much work to get everything moved over
|
||||
constexpr AZStd::fixed_string<32> strScripts{"Scripts/"};
|
||||
// exclude files and PAKs from Mods folder
|
||||
constexpr AZStd::fixed_string<8> modsStr{"Mods/"};
|
||||
if (_strnicmp(filename, strScripts.c_str(), strScripts.length()) == 0 &&
|
||||
_strnicmp(adjustedFilename.c_str(), modsStr.c_str(), modsStr.length()) != 0 &&
|
||||
_strnicmp(pakPath.c_str(), modsStr.c_str(), modsStr.length()) != 0)
|
||||
{
|
||||
return root;
|
||||
}
|
||||
if (result != XMLBinary::XMLBinaryReader::eResult_NotBinXml)
|
||||
{
|
||||
delete [] pFileContents;
|
||||
sprintf_s(str, "%s%s (%s)", errorPrefix, reader.GetErrorDescription(), filename);
|
||||
errorString = str;
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "%s", str);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// not binary XML - refuse to load if in scripts dir and not in bin xml to help reduce hacking
|
||||
// wish we could compile the text xml parser out, but too much work to get everything moved over
|
||||
constexpr AZStd::fixed_string<32> strScripts{"Scripts/"};
|
||||
// exclude files and PAKs from Mods folder
|
||||
constexpr AZStd::fixed_string<8> modsStr{"Mods/"};
|
||||
if (_strnicmp(filename, strScripts.c_str(), strScripts.length()) == 0 &&
|
||||
_strnicmp(adjustedFilename.c_str(), modsStr.c_str(), modsStr.length()) != 0 &&
|
||||
_strnicmp(pakPath.c_str(), modsStr.c_str(), modsStr.length()) != 0)
|
||||
{
|
||||
#ifdef _RELEASE
|
||||
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Non binary XML found in scripts dir (%s)", filename);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1806,12 +1720,6 @@ XmlParser::~XmlParser()
|
||||
m_pImpl->Release();
|
||||
}
|
||||
|
||||
void XmlParser::GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(this, sizeof(*this));
|
||||
pSizer->AddObject(m_pImpl);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
XmlNodeRef XmlParser::ParseBuffer(const char* buffer, int nBufLen, bool bCleanPools, bool bSuppressWarnings)
|
||||
{
|
||||
|
||||
@@ -34,7 +34,6 @@ public:
|
||||
}
|
||||
};
|
||||
virtual const char* AddString(const char* str) = 0;
|
||||
virtual void GetMemoryUsage(ICrySizer* pSizer) const = 0;
|
||||
private:
|
||||
int m_refCount;
|
||||
};
|
||||
@@ -68,8 +67,6 @@ public:
|
||||
|
||||
const char* getErrorString() const { return m_errorString; }
|
||||
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const;
|
||||
|
||||
private:
|
||||
int m_nRefCount;
|
||||
XmlString m_errorString;
|
||||
@@ -88,8 +85,6 @@ struct XmlAttribute
|
||||
const char* key;
|
||||
const char* value;
|
||||
|
||||
void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const{}
|
||||
|
||||
bool operator<(const XmlAttribute& attr) const { return g_pXmlStrCmp(key, attr.key) < 0; }
|
||||
bool operator>(const XmlAttribute& attr) const { return g_pXmlStrCmp(key, attr.key) > 0; }
|
||||
bool operator==(const XmlAttribute& attr) const { return g_pXmlStrCmp(key, attr.key) == 0; }
|
||||
@@ -119,9 +114,6 @@ public:
|
||||
//! Destructor.
|
||||
~CXmlNode();
|
||||
|
||||
// collect allocated memory informations
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Custom new/delete with pool allocator.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -219,11 +211,9 @@ public:
|
||||
void setAttr(const char* key, float value);
|
||||
void setAttr(const char* key, double value);
|
||||
void setAttr(const char* key, const Vec2& value);
|
||||
void setAttr(const char* key, const Vec2d& value);
|
||||
void setAttr(const char* key, const Ang3& value);
|
||||
void setAttr(const char* key, const Vec3& value);
|
||||
void setAttr(const char* key, const Vec4& value);
|
||||
void setAttr(const char* key, const Vec3d& value);
|
||||
void setAttr(const char* key, const Quat& value);
|
||||
|
||||
//! Delete attrbute.
|
||||
@@ -243,11 +233,9 @@ public:
|
||||
bool getAttr(const char* key, XmlString& value) const {const char* v(NULL); bool boHasAttribute(getAttr(key, &v)); value = v; return boHasAttribute; }
|
||||
|
||||
bool getAttr(const char* key, Vec2& value) const;
|
||||
bool getAttr(const char* key, Vec2d& value) const;
|
||||
bool getAttr(const char* key, Ang3& value) const;
|
||||
bool getAttr(const char* key, Vec3& value) const;
|
||||
bool getAttr(const char* key, Vec4& value) const;
|
||||
bool getAttr(const char* key, Vec3d& value) const;
|
||||
bool getAttr(const char* key, Quat& value) const;
|
||||
bool getAttr(const char* key, ColorB& value) const;
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_XML_XML_STRING_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_XML_XML_STRING_H
|
||||
#pragma once
|
||||
|
||||
|
||||
typedef string xml_string;
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_XML_XML_STRING_H
|
||||
Reference in New Issue
Block a user