You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
687 lines
20 KiB
C++
687 lines
20 KiB
C++
/*
|
|
* 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, [[maybe_unused]] const char* name, XmlNodeRef& definition, [[maybe_unused]] XmlNodeRef& data)
|
|
{
|
|
if (XmlNodeRef enumNode = definition->findChild("Enum"))
|
|
{
|
|
// If strict mode is off, then no need to check the enum value
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool LoadProperty(const SParseParams& parseParams, XmlNodeRef& definition, XmlNodeRef& data, IReadXMLSink* pSink)
|
|
{
|
|
const char* name = definition->getAttr("name");
|
|
if (0 == strlen(name))
|
|
{
|
|
CryLog("Property has no name");
|
|
return false;
|
|
}
|
|
|
|
const char* type = definition->getAttr("type");
|
|
if (0 == strlen(type))
|
|
{
|
|
CryLog("Property '%s' has no type", type);
|
|
return false;
|
|
}
|
|
|
|
XmlNodeRef dataToRead = data;
|
|
if (!pSink->IsCreationMode())
|
|
{
|
|
// This check is done so the data xml can specify child elements instead of attributes if desired,
|
|
// since the rest of the code assume only attributes
|
|
if (XmlNodeRef childRef = data->findChild(name))
|
|
{
|
|
if (data->haveAttr(name))
|
|
{
|
|
CryLog("Duplicate definition (attribute and element) for %s", name);
|
|
return false;
|
|
}
|
|
if (childRef->getChildCount())
|
|
{
|
|
CryLog("Property-style elements can not have children (property was %s)", name);
|
|
return false;
|
|
}
|
|
|
|
dataToRead = GetISystem()->CreateXmlNode(data->getTag());
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|