Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,23 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
ly_add_target(
NAME CrySystem.XMLBinary STATIC
NAMESPACE Legacy
FILES_CMAKE
crysystem_xmlbinary_files.cmake
INCLUDE_DIRECTORIES
PUBLIC
.
BUILD_DEPENDENCIES
PUBLIC
Legacy::CryCommon
)
@@ -0,0 +1,22 @@
Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
and Clark Cooper
Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Expat maintainers.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,47 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#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(string); \
ELSE_LOAD_PROPERTY(bool);
#endif // CRYINCLUDE_CRYSYSTEM_XML_READWRITEXMLSINK_H
@@ -0,0 +1,709 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "CrySystem_precompiled.h"
#include "ReadWriteXMLSink.h"
#include <ISystem.h>
#include <stack>
typedef std::map<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<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, const char* name, XmlNodeRef& definition, XmlNodeRef& data)
{
if (XmlNodeRef enumNode = definition->findChild("Enum"))
{
// If strict mode is off, then no need to check the enum value
return true;
// if restrictive attribute set to false, check always succeeds
if (enumNode->haveAttr("restrictive"))
{
bool res = true;
enumNode->getAttr("restrictive", res);
if (!res)
{
return true;
}
}
// else check enum values
const char* val = data->getAttr(name);
for (int i = 0; i < enumNode->getChildCount(); ++i)
{
if (0 == strcmp(enumNode->getChild(i)->getContent(), val))
{
return true;
}
}
return false;
}
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());
string content = childRef->getContent();
dataToRead->setAttr(name, content.Trim().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;
}
}
const char* tag = definition->getTag();
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;
}
@@ -0,0 +1,209 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "CrySystem_precompiled.h"
#include "SerializeXMLReader.h"
#include <ISystem.h>
#define TAG_SCRIPT_VALUE "v"
#define TAG_SCRIPT_TYPE "t"
#define TAG_SCRIPT_NAME "n"
//#define LOG_SERIALIZE_STACK(tag,szName) CryLogAlways( "<%s> %s/%s",tag,GetStackInfo(),szName );
#define LOG_SERIALIZE_STACK(tag, szName)
CSerializeXMLReaderImpl::CSerializeXMLReaderImpl(const XmlNodeRef& nodeRef)
: m_nErrors(0)
{
//m_curTime = gEnv->pTimer->GetFrameStartTime();
assert(!!nodeRef);
m_nodeStack.push_back(CParseState());
m_nodeStack.back().Init(nodeRef);
}
bool CSerializeXMLReaderImpl::Value(const char* name, int8& value)
{
DefaultValue(value); // Set input value to default.
if (m_nErrors)
{
return false;
}
int temp;
bool bResult = Value(name, temp);
if (temp < -128 || temp > 127)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Attribute %s is out of range (%d)", name, temp);
Failed();
bResult = false;
}
else
{
value = temp;
}
return bResult;
}
bool CSerializeXMLReaderImpl::Value(const char* name, string& value)
{
DefaultValue(value); // Set input value to default.
if (m_nErrors)
{
return false;
}
if (!CurNode()->haveAttr(name))
{
//CryWarning( VALIDATOR_MODULE_SYSTEM,VALIDATOR_WARNING,"No such attribute %s (invalid type?)", name);
//Failed();
return false;
}
else
{
value = CurNode()->getAttr(name);
}
return true;
}
bool CSerializeXMLReaderImpl::Value(const char* name, CTimeValue& value)
{
DefaultValue(value); // Set input value to default.
if (m_nErrors)
{
return false;
}
XmlNodeRef nodeRef = CurNode();
if (!nodeRef)
{
return false;
}
if (0 == strcmp("zero", nodeRef->getAttr(name)))
{
value = CTimeValue(0.0f);
}
else
{
float delta;
if (!GetAttr(nodeRef, name, delta))
{
//CryWarning( VALIDATOR_MODULE_SYSTEM,VALIDATOR_WARNING,"Failed to read time value %s", name);
//Failed();
value = gEnv->pTimer->GetFrameStartTime(); // in case we don't find the node, it was assumed to be the default value (0.0)
// 0.0 means current time, whereas "zero" really means CTimeValue(0.0), see above
return false;
}
else
{
value = CTimeValue(gEnv->pTimer->GetFrameStartTime() + delta);
}
}
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)
{
//CryWarning( VALIDATOR_MODULE_SYSTEM,VALIDATOR_WARNING,"BeginGroup %s called on non-existant group", szName);
m_nErrors++;
}
else if (XmlNodeRef node = NextOf(szName))
{
m_nodeStack.push_back(CParseState());
m_nodeStack.back().Init(node);
LOG_SERIALIZE_STACK("BeginGroup:ok", szName);
}
else
{
LOG_SERIALIZE_STACK("BeginGroup:fail", szName);
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "!BeginGroup( %s ) not found", szName);
m_nErrors++;
}
}
bool CSerializeXMLReaderImpl::BeginOptionalGroup(const char* szName, [[maybe_unused]] bool condition)
{
if (m_nErrors)
{
//CryWarning( VALIDATOR_MODULE_SYSTEM,VALIDATOR_WARNING,"BeginOptionalGroup %s called on non-existant group", szName);
m_nErrors++;
}
else if (XmlNodeRef node = NextOf(szName))
{
m_nodeStack.push_back(CParseState());
m_nodeStack.back().Init(node);
LOG_SERIALIZE_STACK("BeginOptionalGroup:ok", szName);
return true;
}
LOG_SERIALIZE_STACK("BeginOptionalGroup:fail", szName);
return false;
}
void CSerializeXMLReaderImpl::EndGroup()
{
if (m_nErrors)
{
m_nErrors--;
}
else
{
LOG_SERIALIZE_STACK("EndGroup", "");
m_nodeStack.pop_back();
}
assert(!m_nodeStack.empty());
}
//////////////////////////////////////////////////////////////////////////
const char* CSerializeXMLReaderImpl::GetStackInfo() const
{
static string str;
str.assign("");
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.c_str();
}
void CSerializeXMLReaderImpl::GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->Add(*this);
pSizer->AddContainer(m_nodeStack);
}
@@ -0,0 +1,187 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#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:
CSerializeXMLReaderImpl(const XmlNodeRef& nodeRef);
template <class T_Value>
ILINE bool GetAttr(const XmlNodeRef& node, const char* name, T_Value& value)
{
XmlStrCmpFunc pPrevCmpFunc = g_pXmlStrCmp;
g_pXmlStrCmp = &strcmp; // Do case-sensitive compare
bool bReturn = node->getAttr(name, value);
g_pXmlStrCmp = pPrevCmpFunc;
return bReturn;
}
ILINE bool GetAttr(const XmlNodeRef& node, const char* name, SSerializeString& value)
{
XmlStrCmpFunc pPrevCmpFunc = g_pXmlStrCmp;
g_pXmlStrCmp = &strcmp; // Do case-sensitive compare
bool bReturn = node->haveAttr(name);
if (bReturn)
{
value = node->getAttr(name);
}
g_pXmlStrCmp = pPrevCmpFunc;
return bReturn;
}
ILINE bool GetAttr([[maybe_unused]] XmlNodeRef& node, [[maybe_unused]] const char* name, [[maybe_unused]] const string& value)
{
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)
{
DefaultValue(value); // Set input value to default.
if (m_nErrors)
{
return false;
}
if (!GetAttr(CurNode(), name, value))
{
//CryWarning( VALIDATOR_MODULE_SYSTEM,VALIDATOR_WARNING,"Unable to read attribute %s (invalid type?)", name);
//Failed();
return false;
}
return true;
}
bool Value(const char* name, int8& value);
bool Value(const char* name, 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();
const char* GetStackInfo() const;
void GetMemoryUsage(ICrySizer* pSizer) const;
private:
//CTimeValue m_curTime;
XmlNodeRef CurNode() { return m_nodeStack.back().m_node; }
XmlNodeRef NextOf(const char* name)
{
XmlStrCmpFunc pPrevCmpFunc = g_pXmlStrCmp;
g_pXmlStrCmp = &strcmp; // Do case-sensitive compare
assert(!m_nodeStack.empty());
CParseState& ps = m_nodeStack.back();
XmlNodeRef node = ps.GetNext(name);
g_pXmlStrCmp = pPrevCmpFunc;
return node;
}
class CParseState
{
public:
CParseState() {}
void Init(const XmlNodeRef& node)
{
m_node = node;
m_nCurrent = 0;
}
XmlNodeRef GetNext(const char* name)
{
int i;
int num = m_node->getChildCount();
for (i = m_nCurrent; i < num; i++)
{
XmlNodeRef child = m_node->getChild(i);
if (strcmp(child->getTag(), name) == 0)
{
m_nCurrent = i + 1;
return child;
}
}
int ncount = min(m_nCurrent, num);
// Try searching from begining.
for (i = 0; i < ncount; i++)
{
XmlNodeRef child = m_node->getChild(i);
if (strcmp(child->getTag(), name) == 0)
{
m_nCurrent = i + 1;
return child;
}
}
return XmlNodeRef();
}
public:
// TODO: make this much more efficient
int m_nCurrent;
XmlNodeRef m_node;
};
int m_nErrors;
std::vector<CParseState> m_nodeStack;
//////////////////////////////////////////////////////////////////////////
// Set Defaults.
//////////////////////////////////////////////////////////////////////////
void DefaultValue(bool& v) const { v = false; }
void DefaultValue(float& v) const { v = 0; }
void DefaultValue(double& v) const { v = 0; }
void DefaultValue(int8& v) const { v = 0; }
void DefaultValue(uint8& v) const { v = 0; }
void DefaultValue(int16& v) const { v = 0; }
void DefaultValue(uint16& v) const { v = 0; }
void DefaultValue(int32& v) const { v = 0; }
void DefaultValue(uint32& v) const { v = 0; }
void DefaultValue(int64& v) const { v = 0; }
void DefaultValue(uint64& v) const { v = 0; }
void DefaultValue(Vec2& v) const { v.x = 0; v.y = 0; }
void DefaultValue(Vec3& v) const { v.x = 0; v.y = 0; v.z = 0; }
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(string& str) const { str = ""; }
void DefaultValue([[maybe_unused]] const 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
@@ -0,0 +1,157 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "CrySystem_precompiled.h"
#include "SerializeXMLWriter.h"
static const size_t MAX_NODE_STACK_DEPTH = 40;
#define TAG_SCRIPT_VALUE "v"
#define TAG_SCRIPT_TYPE "t"
#define TAG_SCRIPT_NAME "n"
CSerializeXMLWriterImpl::CSerializeXMLWriterImpl(const XmlNodeRef& nodeRef)
{
m_curTime = gEnv->pTimer->GetFrameStartTime();
assert(!!nodeRef);
m_nodeStack.push_back(nodeRef);
m_luaSaveStack.reserve(10);
}
//////////////////////////////////////////////////////////////////////////
CSerializeXMLWriterImpl::~CSerializeXMLWriterImpl()
{
if (m_nodeStack.size() != 1)
{
// Node stack is incorrect.
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "!BeginGroup/EndGroup mismatch in SaveGame");
}
}
//////////////////////////////////////////////////////////////////////////
bool CSerializeXMLWriterImpl::Value(const char* name, CTimeValue value)
{
if (value == CTimeValue(0.0f))
{
AddValue(name, "zero");
}
else
{
AddValue(name, (value - m_curTime).GetSeconds());
}
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)
{
assert(0 && "Spaces in group name not supported");
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "!Spaces in group name not supported: %s/%s", GetStackInfo(), szName);
}
XmlNodeRef node = CreateNodeNamed(szName);
CurNode()->addChild(node);
m_nodeStack.push_back(node);
if (m_nodeStack.size() > MAX_NODE_STACK_DEPTH)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "!Too Deep Node Stack:\r\n%s", GetStackInfo());
}
}
bool CSerializeXMLWriterImpl::BeginOptionalGroup(const char* szName, bool condition)
{
if (condition)
{
BeginGroup(szName);
return true;
}
return condition;
}
XmlNodeRef CSerializeXMLWriterImpl::CreateNodeNamed(const char* name)
{
XmlNodeRef newNode = CurNode()->createNode(name);
return newNode;
}
void CSerializeXMLWriterImpl::EndGroup()
{
if (m_nodeStack.size() == 1)
{
//
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "!Misplaced EndGroup() for BeginGroup(%s)", CurNode()->getTag());
}
assert(!m_nodeStack.empty());
m_nodeStack.pop_back();
assert(!m_nodeStack.empty());
}
void CSerializeXMLWriterImpl::GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->Add(*this);
pSizer->AddObject(m_nodeStack);
pSizer->AddContainer(m_luaSaveStack);
}
//////////////////////////////////////////////////////////////////////////
const char* CSerializeXMLWriterImpl::GetStackInfo() const
{
static string str;
str.assign("");
for (int i = 0; i < (int)m_nodeStack.size(); i++)
{
const char* name = m_nodeStack[i]->getAttr(TAG_SCRIPT_NAME);
if (name && name[0])
{
str += name;
}
else
{
str += m_nodeStack[i]->getTag();
}
if (i != m_nodeStack.size() - 1)
{
str += "/";
}
}
return str.c_str();
}
//////////////////////////////////////////////////////////////////////////
const char* CSerializeXMLWriterImpl::GetLuaStackInfo() const
{
static string str;
str.assign("");
for (int i = 0; i < (int)m_luaSaveStack.size(); i++)
{
const char* name = m_luaSaveStack[i];
str += name;
if (i != m_luaSaveStack.size() - 1)
{
str += ".";
}
}
return str.c_str();
}
@@ -0,0 +1,156 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYSYSTEM_XML_SERIALIZEXMLWRITER_H
#define CRYINCLUDE_CRYSYSTEM_XML_SERIALIZEXMLWRITER_H
#pragma once
#include <ISystem.h>
#include <ITimer.h>
#include <IXml.h>
#include "IValidator.h"
#include "SimpleSerialize.h"
class CSerializeXMLWriterImpl
: public CSimpleSerializeImpl<false, eST_SaveGame>
{
public:
CSerializeXMLWriterImpl(const XmlNodeRef& nodeRef);
~CSerializeXMLWriterImpl();
template <class T_Value>
bool Value(const char* name, T_Value& value)
{
AddValue(name, value);
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.
//////////////////////////////////////////////////////////////////////////
CTimeValue m_curTime;
std::vector<XmlNodeRef> m_nodeStack;
std::vector<const char*> m_luaSaveStack;
//////////////////////////////////////////////////////////////////////////
ILINE const XmlNodeRef& CurNode()
{
assert(!m_nodeStack.empty());
if (m_nodeStack.empty())
{
static XmlNodeRef temp = GetISystem()->CreateXmlNode("Error");
return temp;
}
return m_nodeStack.back();
}
XmlNodeRef CreateNodeNamed(const char* name);
template <class T>
void AddValue(const char* name, const T& value)
{
if (strchr(name, ' ') != 0)
{
assert(0 && "Spaces in Value name not supported");
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "!Spaces in Value name not supported: %s in Group %s", name, GetStackInfo());
return;
}
if (GetISystem()->IsDevMode() && CurNode())
{
// Check if this attribute already added.
if (CurNode()->haveAttr(name))
{
assert(0);
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "!Duplicate tag Value( \"%s\" ) in Group %s", name, GetStackInfo());
}
}
if (!IsDefaultValue(value))
{
CurNode()->setAttr(name, value);
}
}
void AddValue(const char* name, const SSerializeString& value)
{
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)
{
if (!IsDefaultValue(value))
{
XmlNodeRef newNode = CreateNodeNamed(name);
newNode->setAttr("v", value);
newNode->setAttr("t", type);
}
}
// Used for printing currebnt stack info for warnings.
const char* GetStackInfo() const;
const char* GetLuaStackInfo() const;
//////////////////////////////////////////////////////////////////////////
// Check For Defaults.
//////////////////////////////////////////////////////////////////////////
bool IsDefaultValue(bool v) const { return v == false; };
bool IsDefaultValue(float v) const { return v == 0; };
bool IsDefaultValue(double v) const { return v == 0; };
bool IsDefaultValue(int8 v) const { return v == 0; };
bool IsDefaultValue(uint8 v) const { return v == 0; };
bool IsDefaultValue(int16 v) const { return v == 0; };
bool IsDefaultValue(uint16 v) const { return v == 0; };
bool IsDefaultValue(int32 v) const { return v == 0; };
bool IsDefaultValue(uint32 v) const { return v == 0; };
bool IsDefaultValue(int64 v) const { return v == 0; };
bool IsDefaultValue(uint64 v) const { return v == 0; };
bool IsDefaultValue(const Vec2& v) const { return v.x == 0 && v.y == 0; };
bool IsDefaultValue(const Vec3& v) const { return v.x == 0 && v.y == 0 && v.z == 0; };
bool IsDefaultValue(const Ang3& v) const { return v.x == 0 && v.y == 0 && v.z == 0; };
bool IsDefaultValue(const Quat& v) const { return v.w == 1.0f && v.v.x == 0 && v.v.y == 0 && v.v.z == 0; };
bool IsDefaultValue(const CTimeValue& v) const { return v.GetValue() == 0; };
bool IsDefaultValue(const char* str) const { return !str || !*str; };
bool IsDefaultValue(const string& str) const { return str.empty(); };
bool IsDefaultValue(const SSerializeString& str) const { return str.empty(); };
//////////////////////////////////////////////////////////////////////////
/*
template <class T>
bool IsDefaultValue( const T& v ) const { return false; };
*/
};
#endif // CRYINCLUDE_CRYSYSTEM_XML_SERIALIZEXMLWRITER_H
@@ -0,0 +1,435 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "CrySystem_precompiled.h"
#include "ReadWriteXMLSink.h"
#include <stack>
typedef std::map<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<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 i = 1; i <= numElems; i++)
{
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;
}
@@ -0,0 +1,386 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include <platform.h>
#include "XMLBinaryNode.h"
#include <CrySizer.h>
//////////////////////////////////////////////////////////////////////////
CBinaryXmlData::CBinaryXmlData()
: pNodes(0)
, pAttributes(0)
, pChildIndices(0)
, pStringData(0)
, pFileContents(0)
, nFileSize(0)
, bOwnsFileContentsMemory(true)
, pBinaryNodes(0)
, nRefCount(0)
{
}
//////////////////////////////////////////////////////////////////////////
CBinaryXmlData::~CBinaryXmlData()
{
if (bOwnsFileContentsMemory)
{
delete [] pFileContents;
}
pFileContents = 0;
delete [] pBinaryNodes;
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
{
const XMLBinary::Node* const pNode = _node();
if (pNode->nParentIndex != (XMLBinary::NodeIndex)-1)
{
return &m_pData->pBinaryNodes[pNode->nParentIndex];
}
return XmlNodeRef();
}
XmlNodeRef CBinaryXmlNode::createNode([[maybe_unused]] const char* tag)
{
assert(0);
return 0;
}
//////////////////////////////////////////////////////////////////////////
bool CBinaryXmlNode::isTag(const char* tag) const
{
return g_pXmlStrCmp(tag, getTag()) == 0;
}
const char* CBinaryXmlNode::getAttr(const char* key) const
{
const char* svalue = GetValue(key);
if (svalue)
{
return svalue;
}
return "";
}
bool CBinaryXmlNode::getAttr(const char* key, const char** value) const
{
const char* svalue = GetValue(key);
if (svalue)
{
*value = svalue;
return true;
}
else
{
*value = "";
return false;
}
}
bool CBinaryXmlNode::haveAttr(const char* key) const
{
return (GetValue(key) != 0);
}
//////////////////////////////////////////////////////////////////////////
bool CBinaryXmlNode::getAttr(const char* key, int& value) const
{
const char* svalue = GetValue(key);
if (svalue)
{
value = atoi(svalue);
return true;
}
return false;
}
bool CBinaryXmlNode::getAttr(const char* key, unsigned int& value) const
{
const char* svalue = GetValue(key);
if (svalue)
{
value = strtoul(svalue, NULL, 10);
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool CBinaryXmlNode::getAttr(const char* key, int64& value) const
{
const char* svalue = GetValue(key);
if (svalue)
{
azsscanf(svalue, "%" PRId64, &value);
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool CBinaryXmlNode::getAttr(const char* key, uint64& value, bool useHexFormat) const
{
const char* svalue = GetValue(key);
if (svalue)
{
if (useHexFormat)
{
azsscanf(svalue, "%" PRIX64, &value);
}
else
{
azsscanf(svalue, "%" PRIu64, &value);
}
return true;
}
return false;
}
bool CBinaryXmlNode::getAttr(const char* key, bool& value) const
{
const char* svalue = GetValue(key);
if (svalue)
{
value = atoi(svalue) != 0;
return true;
}
return false;
}
bool CBinaryXmlNode::getAttr(const char* key, float& value) const
{
const char* svalue = GetValue(key);
if (svalue)
{
value = (float)atof(svalue);
return true;
}
return false;
}
bool CBinaryXmlNode::getAttr(const char* key, double& value) const
{
const char* svalue = GetValue(key);
if (svalue)
{
value = atof(svalue);
return true;
}
return false;
}
bool CBinaryXmlNode::getAttr(const char* key, Ang3& value) const
{
const char* svalue = GetValue(key);
if (svalue)
{
float x, y, z;
if (azsscanf(svalue, "%f,%f,%f", &x, &y, &z) == 3)
{
value(x, y, z);
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool CBinaryXmlNode::getAttr(const char* key, Vec3& value) const
{
const char* svalue = GetValue(key);
if (svalue)
{
float x, y, z;
if (azsscanf(svalue, "%f,%f,%f", &x, &y, &z) == 3)
{
value = Vec3(x, y, z);
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool CBinaryXmlNode::getAttr(const char* key, Vec4& value) const
{
const char* svalue = GetValue(key);
if (svalue)
{
float x, y, z, w;
if (azsscanf(svalue, "%f,%f,%f,%f", &x, &y, &z, &w) == 4)
{
value = Vec4(x, y, z, w);
return true;
}
}
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
{
const char* svalue = GetValue(key);
if (svalue)
{
float x, y;
if (azsscanf(svalue, "%f,%f", &x, &y) == 2)
{
value = Vec2(x, y);
return true;
}
}
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
{
const char* svalue = GetValue(key);
if (svalue)
{
float w, x, y, z;
if (azsscanf(svalue, "%f,%f,%f,%f", &w, &x, &y, &z) == 4)
{
value = Quat(w, x, y, z);
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool CBinaryXmlNode::getAttr(const char* key, ColorB& value) const
{
const char* svalue = GetValue(key);
if (svalue)
{
unsigned int r, g, b, a = 255;
int numFound = azsscanf(svalue, "%u,%u,%u,%u", &r, &g, &b, &a);
if (numFound == 3 || numFound == 4)
{
// If we only found 3 values, a should be unchanged, and still be 255
if (r < 256 && g < 256 && b < 256 && a < 256)
{
value = ColorB(r, g, b, a);
return true;
}
}
}
return false;
}
XmlNodeRef CBinaryXmlNode::findChild(const char* tag) const
{
const XMLBinary::Node* const pNode = _node();
const uint32 nFirst = pNode->nFirstChildIndex;
const uint32 nAfterLast = pNode->nFirstChildIndex + pNode->nChildCount;
for (uint32 i = nFirst; i < nAfterLast; ++i)
{
const char* sChildTag = m_pData->pStringData + m_pData->pNodes[m_pData->pChildIndices[i]].nTagStringOffset;
if (g_pXmlStrCmp(tag, sChildTag) == 0)
{
return m_pData->pBinaryNodes + m_pData->pChildIndices[i];
}
}
return 0;
}
//! Get XML Node child nodes.
XmlNodeRef CBinaryXmlNode::getChild(int i) const
{
const XMLBinary::Node* const pNode = _node();
assert(i >= 0 && i < (int)pNode->nChildCount);
return m_pData->pBinaryNodes + m_pData->pChildIndices[pNode->nFirstChildIndex + i];
}
//////////////////////////////////////////////////////////////////////////
bool CBinaryXmlNode::getAttributeByIndex(int index, const char** key, const char** value)
{
const XMLBinary::Node* const pNode = _node();
if (index >= 0 && index < pNode->nAttributeCount)
{
const XMLBinary::Attribute& attr = m_pData->pAttributes[pNode->nFirstAttributeIndex + index];
*key = _string(attr.nKeyStringOffset);
*value = _string(attr.nValueStringOffset);
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool CBinaryXmlNode::getAttributeByIndex(int index, XmlString& key, XmlString& value)
{
const XMLBinary::Node* const pNode = _node();
if (index >= 0 && index < pNode->nAttributeCount)
{
const XMLBinary::Attribute& attr = m_pData->pAttributes[pNode->nFirstAttributeIndex + index];
key = _string(attr.nKeyStringOffset);
value = _string(attr.nValueStringOffset);
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
@@ -0,0 +1,243 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYSYSTEM_XML_XMLBINARYNODE_H
#define CRYINCLUDE_CRYSYSTEM_XML_XMLBINARYNODE_H
#pragma once
#include <algorithm>
#include "IXml.h"
#include "XMLBinaryHeaders.h"
// Compare function for string comparison, can be strcmp or _stricmp
typedef int (__cdecl * XmlStrCmpFunc)(const char* str1, const char* str2);
extern XmlStrCmpFunc g_pXmlStrCmp;
class CBinaryXmlNode;
//////////////////////////////////////////////////////////////////////////
class CBinaryXmlData
{
public:
const XMLBinary::Node* pNodes;
const XMLBinary::Attribute* pAttributes;
const XMLBinary::NodeIndex* pChildIndices;
const char* pStringData;
const char* pFileContents;
size_t nFileSize;
bool bOwnsFileContentsMemory;
CBinaryXmlNode* pBinaryNodes;
int nRefCount;
CBinaryXmlData();
~CBinaryXmlData();
void GetMemoryUsage(ICrySizer* pSizer) const;
};
// forward declaration
namespace XMLBinary
{
class XMLBinaryReader;
};
//////////////////////////////////////////////////////////////////////////
// CBinaryXmlNode class only used for fast read only binary XML import
//////////////////////////////////////////////////////////////////////////
class CBinaryXmlNode
: public IXmlNode
{
public:
// collect allocated memory informations
void GetMemoryUsage(ICrySizer* pSizer) const;
//////////////////////////////////////////////////////////////////////////
// Custom new/delete with pool allocator.
//////////////////////////////////////////////////////////////////////////
//void* operator new( size_t nSize );
//void operator delete( void *ptr );
virtual void DeleteThis() { }
//! Create new XML node.
XmlNodeRef createNode(const char* tag);
// Summary:
// Reference counting.
virtual void AddRef() { ++m_pData->nRefCount; };
// Notes:
// When ref count reach zero XML node dies.
virtual void Release()
{
if (--m_pData->nRefCount <= 0)
{
delete m_pData;
}
};
//! Get XML node tag.
const char* getTag() const { return _string(_node()->nTagStringOffset); };
void setTag([[maybe_unused]] const char* tag) { assert(0); };
//! Return true if given tag is equal to node tag.
bool isTag(const char* tag) const;
//! Get XML Node attributes.
virtual int getNumAttributes() const { return (int)_node()->nAttributeCount; };
//! Return attribute key and value by attribute index.
virtual bool getAttributeByIndex(int index, const char** key, const char** value);
//! Return attribute key and value by attribute index, string version.
virtual bool getAttributeByIndex(int index, XmlString& key, XmlString& value);
virtual void shareChildren([[maybe_unused]] const XmlNodeRef& fromNode) { assert(0); };
virtual void copyAttributes(XmlNodeRef fromNode) { assert(0); };
//! Get XML Node attribute for specified key.
const char* getAttr(const char* key) const;
//! Get XML Node attribute for specified key.
// Returns true if the attribute exists, false otherwise.
bool getAttr(const char* key, const char** value) const;
//! Check if attributes with specified key exist.
bool haveAttr(const char* key) const;
XmlNodeRef newChild([[maybe_unused]] const char* tagName) { assert(0); return 0; };
void replaceChild([[maybe_unused]] int inChild, [[maybe_unused]] const XmlNodeRef& node) { assert(0); };
void insertChild([[maybe_unused]] int inChild, [[maybe_unused]] const XmlNodeRef& node) { assert(0); };
void addChild([[maybe_unused]] const XmlNodeRef& node) { assert(0); };
void removeChild([[maybe_unused]] const XmlNodeRef& node) { assert(0); };
//! Remove all child nodes.
void removeAllChilds() { assert(0); };
//! Get number of child XML nodes.
int getChildCount() const { return (int)_node()->nChildCount; };
//! Get XML Node child nodes.
XmlNodeRef getChild(int i) const;
//! Find node with specified tag.
XmlNodeRef findChild(const char* tag) const;
void deleteChild([[maybe_unused]] const char* tag) { assert(0); };
void deleteChildAt([[maybe_unused]] int nIndex) { assert(0); };
//! Get parent XML node.
XmlNodeRef getParent() const;
//! Returns content of this node.
const char* getContent() const { return _string(_node()->nContentStringOffset); };
void setContent([[maybe_unused]] const char* str) { assert(0); };
XmlNodeRef clone() { assert(0); return 0; };
//! Returns line number for XML tag.
int getLine() const { return 0; };
//! Set line number in xml.
void setLine([[maybe_unused]] int line) { assert(0); };
//! Returns XML of this node and sub nodes.
virtual IXmlStringData* getXMLData([[maybe_unused]] int nReserveMem = 0) const { assert(0); return 0; };
XmlString getXML([[maybe_unused]] int level = 0) const { assert(0); return ""; };
bool saveToFile([[maybe_unused]] const char* fileName) { assert(0); return false; }; // saves in one huge chunk
bool saveToFile([[maybe_unused]] const char* fileName, [[maybe_unused]] size_t chunkSizeBytes, [[maybe_unused]] AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle) { assert(0); return false; }; // save in small memory chunks
//! Set new XML Node attribute (or override attribute with same key).
void setAttr([[maybe_unused]] const char* key, [[maybe_unused]] const char* value) { assert(0); };
void setAttr([[maybe_unused]] const char* key, [[maybe_unused]] int value) { assert(0); };
void setAttr([[maybe_unused]] const char* key, [[maybe_unused]] unsigned int value) { assert(0); };
void setAttr([[maybe_unused]] const char* key, [[maybe_unused]] int64 value) { assert(0); };
void setAttr([[maybe_unused]] const char* key, [[maybe_unused]] uint64 value, [[maybe_unused]] bool useHexFormat = true /* ignored */) { assert(0); };
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); };
//! Get attribute value of node.
bool getAttr(const char* key, int& value) const;
bool getAttr(const char* key, unsigned int& value) const;
bool getAttr(const char* key, int64& value) const;
bool getAttr(const char* key, uint64& value, bool useHexFormat = true /* ignored */) const;
bool getAttr(const char* key, float& value) const;
bool getAttr(const char* key, f64& value) const;
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;
// bool getAttr( const char *key,CString &value ) const { XmlString v; if (getAttr(key,v)) { value = (const char*)v; return true; } else return false; }
private:
//////////////////////////////////////////////////////////////////////////
// INTERNAL METHODS
//////////////////////////////////////////////////////////////////////////
const char* GetValue(const char* key) const
{
const XMLBinary::Attribute* const pAttributes = m_pData->pAttributes;
const char* const pStringData = m_pData->pStringData;
const int nFirst = _node()->nFirstAttributeIndex;
const int nLast = nFirst + _node()->nAttributeCount;
for (int i = nFirst; i < nLast; i++)
{
const char* const attrKey = pStringData + pAttributes[i].nKeyStringOffset;
if (g_pXmlStrCmp(key, attrKey) == 0)
{
const char* attrValue = pStringData + pAttributes[i].nValueStringOffset;
return attrValue;
}
}
return 0;
}
// Return current node in binary data.
const XMLBinary::Node* _node() const
{
return &m_pData->pNodes[this - m_pData->pBinaryNodes];
}
const char* _string(int nIndex) const
{
return m_pData->pStringData + nIndex;
}
protected:
virtual void setParent([[maybe_unused]] const XmlNodeRef& inRef) { assert(0); }
//////////////////////////////////////////////////////////////////////////
private:
CBinaryXmlData* m_pData;
friend class XMLBinary::XMLBinaryReader;
};
#endif // CRYINCLUDE_CRYSYSTEM_XML_XMLBINARYNODE_H
@@ -0,0 +1,276 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include <platform.h>
#include "XMLBinaryReader.h"
#include "XMLBinaryNode.h"
#include "CryPath.h"
XMLBinary::XMLBinaryReader::XMLBinaryReader()
{
m_errorDescription[0] = 0;
}
XMLBinary::XMLBinaryReader::~XMLBinaryReader()
{
}
const char* XMLBinary::XMLBinaryReader::GetErrorDescription() const
{
return &m_errorDescription[0];
}
void XMLBinary::XMLBinaryReader::SetErrorDescription(const char* text)
{
cry_strcpy(m_errorDescription, text);
}
XmlNodeRef XMLBinary::XMLBinaryReader::LoadFromFile(
const char* filename,
XMLBinary::XMLBinaryReader::EResult& result)
{
m_errorDescription[0] = 0;
result = eResult_Error;
CCryFile xmlFile;
if (!xmlFile.Open(filename, "rb"))
{
SetErrorDescription("Can't open file.");
return 0;
}
const size_t fileSize = xmlFile.GetLength();
if (fileSize < sizeof(BinaryFileHeader))
{
result = eResult_NotBinXml;
SetErrorDescription("File is not a binary XML file (file size is too small).");
return 0;
}
// Read in the entire file - this buffer will not be deallocated immediately, since the nodes
// will contain pointers directly into it. It will be deleted once the reference count on the
// CBinaryXmlData object reaches 0 again.
char* const pFileContents = new char[fileSize];
if (!pFileContents)
{
SetErrorDescription("Can't allocate memory for binary XML file contents.");
return 0;
}
if (xmlFile.ReadRaw(pFileContents, fileSize) != fileSize)
{
delete [] pFileContents;
SetErrorDescription("Failed to read binary XML file, the file is corrupt.");
return 0;
}
Check(pFileContents, fileSize, result);
if (result != eResult_Success)
{
delete [] pFileContents;
return 0;
}
CBinaryXmlData* const pData = Create(pFileContents, fileSize, result);
if (result != eResult_Success)
{
assert(pData == 0);
delete [] pFileContents;
return 0;
}
assert(pData);
pData->bOwnsFileContentsMemory = true;
// Return first node
return &pData->pBinaryNodes[0];
}
XmlNodeRef XMLBinary::XMLBinaryReader::LoadFromBuffer(
EBufferMemoryHandling bufferMemoryHandling,
const char* buffer,
size_t size,
XMLBinary::XMLBinaryReader::EResult& result)
{
m_errorDescription[0] = 0;
result = eResult_Error;
Check(buffer, size, result);
if (result != eResult_Success)
{
return 0;
}
CBinaryXmlData* pData = 0;
if (bufferMemoryHandling == eBufferMemoryHandling_MakeCopy)
{
char* ownBuffer = new char[size];
if (!ownBuffer)
{
SetErrorDescription("Can't allocate memory for binary XML data.");
return 0;
}
memcpy(ownBuffer, buffer, size);
pData = Create(ownBuffer, size, result);
if (result != eResult_Success)
{
assert(pData == 0);
delete [] ownBuffer;
return 0;
}
}
else
{
assert(bufferMemoryHandling == eBufferMemoryHandling_TakeOwnership);
pData = Create(buffer, size, result);
if (result != eResult_Success)
{
assert(pData == 0);
return 0;
}
}
assert(pData);
pData->bOwnsFileContentsMemory = true;
// Return first node
return &pData->pBinaryNodes[0];
}
void XMLBinary::XMLBinaryReader::Check(const char* buffer, size_t size, EResult& result)
{
m_errorDescription[0] = 0;
result = eResult_Error;
if (buffer == 0)
{
SetErrorDescription("Buffer is null.");
return;
}
if (size < sizeof(BinaryFileHeader))
{
result = eResult_NotBinXml;
SetErrorDescription("Not a binary XML - data size is too small.");
return;
}
const BinaryFileHeader& header = *(reinterpret_cast<const BinaryFileHeader*>(buffer));
CheckHeader(header, size, result);
}
void XMLBinary::XMLBinaryReader::CheckHeader(const BinaryFileHeader& header, size_t size, EResult& result)
{
assert(size >= sizeof(BinaryFileHeader));
m_errorDescription[0] = 0;
// Check the signature of the file to make sure that it is a binary XML file.
{
static const char signature[] = "CryXmlB";
COMPILE_TIME_ASSERT(sizeof(signature) == sizeof(header.szSignature));
if (memcmp(header.szSignature, signature, sizeof(header.szSignature)) != 0)
{
result = eResult_NotBinXml;
SetErrorDescription("Not a binary XML - has no signature.");
return;
}
}
// Check contents of the file header.
const uint32 nNodeTableEnd = header.nNodeTablePosition + header.nNodeCount * sizeof(Node);
const uint32 nChildTableEnd = header.nChildTablePosition + header.nChildCount * sizeof(NodeIndex);
const uint32 nAttributeTableEnd = header.nAttributeTablePosition + header.nAttributeCount * sizeof(Attribute);
const uint32 nStringDataEnd = header.nStringDataPosition + header.nStringDataSize;
bool bCorrupt = false;
bCorrupt = bCorrupt || header.nXMLSize > size;
bCorrupt = bCorrupt || nNodeTableEnd > header.nChildTablePosition;
bCorrupt = bCorrupt || nChildTableEnd > header.nAttributeTablePosition;
bCorrupt = bCorrupt || nAttributeTableEnd > header.nStringDataPosition;
bCorrupt = bCorrupt || nStringDataEnd > header.nXMLSize;
if (bCorrupt)
{
result = eResult_Error;
SetErrorDescription("Binary XML data is corrupt.");
return;
}
result = eResult_Success;
}
CBinaryXmlData* XMLBinary::XMLBinaryReader::Create(const char* buffer, size_t size, EResult& result)
{
assert((buffer != 0) && (size >= sizeof(BinaryFileHeader)));
m_errorDescription[0] = 0;
result = eResult_Error;
CBinaryXmlData* const pData = new CBinaryXmlData;
if (!pData)
{
SetErrorDescription("Can't allocate memory for binary XML object.");
return 0;
}
pData->pFileContents = buffer;
pData->nFileSize = size;
pData->bOwnsFileContentsMemory = false;
const BinaryFileHeader& header = *(reinterpret_cast<const BinaryFileHeader*>(buffer));
// Create nodes
pData->pBinaryNodes = new CBinaryXmlNode[header.nNodeCount];
if (!pData->pBinaryNodes)
{
delete pData;
SetErrorDescription("Can't allocate memory for binary XML nodes.");
return 0;
}
pData->pAttributes = reinterpret_cast<const Attribute*>(buffer + header.nAttributeTablePosition);
pData->pChildIndices = reinterpret_cast<const NodeIndex*>(buffer + header.nChildTablePosition);
pData->pNodes = reinterpret_cast<const Node*>(buffer + header.nNodeTablePosition);
pData->pStringData = buffer + header.nStringDataPosition;
for (uint32 nNode = 0; nNode < header.nNodeCount; ++nNode)
{
CBinaryXmlNode* const pNode = &pData->pBinaryNodes[nNode];
pNode->m_nRefCount = 0;
pNode->m_pData = pData;
}
result = eResult_Success;
return pData;
}
@@ -0,0 +1,68 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYSYSTEM_XML_XMLBINARYREADER_H
#define CRYINCLUDE_CRYSYSTEM_XML_XMLBINARYREADER_H
#pragma once
#include "XMLBinaryHeaders.h"
#include "IXml.h"
#include "CryFile.h"
class CBinaryXmlData;
namespace XMLBinary
{
class XMLBinaryReader
{
public:
enum EResult
{
eResult_Success,
eResult_NotBinXml,
eResult_Error
};
enum EBufferMemoryHandling
{
eBufferMemoryHandling_MakeCopy,
eBufferMemoryHandling_TakeOwnership
};
public:
XMLBinaryReader();
~XMLBinaryReader();
XmlNodeRef LoadFromFile(const char* filename, EResult& result);
// Note: if bufferMemoryHandling == eBufferMemoryHandling_TakeOwnership and
// returned result is eResult_Success, then buffer's memory is owned and
// will be released by XMLBinaryReader (by a 'delete[] buffer' call).
// Otherwise, the caller is responsible for releasing buffer's memory.
XmlNodeRef LoadFromBuffer(EBufferMemoryHandling bufferMemoryHandling, const char* buffer, size_t size, EResult& result);
const char* GetErrorDescription() const;
private:
void Check(const char* buffer, size_t size, EResult& result);
void CheckHeader(const BinaryFileHeader& layout, size_t size, EResult& result);
CBinaryXmlData* Create(const char* buffer, size_t size, EResult& result);
void SetErrorDescription(const char* text);
private:
char m_errorDescription[64];
};
}
#endif // CRYINCLUDE_CRYSYSTEM_XML_XMLBINARYREADER_H
@@ -0,0 +1,340 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include <platform.h>
#include "XMLBinaryWriter.h"
#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()
{
m_nStringDataSize = 0;
}
static void align(size_t& nPosition, const size_t nAlignment)
{
const size_t nPadSize = ((nPosition + (nAlignment - 1)) & ~(nAlignment - 1)) - nPosition;
nPosition += nPadSize;
}
static void alignWrite(XMLBinary::IDataWriter* const pFile, size_t& nPosition, const size_t nAlignment)
{
size_t nPadSize = ((nPosition + (nAlignment - 1)) & ~(nAlignment - 1)) - nPosition;
if (nPadSize > 0)
{
nPosition += nPadSize;
static const char zeroes[32] = { 0 };
while (nPadSize > 0)
{
const size_t n = (nPadSize <= sizeof(zeroes)) ? nPadSize : sizeof(zeroes);
nPadSize -= n;
pFile->Write(zeroes, n);
}
}
}
static void write(XMLBinary::IDataWriter* const pFile, size_t& nPosition, const void* const pData, const size_t nDataSize)
{
pFile->Write(pData, nDataSize);
nPosition += nDataSize;
}
//////////////////////////////////////////////////////////////////////////
bool XMLBinary::CXMLBinaryWriter::WriteNode(IDataWriter* pFile, XmlNodeRef node, bool bNeedSwapEndian, XMLBinary::IFilter* pFilter, string& error)
{
error = "";
// Scan the node tree, building a flat node list, attribute list and string table.
m_nStringDataSize = 0;
if (!CompileTables(node, pFilter, error))
{
return false;
}
static const uint nMaxNodeCount = (NodeIndex) ~0;
if (m_nodes.size() > nMaxNodeCount)
{
error.Format("XMLBinary: Too many nodes: %d (max is %i)", m_nodes.size(), nMaxNodeCount);
return false;
}
// Initialize the file header.
size_t nTheoreticalPosition = 0;
static const size_t nAlignment = sizeof(uint32);
BinaryFileHeader header;
static const char signature[] = "CryXmlB";
COMPILE_TIME_ASSERT(sizeof(signature) == sizeof(header.szSignature));
memcpy(header.szSignature, signature, sizeof(header.szSignature));
nTheoreticalPosition += sizeof(header);
align(nTheoreticalPosition, nAlignment);
header.nNodeTablePosition = nTheoreticalPosition;
header.nNodeCount = int(m_nodes.size());
nTheoreticalPosition += header.nNodeCount * sizeof(Node);
align(nTheoreticalPosition, nAlignment);
header.nChildTablePosition = nTheoreticalPosition;
header.nChildCount = int(m_childs.size());
nTheoreticalPosition += header.nChildCount * sizeof(NodeIndex);
align(nTheoreticalPosition, nAlignment);
header.nAttributeTablePosition = nTheoreticalPosition;
header.nAttributeCount = int(m_attributes.size());
nTheoreticalPosition += header.nAttributeCount * sizeof(Attribute);
align(nTheoreticalPosition, nAlignment);
header.nStringDataPosition = nTheoreticalPosition;
header.nStringDataSize = m_nStringDataSize;
nTheoreticalPosition += header.nStringDataSize;
header.nXMLSize = 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;
// Write out the file header.
write(pFile, nTheoreticalPosition, &header, sizeof(header));
alignWrite(pFile, nTheoreticalPosition, nAlignment);
// Write out the node table.
if (!m_nodes.empty())
{
write(pFile, nTheoreticalPosition, &m_nodes[0], sizeof(m_nodes[0]) * m_nodes.size());
alignWrite(pFile, nTheoreticalPosition, nAlignment);
}
// Write out the children table.
if (!m_childs.empty())
{
write(pFile, nTheoreticalPosition, &m_childs[0], sizeof(m_childs[0]) * m_childs.size());
alignWrite(pFile, nTheoreticalPosition, nAlignment);
}
// Write out the attribute table.
if (!m_attributes.empty())
{
write(pFile, nTheoreticalPosition, &m_attributes[0], sizeof(m_attributes[0]) * m_attributes.size());
alignWrite(pFile, nTheoreticalPosition, nAlignment);
}
// Write out the data of all the m_strings.
for (size_t nString = 0; nString < m_strings.size(); ++nString)
{
pFile->Write(m_strings[nString].c_str(), m_strings[nString].size() + 1);
}
}
return true;
}
bool XMLBinary::CXMLBinaryWriter::CompileTables(XmlNodeRef node, XMLBinary::IFilter* pFilter, string& error)
{
bool ok = CompileTablesForNode(node, -1, pFilter, error);
ok = ok && CompileChildTable(node, pFilter, error);
return ok;
}
//////////////////////////////////////////////////////////////////////////
bool XMLBinary::CXMLBinaryWriter::CompileTablesForNode(XmlNodeRef node, int nParentIndex, XMLBinary::IFilter* pFilter, string& error)
{
// Add the tag to the string table.
int nTagStringOffset = AddString(node->getTag());
// Add the content string to the string table.
int nContentStringOffset = AddString(node->getContent());
// Add all the attributes to the attributes table.
const char* szKey;
const char* szValue;
const int nFirstAttributeIndex = int(m_attributes.size());
for (int i = 0, attrCount = node->getNumAttributes(); i < attrCount; ++i)
{
if (node->getAttributeByIndex(i, &szKey, &szValue) &&
(!pFilter || pFilter->IsAccepted(IFilter::eType_AttributeName, szKey)))
{
// Add the key and the value to the string table.
Attribute attribute;
attribute.nKeyStringOffset = AddString(szKey);
attribute.nValueStringOffset = AddString(szValue);
// Add the attribute to the attribute table.
m_attributes.push_back(attribute);
}
}
const int nAttributeCount = int(m_attributes.size()) - nFirstAttributeIndex;
static const int nMaxAttributeCount = (uint16) ~0;
if (nAttributeCount > nMaxAttributeCount)
{
error.Format("XMLBinary: Too many attributes in a node: %d (max is %i)", nAttributeCount, nMaxAttributeCount);
return false;
}
// Add ourselves to the node list.
const int nIndex = int(m_nodes.size());
{
Node nd;
memset(&nd, 0, sizeof(nd));
nd.nTagStringOffset = nTagStringOffset;
nd.nContentStringOffset = nContentStringOffset;
nd.nParentIndex = nParentIndex;
nd.nFirstAttributeIndex = nFirstAttributeIndex;
nd.nAttributeCount = nAttributeCount;
m_nodes.push_back(nd);
}
m_nodesMap.insert(NodesMap::value_type(node, nIndex));
// Recurse to the child nodes.
int nChildCount = 0;
static const int nMaxChildCount = (uint16) ~0;
for (int nChild = 0, numChilds = node->getChildCount(); nChild < numChilds; ++nChild)
{
XmlNodeRef childNode = node->getChild(nChild);
if (!pFilter || pFilter->IsAccepted(IFilter::eType_ElementName, childNode->getTag()))
{
if (++nChildCount > nMaxChildCount)
{
error.Format("XMLBinary: Too many children in node '%s': %d (max is %i)", childNode->getTag(), nChildCount, nMaxChildCount);
return false;
}
if (!CompileTablesForNode(childNode, nIndex, pFilter, error))
{
return false;
}
}
}
m_nodes[nIndex].nChildCount = nChildCount;
return true;
}
//////////////////////////////////////////////////////////////////////////
bool XMLBinary::CXMLBinaryWriter::CompileChildTable(XmlNodeRef node, XMLBinary::IFilter* pFilter, string& error)
{
const int nIndex = m_nodesMap.find(node)->second; // Assume node always exist in map.
const int nFirstChildIndex = (int)m_childs.size();
Node& nd = m_nodes[nIndex];
nd.nFirstChildIndex = nFirstChildIndex;
int nChildCount = 0;
for (int nChild = 0, numChilds = node->getChildCount(); nChild < numChilds; ++nChild)
{
XmlNodeRef childNode = node->getChild(nChild);
if (!pFilter || pFilter->IsAccepted(IFilter::eType_ElementName, childNode->getTag()))
{
++nChildCount;
const int nChildIndex = m_nodesMap.find(childNode)->second; // Assume node always exist in map.
m_childs.push_back(nChildIndex);
}
}
if (nChildCount != nd.nChildCount)
{
error.Format("XMLBinary: Internal error in CompileChildTable()");
return false;
}
// Recurse to the child nodes.
for (int nChild = 0, numChilds = node->getChildCount(); nChild < numChilds; ++nChild)
{
XmlNodeRef childNode = node->getChild(nChild);
if (!pFilter || pFilter->IsAccepted(IFilter::eType_ElementName, childNode->getTag()))
{
if (!CompileChildTable(childNode, pFilter, error))
{
return false;
}
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
int XMLBinary::CXMLBinaryWriter::AddString(const XmlString& sString)
{
// If we have such string already, then we will re-use its data.
StringMap::const_iterator itStringEntry = m_stringMap.find(sString);
if (itStringEntry == m_stringMap.end())
{
// We don't have such string yet, so we should add it to the tables.
m_strings.push_back(sString);
itStringEntry = m_stringMap.insert(StringMap::value_type(sString, m_nStringDataSize)).first;
m_nStringDataSize += sString.length() + 1;
}
// Return offset of the string in the string data buffer.
return (*itStringEntry).second;
}
@@ -0,0 +1,57 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYSYSTEM_XML_XMLBINARYWRITER_H
#define CRYINCLUDE_CRYSYSTEM_XML_XMLBINARYWRITER_H
#pragma once
#include "IXml.h"
#include "XMLBinaryHeaders.h"
#include <vector>
#include <map>
class IXMLDataSink;
namespace XMLBinary
{
class CXMLBinaryWriter
{
public:
CXMLBinaryWriter();
bool WriteNode(IDataWriter* pFile, XmlNodeRef node, bool bNeedSwapEndian, XMLBinary::IFilter* pFilter, string& error);
private:
bool CompileTables(XmlNodeRef node, XMLBinary::IFilter* pFilter, string& error);
bool CompileTablesForNode(XmlNodeRef node, int nParentIndex, XMLBinary::IFilter* pFilter, string& error);
bool CompileChildTable(XmlNodeRef node, XMLBinary::IFilter* pFilter, string& error);
int AddString(const XmlString& sString);
private:
// tables.
typedef std::map<IXmlNode*, int> NodesMap;
typedef std::map<string, uint> StringMap;
std::vector<Node> m_nodes;
NodesMap m_nodesMap;
std::vector<Attribute> m_attributes;
std::vector<NodeIndex> m_childs;
std::vector<string> m_strings;
StringMap m_stringMap;
uint m_nStringDataSize;
};
}
#endif // CRYINCLUDE_CRYSYSTEM_XML_XMLBINARYWRITER_H
+429
View File
@@ -0,0 +1,429 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "CrySystem_precompiled.h"
#include "XMLPatcher.h"
#include "StringUtils.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 && CryStringUtils::stristr(pForFile, pInFileToPatch) != 0)
{
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,
CryFixedStringT<512>* ioTempString)
{
auto pPak = gEnv->pCryPak;
inIndent = min(inIndent, int(sizeof(k_lotsOfTabs) - 1));
INDENT();
ioTempString->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->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->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;
if (pOrigFileName = strrchr(pInXMLFileName, '/'))
{
pOrigFileName++;
DumpXMLFile(string().Format("PATCH_%s", pOrigFileName), inBefore);
CryFixedStringT<128> newFileName(pOrigFileName);
newFileName.replace(".xml", "_patched.xml");
DumpXMLFile(string().Format("PATCH_%s", newFileName.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)
{
CryFixedStringT<512> tempStr;
DumpXMLNodes(fileHandle, 0, inNode, &tempStr);
pIPak->FClose(fileHandle);
}
}
#endif
+85
View File
@@ -0,0 +1,85 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#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,
CryFixedStringT<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
+718
View File
@@ -0,0 +1,718 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "CrySystem_precompiled.h"
#include <IXml.h>
#include "xml.h"
#include "XmlUtils.h"
#include "ReadWriteXMLSink.h"
#include "../SimpleStringPool.h"
#include "SerializeXMLReader.h"
#include "SerializeXMLWriter.h"
#include "XMLBinaryWriter.h"
#include "XMLBinaryReader.h"
#include "XMLPatcher.h"
#include <md5.h>
//////////////////////////////////////////////////////////////////////////
CXmlNode_PoolAlloc* g_pCXmlNode_PoolAlloc = 0;
#ifdef CRY_COLLECT_XML_NODE_STATS
SXmlNodeStats* g_pCXmlNode_Stats = 0;
#endif
extern bool g_bEnableBinaryXmlLoading;
//////////////////////////////////////////////////////////////////////////
CXmlUtils::CXmlUtils(ISystem* pSystem)
{
m_pSystem = pSystem;
m_pSystem->GetISystemEventDispatcher()->RegisterListener(this);
// create IReadWriteXMLSink object
m_pReadWriteXMLSink = new CReadWriteXMLSink();
g_pCXmlNode_PoolAlloc = new CXmlNode_PoolAlloc;
#ifdef CRY_COLLECT_XML_NODE_STATS
g_pCXmlNode_Stats = new SXmlNodeStats();
#endif
m_pStatsXmlNodePool = 0;
#ifndef _RELEASE
m_statsThreadOwner = CryGetCurrentThreadId();
#endif
m_pXMLPatcher = NULL;
}
//////////////////////////////////////////////////////////////////////////
CXmlUtils::~CXmlUtils()
{
m_pSystem->GetISystemEventDispatcher()->RemoveListener(this);
delete g_pCXmlNode_PoolAlloc;
#ifdef CRY_COLLECT_XML_NODE_STATS
delete g_pCXmlNode_Stats;
#endif
SAFE_DELETE(m_pStatsXmlNodePool);
SAFE_DELETE(m_pXMLPatcher);
}
//////////////////////////////////////////////////////////////////////////
IXmlParser* CXmlUtils::CreateXmlParser()
{
const bool bReuseStrings = false; //TODO: do we ever want to reuse strings here?
return new XmlParser(bReuseStrings);
}
//////////////////////////////////////////////////////////////////////////
XmlNodeRef CXmlUtils::LoadXmlFromFile(const char* sFilename, bool bReuseStrings, bool bEnablePatching)
{
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;
}
//////////////////////////////////////////////////////////////////////////
XmlNodeRef CXmlUtils::LoadXmlFromBuffer(const char* buffer, size_t size, bool bReuseStrings, bool bSuppressWarnings)
{
XmlParser parser(bReuseStrings);
XmlNodeRef node = parser.ParseBuffer(buffer, size, true, bSuppressWarnings);
return node;
}
void GetMD5(const char* pSrcBuffer, int nSrcSize, char signatureMD5[16])
{
MD5Context md5c;
MD5Init(&md5c);
MD5Update(&md5c, (unsigned char*)pSrcBuffer, nSrcSize);
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(), 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
{
public:
CXmlSerializer()
: m_nRefCount(0)
, m_pReaderImpl(NULL)
, m_pReaderSer(NULL)
, m_pWriterSer(NULL)
, m_pWriterImpl(NULL)
{
}
~CXmlSerializer()
{
ClearAll();
}
void ClearAll()
{
SAFE_DELETE(m_pReaderSer);
SAFE_DELETE(m_pReaderImpl);
SAFE_DELETE(m_pWriterSer);
SAFE_DELETE(m_pWriterImpl);
}
//////////////////////////////////////////////////////////////////////////
virtual void AddRef() { ++m_nRefCount; }
virtual void Release()
{
if (--m_nRefCount <= 0)
{
delete this;
}
}
virtual ISerialize* GetWriter(XmlNodeRef& node)
{
ClearAll();
m_pWriterImpl = new CSerializeXMLWriterImpl(node);
m_pWriterSer = new CSimpleSerializeWithDefaults<CSerializeXMLWriterImpl>(*m_pWriterImpl);
return m_pWriterSer;
}
virtual ISerialize* GetReader(XmlNodeRef& node)
{
ClearAll();
m_pReaderImpl = new CSerializeXMLReaderImpl(node);
m_pReaderSer = new CSimpleSerializeWithDefaults<CSerializeXMLReaderImpl>(*m_pReaderImpl);
return m_pReaderSer;
}
virtual void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->Add(*this);
pSizer->AddObject(m_pReaderImpl);
pSizer->AddObject(m_pWriterImpl);
}
//////////////////////////////////////////////////////////////////////////
private:
int m_nRefCount;
CSerializeXMLReaderImpl* m_pReaderImpl;
CSimpleSerializeWithDefaults<CSerializeXMLReaderImpl>* m_pReaderSer;
CSerializeXMLWriterImpl* m_pWriterImpl;
CSimpleSerializeWithDefaults<CSerializeXMLWriterImpl>* m_pWriterSer;
};
//////////////////////////////////////////////////////////////////////////
IXmlSerializer* CXmlUtils::CreateXmlSerializer()
{
return new CXmlSerializer;
}
//////////////////////////////////////////////////////////////////////////
void CXmlUtils::GetMemoryUsage(ICrySizer* pSizer)
{
{
SIZER_COMPONENT_NAME(pSizer, "Nodes");
g_pCXmlNode_PoolAlloc->GetMemoryUsage(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
}
//////////////////////////////////////////////////////////////////////////
void CXmlUtils::OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wparam, [[maybe_unused]] UINT_PTR lparam)
{
switch (event)
{
case ESYSTEM_EVENT_LEVEL_POST_UNLOAD:
case ESYSTEM_EVENT_LEVEL_LOAD_END:
g_pCXmlNode_PoolAlloc->FreeMemoryIfEmpty();
STLALLOCATOR_CLEANUP;
break;
}
}
//////////////////////////////////////////////////////////////////////////
class CXmlBinaryDataWriterFile
: public XMLBinary::IDataWriter
{
public:
CXmlBinaryDataWriterFile(const char* file)
{
m_fileHandle = gEnv->pCryPak->FOpen(file, "wb");
}
~CXmlBinaryDataWriterFile()
{
if (m_fileHandle != AZ::IO::InvalidHandle)
{
gEnv->pCryPak->FClose(m_fileHandle);
}
};
virtual bool IsOk()
{
return m_fileHandle != AZ::IO::InvalidHandle;
}
;
virtual void Write(const void* pData, size_t size)
{
if (m_fileHandle != AZ::IO::InvalidHandle)
{
gEnv->pCryPak->FWrite(pData, size, 1, m_fileHandle);
}
}
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;
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();
virtual void Release();
virtual bool Begin(XmlNodeRef rootNode);
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;
XmlNodeRef m_tableNode;
XmlNodeRef m_rowNode;
float m_currentRowHeight;
int m_rowNodeIndex;
int m_row;
int m_columnNodeIndex; // used if m_bExcel == true
int m_column;
size_t m_rowTextSize; // used if m_bExcel == false
size_t m_rowTextPos; // used if m_bExcel == false
};
//////////////////////////////////////////////////////////////////////////
CXmlTableReader::CXmlTableReader()
{
}
//////////////////////////////////////////////////////////////////////////
CXmlTableReader::~CXmlTableReader()
{
}
//////////////////////////////////////////////////////////////////////////
void CXmlTableReader::Release()
{
delete this;
}
//////////////////////////////////////////////////////////////////////////
bool CXmlTableReader::Begin(XmlNodeRef rootNode)
{
m_tableNode = 0;
if (!rootNode)
{
return false;
}
XmlNodeRef worksheetNode = rootNode->findChild("Worksheet");
if (worksheetNode)
{
m_bExcel = true;
m_tableNode = worksheetNode->findChild("Table");
}
else
{
m_bExcel = false;
m_tableNode = rootNode->findChild("Table");
}
m_rowNode = 0;
m_rowNodeIndex = -1;
m_row = -1;
return (m_tableNode != 0);
}
//////////////////////////////////////////////////////////////////////////
int CXmlTableReader::GetEstimatedRowCount()
{
if (!m_tableNode)
{
return -1;
}
return m_tableNode->getChildCount();
}
//////////////////////////////////////////////////////////////////////////
bool CXmlTableReader::ReadRow(int& rowIndex)
{
m_currentRowHeight = 0.0f;
if (!m_tableNode)
{
return false;
}
m_columnNodeIndex = -1;
m_column = -1;
const int rowNodeCount = m_tableNode->getChildCount();
if (m_bExcel)
{
for (;; )
{
if (++m_rowNodeIndex >= rowNodeCount)
{
m_rowNodeIndex = rowNodeCount;
return false;
}
m_rowNode = m_tableNode->getChild(m_rowNodeIndex);
if (!m_rowNode)
{
m_rowNodeIndex = rowNodeCount;
return false;
}
if (!m_rowNode->isTag("Row"))
{
m_rowNode = 0;
continue;
}
++m_row;
int index = 0;
if (m_rowNode->getAttr("ss:Index", index))
{
--index; // one-based -> zero-based
if (index < m_row)
{
m_rowNodeIndex = rowNodeCount;
m_rowNode = 0;
return false;
}
m_row = index;
}
float height;
if (m_rowNode->getAttr("ss:Height", height))
{
m_currentRowHeight = height;
}
rowIndex = m_row;
return true;
}
}
{
m_rowTextSize = 0;
m_rowTextPos = 0;
if (++m_rowNodeIndex >= rowNodeCount)
{
m_rowNodeIndex = rowNodeCount;
return false;
}
m_rowNode = m_tableNode->getChild(m_rowNodeIndex);
if (!m_rowNode)
{
m_rowNodeIndex = rowNodeCount;
return false;
}
const char* const pContent = m_rowNode->getContent();
if (pContent)
{
m_rowTextSize = strlen(pContent);
}
m_row = m_rowNodeIndex;
rowIndex = m_rowNodeIndex;
return true;
}
}
//////////////////////////////////////////////////////////////////////////
bool CXmlTableReader::ReadCell(int& columnIndex, const char*& pContent, size_t& contentSize)
{
pContent = 0;
contentSize = 0;
if (!m_tableNode)
{
return false;
}
if (!m_rowNode)
{
return false;
}
if (m_bExcel)
{
const int columnNodeCount = m_rowNode->getChildCount();
for (;; )
{
if (++m_columnNodeIndex >= columnNodeCount)
{
m_columnNodeIndex = columnNodeCount;
return false;
}
XmlNodeRef columnNode = m_rowNode->getChild(m_columnNodeIndex);
if (!columnNode)
{
m_columnNodeIndex = columnNodeCount;
return false;
}
if (!columnNode->isTag("Cell"))
{
continue;
}
++m_column;
int index = 0;
if (columnNode->getAttr("ss:Index", index))
{
--index; // one-based -> zero-based
if (index < m_column)
{
m_columnNodeIndex = columnNodeCount;
return false;
}
m_column = index;
}
columnIndex = m_column;
XmlNodeRef dataNode = columnNode->findChild("Data");
if (dataNode)
{
pContent = dataNode->getContent();
if (pContent)
{
contentSize = strlen(pContent);
}
}
return true;
}
}
{
if (m_rowTextPos >= m_rowTextSize)
{
return false;
}
const char* const pRowContent = m_rowNode->getContent();
if (!pRowContent)
{
m_rowTextPos = m_rowTextSize;
return false;
}
pContent = &pRowContent[m_rowTextPos];
columnIndex = ++m_column;
for (;; )
{
char c = pRowContent[m_rowTextPos++];
if ((c == '\n') || (c == '\0'))
{
return true;
}
if (c == '\r')
{
// ignore all '\r' chars
for (;; )
{
c = pRowContent[m_rowTextPos++];
if ((c == '\n') || (c == '\0'))
{
return true;
}
if (c != '\r')
{
// broken data. '\r' expected to be followed by '\n' or '\0'.
contentSize = 0;
m_rowTextPos = m_rowTextSize;
return false;
}
}
}
++contentSize;
}
}
}
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);
}
}
+106
View File
@@ -0,0 +1,106 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYSYSTEM_XML_XMLUTILS_H
#define CRYINCLUDE_CRYSYSTEM_XML_XMLUTILS_H
#pragma once
#include "ISystem.h"
#ifdef _RELEASE
#define CHECK_STATS_THREAD_OWNERSHIP()
#else
#define CHECK_STATS_THREAD_OWNERSHIP() if (m_statsThreadOwner != CryGetCurrentThreadId()) {__debugbreak(); }
#endif
class CXmlNodePool;
class CXMLPatcher;
//////////////////////////////////////////////////////////////////////////
// Implements IXmlUtils interface.
//////////////////////////////////////////////////////////////////////////
class CXmlUtils
: public IXmlUtils
, public ISystemEventListener
{
public:
CXmlUtils(ISystem* pSystem);
virtual ~CXmlUtils();
//////////////////////////////////////////////////////////////////////////
// IXmlUtils
//////////////////////////////////////////////////////////////////////////
virtual IXmlParser* CreateXmlParser();
// Load xml from file, returns 0 if load failed.
virtual XmlNodeRef LoadXmlFromFile(const char* sFilename, bool bReuseStrings = false, bool bEnablePatching = true);
// 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();
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// ISystemEventListener
//////////////////////////////////////////////////////////////////////////
virtual void OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam);
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
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
@@ -0,0 +1,19 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
XMLBinaryNode.cpp
XMLBinaryNode.h
XMLBinaryReader.cpp
XMLBinaryReader.h
XMLBinaryWriter.cpp
XMLBinaryWriter.h
)
File diff suppressed because it is too large Load Diff
+443
View File
@@ -0,0 +1,443 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYSYSTEM_XML_XML_H
#define CRYINCLUDE_CRYSYSTEM_XML_XML_H
#pragma once
#include <algorithm>
#include <PoolAllocator.h>
#include <stack>
#include "IXml.h"
// track some XML stats. only to find persistent XML nodes in the system
// slow, so disable by default
//#define CRY_COLLECT_XML_NODE_STATS
//#undef CRY_COLLECT_XML_NODE_STATS
struct IXmlStringPool
{
public:
IXmlStringPool() { m_refCount = 0; }
virtual ~IXmlStringPool() {};
void AddRef() { m_refCount++; };
void Release()
{
if (--m_refCount <= 0)
{
delete this;
}
};
virtual const char* AddString(const char* str) = 0;
virtual void GetMemoryUsage(ICrySizer* pSizer) const = 0;
private:
int m_refCount;
};
/************************************************************************/
/* XmlParser class, Parse xml and return root xml node if success. */
/************************************************************************/
class XmlParser
: public IXmlParser
{
public:
explicit XmlParser(bool bReuseStrings);
~XmlParser();
void AddRef()
{
++m_nRefCount;
}
void Release()
{
if (--m_nRefCount <= 0)
{
delete this;
}
}
virtual XmlNodeRef ParseFile(const char* filename, bool bCleanPools);
virtual XmlNodeRef ParseBuffer(const char* buffer, int nBufLen, bool bCleanPools, bool bSuppressWarnings = false);
const char* getErrorString() const { return m_errorString; }
void GetMemoryUsage(ICrySizer* pSizer) const;
private:
int m_nRefCount;
XmlString m_errorString;
class XmlParserImp* m_pImpl;
};
// Compare function for string comparasion, can be strcmp or _stricmp
typedef int (__cdecl * XmlStrCmpFunc)(const char* str1, const char* str2);
extern XmlStrCmpFunc g_pXmlStrCmp;
//////////////////////////////////////////////////////////////////////////
// XmlAttribute class
//////////////////////////////////////////////////////////////////////////
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; }
bool operator!=(const XmlAttribute& attr) const { return g_pXmlStrCmp(key, attr.key) != 0; }
};
//! Xml node attributes class.
typedef std::vector<XmlAttribute> XmlAttributes;
typedef XmlAttributes::iterator XmlAttrIter;
typedef XmlAttributes::const_iterator XmlAttrConstIter;
/**
******************************************************************************
* CXmlNode class
* Never use CXmlNode directly instead use reference counted XmlNodeRef.
******************************************************************************
*/
class CXmlNode
: public IXmlNode
{
public:
//! Constructor.
CXmlNode();
CXmlNode(const char* tag, bool bReuseStrings, bool bIsProcessingInstruction = false);
//! Destructor.
~CXmlNode();
// collect allocated memory informations
void GetMemoryUsage(ICrySizer* pSizer) const;
//////////////////////////////////////////////////////////////////////////
// Custom new/delete with pool allocator.
//////////////////////////////////////////////////////////////////////////
//void* operator new( size_t nSize );
//void operator delete( void *ptr );
virtual void DeleteThis();
//! Create new XML node.
XmlNodeRef createNode(const char* tag);
//! Get XML node tag.
const char* getTag() const { return m_tag; };
void setTag(const char* tag);
//! Return true if given tag equal to node tag.
bool isTag(const char* tag) const;
//! Get XML Node attributes.
virtual int getNumAttributes() const { return m_pAttributes ? (int)m_pAttributes->size() : 0; };
//! Return attribute key and value by attribute index.
virtual bool getAttributeByIndex(int index, const char** key, const char** value);
//! Return attribute key and value by attribute index, string version.
virtual bool getAttributeByIndex(int index, XmlString& key, XmlString& value);
virtual void copyAttributes(XmlNodeRef fromNode);
virtual void shareChildren(const XmlNodeRef& fromNode);
//! Get XML Node attribute for specified key.
const char* getAttr(const char* key) const;
//! Get XML Node attribute for specified key.
// Returns true if the attribute existes, alse otherwise.
bool getAttr(const char* key, const char** value) const;
//! Check if attributes with specified key exist.
bool haveAttr(const char* key) const;
//! Creates new xml node and add it to childs list.
XmlNodeRef newChild(const char* tagName);
//! Adds new child node.
void addChild(const XmlNodeRef& node);
//! Remove child node.
void removeChild(const XmlNodeRef& node);
void insertChild(int nIndex, const XmlNodeRef& node);
void replaceChild(int nIndex, const XmlNodeRef& node);
//! Remove all child nodes.
void removeAllChilds();
//! Get number of child XML nodes.
int getChildCount() const { return m_pChilds ? (int)m_pChilds->size() : 0; };
//! Get XML Node child nodes.
XmlNodeRef getChild(int i) const;
//! Find node with specified tag.
XmlNodeRef findChild(const char* tag) const;
void deleteChild(const char* tag);
void deleteChildAt(int nIndex);
//! Get parent XML node.
XmlNodeRef getParent() const { return m_parent; }
void setParent(const XmlNodeRef& inRef);
//! Returns content of this node.
const char* getContent() const { return m_content; };
void setContent(const char* str);
XmlNodeRef clone();
//! Returns line number for XML tag.
int getLine() const { return m_line; };
//! Set line number in xml.
void setLine(int line) { m_line = line; };
//! Returns XML of this node and sub nodes.
virtual IXmlStringData* getXMLData(int nReserveMem = 0) const;
XmlString getXML(int level = 0) const;
XmlString getXMLUnsafe(int level, char* tmpBuffer, uint32 sizeOfTmpBuffer) const;
bool saveToFile(const char* fileName); // saves in one huge chunk
bool saveToFile(const char* fileName, size_t chunkSizeBytes, AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle); // save in small memory chunks
//! Set new XML Node attribute (or override attribute with same key).
void setAttr(const char* key, const char* value);
void setAttr(const char* key, int value);
void setAttr(const char* key, unsigned int value);
void setAttr(const char* key, int64 value);
void setAttr(const char* key, uint64 value, bool useHexFormat = true);
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.
void delAttr(const char* key);
//! Remove all node attributes.
void removeAllAttributes();
//! Get attribute value of node.
bool getAttr(const char* key, int& value) const;
bool getAttr(const char* key, unsigned int& value) const;
bool getAttr(const char* key, int64& value) const;
bool getAttr(const char* key, uint64& value, bool useHexFormat = true /*ignored*/) const;
bool getAttr(const char* key, float& value) const;
bool getAttr(const char* key, double& value) const;
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;
protected:
private:
CXmlNode(const CXmlNode&);
CXmlNode& operator = (const CXmlNode&);
private:
void ReleaseChild(IXmlNode* pChild);
void removeAllChildsImpl();
void AddToXmlString(XmlString& xml, int level, AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle, size_t chunkSizeBytes = 0) const;
char* AddToXmlStringUnsafe(char* xml, int level, char* endPtr, AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle, size_t chunkSizeBytes = 0) const;
XmlString MakeValidXmlString(const XmlString& xml) const;
bool IsValidXmlString(const char* str) const;
XmlAttrConstIter GetAttrConstIterator(const char* key) const
{
assert(m_pAttributes);
XmlAttribute tempAttr;
tempAttr.key = key;
XmlAttributes::const_iterator it = std::find(m_pAttributes->begin(), m_pAttributes->end(), tempAttr);
return it;
/*
XmlAttributes::const_iterator it = std::lower_bound( m_attributes.begin(),m_attributes.end(),tempAttr );
if (it != m_attributes.end() && _stricmp(it->key,key) == 0)
return it;
return m_attributes.end();
*/
}
XmlAttrIter GetAttrIterator(const char* key)
{
assert(m_pAttributes);
XmlAttribute tempAttr;
tempAttr.key = key;
XmlAttributes::iterator it = std::find(m_pAttributes->begin(), m_pAttributes->end(), tempAttr);
return it;
// XmlAttributes::iterator it = std::lower_bound( m_attributes.begin(),m_attributes.end(),tempAttr );
//if (it != m_attributes.end() && _stricmp(it->key,key) == 0)
//return it;
//return m_attributes.end();
}
const char* GetValue(const char* key) const
{
if (m_pAttributes)
{
XmlAttrConstIter it = GetAttrConstIterator(key);
if (it != m_pAttributes->end())
{
return it->value;
}
}
return 0;
}
protected:
// String pool used by this node.
IXmlStringPool* m_pStringPool;
//! Tag of XML node.
const char* m_tag;
private:
//! Content of XML node.
const char* m_content;
//! Parent XML node.
IXmlNode* m_parent;
//typedef DynArray<CXmlNode*,XmlDynArrayAlloc> XmlNodes;
typedef std::vector<IXmlNode*> XmlNodes;
//XmlNodes m_childs;
XmlNodes* m_pChilds;
//! Xml node attributes.
//XmlAttributes m_attributes;
XmlAttributes* m_pAttributes;
//! Line in XML file where this node firstly appeared (useful for debugging).
int m_line;
bool m_isProcessingInstruction;
friend class XmlParserImp;
};
typedef stl::PoolAllocatorNoMT<sizeof(CXmlNode)> CXmlNode_PoolAlloc;
extern CXmlNode_PoolAlloc* g_pCXmlNode_PoolAlloc;
#ifdef CRY_COLLECT_XML_NODE_STATS
typedef std::set<CXmlNode*> TXmlNodeSet; // yes, slow, but really only for one-shot debugging
struct SXmlNodeStats
{
SXmlNodeStats()
: nAllocs(0)
, nFrees(0) {}
TXmlNodeSet nodeSet;
uint32 nAllocs;
uint32 nFrees;
};
extern SXmlNodeStats* g_pCXmlNode_Stats;
#endif
/*
//////////////////////////////////////////////////////////////////////////
inline void* CXmlNode::operator new( size_t nSize )
{
void *ptr = g_pCXmlNode_PoolAlloc->Allocate();
if (ptr)
{
memset( ptr,0,nSize ); // Clear objects memory.
#ifdef CRY_COLLECT_XML_NODE_STATS
g_pCXmlNode_Stats->nodeSet.insert(reinterpret_cast<CXmlNode*> (ptr));
++g_pCXmlNode_Stats->nAllocs;
#endif
}
return ptr;
}
//////////////////////////////////////////////////////////////////////////
inline void CXmlNode::operator delete( void *ptr )
{
if (ptr)
{
g_pCXmlNode_PoolAlloc->Deallocate(ptr);
#ifdef CRY_COLLECT_XML_NODE_STATS
g_pCXmlNode_Stats->nodeSet.erase(reinterpret_cast<CXmlNode*> (ptr));
++g_pCXmlNode_Stats->nFrees;
#endif
}
}
*/
//////////////////////////////////////////////////////////////////////////
//
// Reusable XmlNode for XmlNode pool with shared xml string pool
//
//////////////////////////////////////////////////////////////////////////
class CXmlNodePool;
class CXmlNodeReuse
: public CXmlNode
{
public:
CXmlNodeReuse(const char* tag, CXmlNodePool* pPool);
virtual void Release();
protected:
CXmlNodePool* m_pPool;
};
//////////////////////////////////////////////////////////////////////////
//
// Pool of reusable XML nodes with shared string pool
//
//////////////////////////////////////////////////////////////////////////
class CXmlNodePool
{
public:
CXmlNodePool(unsigned int nBlockSize, bool bReuseStrings);
virtual ~CXmlNodePool();
XmlNodeRef GetXmlNode(const char* sNodeName);
bool empty() const { return (m_nAllocated == 0); }
protected:
virtual void OnRelease(int iRefCount, void* pThis);
IXmlStringPool* GetStringPool() { return m_pStringPool; }
private:
friend class CXmlNodeReuse;
IXmlStringPool* m_pStringPool;
unsigned int m_nAllocated;
std::stack<CXmlNodeReuse*> m_pNodePool;
};
#endif // CRYINCLUDE_CRYSYSTEM_XML_XML_H
+21
View File
@@ -0,0 +1,21 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#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