summaryrefslogtreecommitdiffstats
path: root/src/Runtime/ogl-runtime/src/dm/systems/Qt3DSDMXML.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Runtime/ogl-runtime/src/dm/systems/Qt3DSDMXML.cpp')
-rw-r--r--src/Runtime/ogl-runtime/src/dm/systems/Qt3DSDMXML.cpp1253
1 files changed, 1253 insertions, 0 deletions
diff --git a/src/Runtime/ogl-runtime/src/dm/systems/Qt3DSDMXML.cpp b/src/Runtime/ogl-runtime/src/dm/systems/Qt3DSDMXML.cpp
new file mode 100644
index 00000000..2055adf1
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/dm/systems/Qt3DSDMXML.cpp
@@ -0,0 +1,1253 @@
+/****************************************************************************
+**
+** Copyright (C) 1993-2009 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "Qt3DSDMPrefix.h"
+#include "Qt3DSDMXML.h"
+#include "foundation/Qt3DSPool.h"
+#include "foundation/Qt3DSAtomic.h"
+#include "foundation/Qt3DSRefCounted.h"
+#include "Qt3DSDMStringTable.h"
+#include "Qt3DSDMWStrOpsImpl.h"
+#include <memory>
+#include "foundation/StrConvertUTF.h"
+#include "foundation/StringTable.h"
+#ifdef QT3DS_VC
+#include <winsock2.h>
+#include <windows.h> //output debug string
+#endif
+
+#include <QtCore/qxmlstream.h>
+
+typedef char XML_Char;
+typedef char XML_LChar;
+
+using namespace qt3dsdm;
+using std::shared_ptr;
+using namespace qt3ds::foundation;
+using qt3ds::foundation::Pool;
+
+#define QT3DSXML_FOREACH(idxnm, val) \
+ for (QT3DSU32 idxnm = 0, __numItems = (QT3DSU32)val; idxnm < __numItems; ++idxnm)
+
+namespace qt3dsdm {
+
+// All names are string table values so we can do straight
+// pointer comparisons on them, we don't have the compare their
+// values.
+struct SDOMAttribute
+{
+ TXMLCharPtr m_Name;
+ TXMLCharPtr m_Value;
+ SDOMAttribute *m_NextAttribute;
+
+ SDOMAttribute(TXMLCharPtr nm, TXMLCharPtr val)
+ : m_Name(nm)
+ , m_Value(val)
+ , m_NextAttribute(NULL)
+ {
+ }
+};
+
+struct SDOMElement
+{
+ TXMLCharPtr m_Name;
+ SDOMAttribute *m_FirstAttribute;
+ SDOMAttribute *m_LastAttribute;
+ SDOMElement *m_Parent;
+ SDOMElement *m_FirstChild;
+ SDOMElement *m_LastChild;
+ SDOMElement *m_NextSibling;
+ TXMLCharPtr m_Value;
+
+ SDOMElement(TXMLCharPtr nm)
+ : m_Name(nm)
+ , m_FirstAttribute(NULL)
+ , m_LastAttribute(NULL)
+ , m_Parent(NULL)
+ , m_FirstChild(NULL)
+ , m_LastChild(NULL)
+ , m_NextSibling(NULL)
+ , m_Value("")
+ {
+ }
+
+ void AddAttribute(SDOMAttribute &att)
+ {
+ if (m_LastAttribute) {
+ m_LastAttribute->m_NextAttribute = &att;
+ m_LastAttribute = &att;
+ } else {
+ QT3DS_ASSERT(m_FirstAttribute == NULL);
+ m_FirstAttribute = m_LastAttribute = &att;
+ }
+ }
+ // Used to ensure duplicate attributes can't happen
+ void SetAttributeValue(TXMLCharPtr inName, TXMLCharPtr inValue, IDOMFactory &inFactory,
+ const SDOMFlags &inFlags)
+ {
+ inName = inFactory.GetStringTable()->RegisterStr(inName);
+ SDOMAttribute *att = FindAttribute(inName, inFlags);
+ if (att) {
+ att->m_Value = inFactory.RegisterValue(inValue);
+ } else {
+ AddAttribute(*inFactory.NextAttribute(inName, inValue));
+ }
+ }
+ void SetAttributeValue(TWideXMLCharPtr inName, TWideXMLCharPtr inValue, IDOMFactory &inFactory,
+ const SDOMFlags &inFlags)
+ {
+ TXMLCharPtr theName = inFactory.GetStringTable()->GetNarrowStr(inName);
+ SDOMAttribute *att = FindAttribute(theName, inFlags);
+ if (att) {
+ att->m_Value = inFactory.RegisterValue(inValue);
+ } else {
+ AddAttribute(
+ *inFactory.NextAttribute(inFactory.GetStringTable()->GetWideStr(inName), inValue));
+ }
+ }
+ const SDOMAttribute *FindAttribute(TXMLCharPtr nm, const SDOMFlags &inFlags) const
+ {
+ return const_cast<SDOMElement *>(this)->FindAttribute(nm, inFlags);
+ }
+ SDOMAttribute *FindAttribute(TXMLCharPtr nm, const SDOMFlags &inFlags)
+ {
+ for (SDOMAttribute *att = m_FirstAttribute; att != NULL; att = att->m_NextAttribute) {
+ if (att->m_Name == nm)
+ return att;
+ else if (inFlags.CaselessAttributes() && AreEqualCaseless(nm, att->m_Name))
+ return att;
+ }
+ return NULL;
+ }
+ void RemoveAttribute(TXMLCharPtr nm, const SDOMFlags &inFlags)
+ {
+ SDOMAttribute *preatt = m_FirstAttribute;
+ for (SDOMAttribute *att = m_FirstAttribute; att != NULL;
+ preatt = att, att = att->m_NextAttribute) {
+ if (att->m_Name == nm
+ || (inFlags.CaselessAttributes() && AreEqualCaseless(nm, att->m_Name))) {
+ if (att == m_FirstAttribute) {
+ m_FirstAttribute = att->m_NextAttribute;
+ } else {
+ preatt->m_NextAttribute = att->m_NextAttribute;
+ if (att == m_LastAttribute)
+ m_LastAttribute = preatt;
+ }
+
+ att->m_NextAttribute = NULL;
+ }
+ }
+ }
+ TXMLCharPtr GetAttributeValue(TXMLCharPtr nm, SDOMFlags &inFlags) const
+ {
+ const SDOMAttribute *att = FindAttribute(nm, inFlags);
+ if (att)
+ return att->m_Value;
+ return NULL;
+ }
+ void AddChild(SDOMElement &elem)
+ {
+ elem.m_Parent = this;
+ if (m_LastChild) {
+ m_LastChild->m_NextSibling = &elem;
+ m_LastChild = &elem;
+ } else {
+ QT3DS_ASSERT(m_FirstChild == NULL);
+ m_FirstChild = m_LastChild = &elem;
+ }
+ }
+ SDOMElement *FindPreviousChild(SDOMElement &elem)
+ {
+ if (&elem == m_FirstChild)
+ return NULL;
+ // Find the previous sibling.
+ SDOMElement *theChild = m_FirstChild;
+ // Empty loop intentional
+ for (; theChild && theChild->m_NextSibling != &elem; theChild = theChild->m_NextSibling) {
+ }
+
+ return theChild;
+ }
+ void RemoveChild(SDOMElement &elem)
+ {
+ if (elem.m_Parent != this) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ elem.m_Parent = NULL;
+ if (&elem == m_FirstChild) {
+ m_FirstChild = elem.m_NextSibling;
+ } else {
+ SDOMElement *theChild(FindPreviousChild(elem));
+ QT3DS_ASSERT(theChild);
+ if (theChild) {
+ theChild->m_NextSibling = elem.m_NextSibling;
+ if (&elem == m_LastChild)
+ m_LastChild = theChild;
+ }
+ }
+ elem.m_NextSibling = NULL;
+ }
+
+ void ReplaceChild(SDOMElement &inChild, SDOMElement &inReplacement)
+ {
+ inChild.m_Parent = NULL;
+ if (&inChild == m_FirstChild)
+ m_FirstChild = &inReplacement;
+ else {
+ SDOMElement *theChild(FindPreviousChild(inChild));
+ QT3DS_ASSERT(theChild);
+ if (theChild) {
+ theChild->m_NextSibling = &inReplacement;
+ if (&inChild == m_LastChild)
+ m_LastChild = &inReplacement;
+ }
+ }
+ inReplacement.m_NextSibling = inChild.m_NextSibling;
+ inReplacement.m_Parent = this;
+ inChild.m_NextSibling = NULL;
+ }
+
+ void InsertChildBefore(SDOMElement &elem, SDOMElement &theSibling)
+ {
+ // Ensure elem isn't in the graph.
+ QT3DS_ASSERT(elem.m_Parent == NULL);
+ QT3DS_ASSERT(elem.m_NextSibling == NULL);
+ elem.m_Parent = this;
+ if (&theSibling == m_FirstChild)
+ m_FirstChild = &elem;
+ else {
+ SDOMElement *thePrevious = FindPreviousChild(theSibling);
+ QT3DS_ASSERT(thePrevious);
+ if (thePrevious)
+ thePrevious->m_NextSibling = &elem;
+ }
+
+ elem.m_NextSibling = &theSibling;
+ }
+ QT3DSU32 GetNumChildren(TXMLCharPtr inChildName, const SDOMFlags &inFlags) const
+ {
+ QT3DSU32 idx = 0;
+ for (SDOMElement *elem = m_FirstChild; elem != NULL; elem = elem->m_NextSibling) {
+ if (elem->m_Name == inChildName)
+ ++idx;
+ else if (inFlags.CaselessElements() && AreEqualCaseless(inChildName, elem->m_Name))
+ ++idx;
+ }
+ return idx;
+ }
+ QT3DSU32 GetNumChildren() const
+ {
+ QT3DSU32 idx = 0;
+ for (SDOMElement *elem = m_FirstChild; elem != NULL; elem = elem->m_NextSibling)
+ ++idx;
+ return idx;
+ }
+ SDOMElement *FindChildByName(TXMLCharPtr nm, const SDOMFlags &inFlags) const
+ {
+ for (SDOMElement *elem = m_FirstChild; elem != NULL; elem = elem->m_NextSibling) {
+ if (elem->m_Name == nm)
+ return elem;
+ else if (inFlags.CaselessElements() && AreEqualCaseless(nm, elem->m_Name))
+ return elem;
+ }
+ return NULL;
+ }
+ SDOMElement *FindNextSiblingByName(TXMLCharPtr nm, const SDOMFlags &inFlags) const
+ {
+ for (SDOMElement *elem = m_NextSibling; elem != NULL; elem = elem->m_NextSibling) {
+ if (elem->m_Name == nm)
+ return elem;
+ else if (inFlags.CaselessElements() && AreEqualCaseless(nm, elem->m_Name))
+ return elem;
+ }
+ return NULL;
+ }
+};
+}
+
+namespace {
+
+const QT3DSU16 g_BOMMarker = (QT3DSU16)0xFEFF;
+
+struct SElemPointer : eastl::pair<SDOMElement *, SDOMAttribute *>
+{
+ SElemPointer(SDOMElement *elem = NULL)
+ : eastl::pair<SDOMElement *, SDOMAttribute *>(elem, NULL)
+ {
+ }
+ SElemPointer &operator=(SDOMElement *elem)
+ {
+ first = elem;
+ second = NULL;
+ return *this;
+ }
+ SElemPointer &operator=(SDOMAttribute *att)
+ {
+ second = att;
+ return *this;
+ }
+ SElemPointer &operator=(const eastl::pair<SDOMElement *, SDOMAttribute *> &other)
+ {
+ eastl::pair<SDOMElement *, SDOMAttribute *>::operator=(other);
+ return *this;
+ }
+ operator SDOMElement *() const { return first; }
+ SDOMElement *operator->() const { return first; }
+};
+
+// Some DOM parsing operations are destructive. If you need
+// them to not be destructive, then we need to modify
+// the reader. Specifically parsing lists of floats, due
+// to a bug in strtod, is destructive.
+struct SDOMReader : public IDOMReader
+{
+ SElemPointer m_TopElement;
+ eastl::vector<eastl::pair<SDOMElement *, SDOMAttribute *>> m_ScopeStack;
+ std::shared_ptr<IDOMFactory> m_Factory;
+ SDOMFlags m_Flags;
+ eastl::basic_string<TWCharEASTLConverter::TCharType> m_TempBuffer;
+
+ SDOMReader(SDOMElement &te, std::shared_ptr<qt3dsdm::IStringTable> s,
+ std::shared_ptr<IDOMFactory> inFactory = std::shared_ptr<IDOMFactory>())
+ : IDOMReader(s)
+ , m_TopElement(&te)
+ , m_Factory(inFactory)
+ {
+ }
+
+ SDOMElement *Current() const { return m_TopElement.first; }
+ void SetDOMFlags(SDOMFlags inFlags) override { m_Flags = inFlags; }
+ SDOMFlags GetDOMFlags() const override { return m_Flags; }
+
+ void PushScope() override { m_ScopeStack.push_back(m_TopElement); }
+ void PopScope() override
+ {
+ if (m_ScopeStack.size()) {
+ m_TopElement = m_ScopeStack.back();
+ m_ScopeStack.pop_back();
+ } else
+ m_TopElement = eastl::pair<SDOMElement *, SDOMAttribute *>(NULL, NULL);
+ }
+
+ void *GetScope() override { return m_TopElement.first; }
+
+ void SetScope(void *inScope) override
+ {
+ m_TopElement =
+ eastl::make_pair(reinterpret_cast<SDOMElement *>(inScope), (SDOMAttribute *)NULL);
+ }
+
+ TWideXMLCharPtr GetElementName() const override
+ {
+ return m_StringTable->GetWideStr(GetNarrowElementName());
+ }
+
+ TXMLCharPtr GetNarrowElementName() const override
+ {
+ if (!Current()) {
+ QT3DS_ASSERT(false);
+ return NULL;
+ }
+ return Current()->m_Name;
+ }
+
+ bool UnregisteredAtt(TWideXMLCharPtr name, TWideXMLCharPtr &outValue) override
+ {
+ outValue = L"";
+ SDOMElement *current(Current());
+ if (current) {
+ TXMLCharPtr theValue =
+ current->GetAttributeValue(m_StringTable->GetNarrowStr(name), m_Flags);
+ if (theValue && *theValue) {
+ qt3ds::foundation::ConvertUTF(theValue, 0, m_TempBuffer);
+ outValue = reinterpret_cast<const wchar_t *>(m_TempBuffer.c_str());
+ return true;
+ }
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ return false;
+ }
+
+ bool UnregisteredAtt(TXMLCharPtr name, TXMLCharPtr &outValue) override
+ {
+ outValue = "";
+ SDOMElement *current(Current());
+ if (current) {
+ outValue = current->GetAttributeValue(m_StringTable->GetNarrowStr(name), m_Flags);
+ if (outValue)
+ return true;
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ return false;
+ }
+
+ bool Att(TWideXMLCharPtr name, TWideXMLCharPtr &outValue) override
+ {
+ if (UnregisteredAtt(name, outValue)) {
+ outValue = m_StringTable->RegisterStr(outValue);
+ return true;
+ }
+ return false;
+ }
+ bool Att(TXMLCharPtr name, TXMLCharPtr &outValue) override
+ {
+ if (UnregisteredAtt(name, outValue)) {
+ outValue = m_StringTable->RegisterStr(outValue);
+ return true;
+ }
+ return false;
+ }
+
+ QT3DSU32 CountChildren() override
+ {
+ SDOMElement *elem = Current();
+ if (elem == NULL) {
+ QT3DS_ASSERT(false);
+ return 0;
+ }
+ return elem->GetNumChildren();
+ }
+
+ QT3DSU32 CountChildren(TWideXMLCharPtr childName) override
+ {
+ return CountChildren(m_StringTable->GetNarrowStr(childName));
+ }
+
+ QT3DSU32 CountChildren(TXMLCharPtr childName) override
+ {
+ SDOMElement *elem = Current();
+ if (elem == NULL) {
+ QT3DS_ASSERT(false);
+ return 0;
+ }
+ return elem->GetNumChildren(m_StringTable->GetNarrowStr(childName), m_Flags);
+ }
+
+ eastl::pair<TWideXMLCharPtr, TWideXMLCharPtr>
+ ToWide(const eastl::pair<TXMLCharPtr, TXMLCharPtr> &att)
+ {
+ return eastl::make_pair(m_StringTable->GetWideStr(att.first),
+ m_StringTable->GetWideStr(att.second));
+ }
+ eastl::pair<TWideXMLCharPtr, TWideXMLCharPtr> CurrentAtt()
+ {
+ return ToWide(CurrentAttNarrow());
+ }
+
+ eastl::pair<TXMLCharPtr, TXMLCharPtr> CurrentAttNarrow()
+ {
+ if (m_TopElement.second)
+ return eastl::make_pair(m_TopElement.second->m_Name, m_TopElement.second->m_Value);
+ return eastl::make_pair("", "");
+ }
+ eastl::pair<TXMLCharPtr, TXMLCharPtr> GetNarrowFirstAttribute() override
+ {
+ if (m_TopElement.first == NULL) {
+ QT3DS_ASSERT(false);
+ eastl::make_pair("", "");
+ }
+ m_TopElement.second = m_TopElement.first->m_FirstAttribute;
+ return CurrentAttNarrow();
+ }
+
+ eastl::pair<TWideXMLCharPtr, TWideXMLCharPtr> GetFirstAttribute() override
+ {
+ return ToWide(GetNarrowFirstAttribute());
+ }
+ eastl::pair<TXMLCharPtr, TXMLCharPtr> GetNarrowNextAttribute() override
+ {
+ if (m_TopElement.second)
+ m_TopElement.second = m_TopElement.second->m_NextAttribute;
+ return CurrentAttNarrow();
+ }
+
+ eastl::pair<TWideXMLCharPtr, TWideXMLCharPtr> GetNextAttribute() override
+ {
+ return ToWide(GetNarrowNextAttribute());
+ }
+
+ bool MoveToFirstChild() override
+ {
+ SDOMElement *elem = Current();
+ if (elem == NULL) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+ if (elem->m_FirstChild) {
+ m_TopElement = elem->m_FirstChild;
+ return true;
+ }
+ return false;
+ }
+ bool MoveToFirstChild(TXMLCharPtr childName) override
+ {
+ SDOMElement *elem = Current();
+ if (elem == NULL) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+ SDOMElement *child = elem->FindChildByName(m_StringTable->RegisterStr(childName), m_Flags);
+ if (child != NULL) {
+ m_TopElement = child;
+ return true;
+ }
+ return false;
+ }
+
+ bool MoveToFirstChild(TWideXMLCharPtr childName) override
+ {
+ return MoveToFirstChild(m_StringTable->GetNarrowStr(childName));
+ }
+
+ bool MoveToNextSibling() override
+ {
+ SDOMElement *elem = Current();
+ if (elem == NULL) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+ if (elem->m_NextSibling) {
+ m_TopElement = elem->m_NextSibling;
+ return true;
+ }
+ return false;
+ }
+ bool MoveToNextSibling(TXMLCharPtr childName) override
+ {
+ SDOMElement *elem = Current();
+ if (elem == NULL) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+ SDOMElement *nextSibling =
+ elem->FindNextSiblingByName(m_StringTable->RegisterStr(childName), m_Flags);
+ if (nextSibling) {
+ m_TopElement = nextSibling;
+ return true;
+ }
+ return false;
+ }
+ bool MoveToNextSibling(TWideXMLCharPtr childName) override
+ {
+ return MoveToNextSibling(m_StringTable->GetNarrowStr(childName));
+ }
+ // Leave element means go to its parent.
+ void Leave() override
+ {
+ if (m_TopElement)
+ m_TopElement = m_TopElement->m_Parent;
+
+ QT3DS_ASSERT(m_TopElement);
+ }
+ bool Value(TXMLCharPtr &outValue) override
+ {
+ SDOMElement *current(Current());
+ if (!current) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+ outValue = current->m_Value;
+ return true;
+ }
+
+ bool Value(TWideXMLCharPtr &outValue) override
+ {
+ outValue = L"";
+ TXMLCharPtr theValue;
+ if (Value(theValue)) {
+ qt3ds::foundation::ConvertUTF(theValue, 0, m_TempBuffer);
+ outValue = reinterpret_cast<const wchar_t *>(m_TempBuffer.c_str());
+ return true;
+ }
+ return false;
+ }
+
+ SDOMElement *GetTopElement() override
+ {
+ SDOMElement *current(Current());
+ while (current && current->m_Parent)
+ current = current->m_Parent;
+ return current;
+ }
+
+ virtual std::shared_ptr<IDOMFactory> GetFactory() { return m_Factory; }
+};
+
+struct SDOMWriter : public IDOMWriter, public SDOMReader
+{
+ std::shared_ptr<IDOMFactory> m_FactoryPtr;
+ IDOMFactory &m_Factory;
+
+ SDOMWriter(std::shared_ptr<IDOMFactory> inDOMFactory,
+ std::shared_ptr<qt3dsdm::IStringTable> inStringTable, SDOMElement &inTopElem)
+ : m_FactoryPtr(inDOMFactory)
+ , m_Factory(*inDOMFactory)
+ , SDOMReader(inTopElem, inStringTable)
+ {
+ }
+ void SetDOMFlags(SDOMFlags inFlags) override { m_Flags = inFlags; }
+ SDOMFlags GetDOMFlags() const override { return m_Flags; }
+
+ void Begin(TXMLCharPtr inElemName) override
+ {
+ if (!m_TopElement) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ SDOMElement *current(Current());
+ SDOMElement *newElement(m_Factory.NextElement(inElemName));
+ current->AddChild(*newElement);
+ m_TopElement = newElement;
+ }
+
+ void Begin(TWideXMLCharPtr inElemName) override
+ {
+ Begin(m_FactoryPtr->GetStringTable()->GetNarrowStr(inElemName));
+ }
+
+ void Att(TXMLCharPtr name, TXMLCharPtr value) override
+ {
+ if (!m_TopElement) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ m_TopElement->SetAttributeValue(name, value, m_Factory, m_Flags);
+ }
+ // Attributes. They may be sorted just before write
+ void Att(TWideXMLCharPtr name, TWideXMLCharPtr value) override
+ {
+ if (!m_TopElement) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ m_TopElement->SetAttributeValue(name, value, m_Factory, m_Flags);
+ }
+
+ void Value(TWideXMLCharPtr value) override
+ {
+ if (!m_TopElement) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ if (value == NULL)
+ value = L"";
+ size_t len = wcslen(value);
+ m_Factory.AppendStrBuf(value, (QT3DSU32)len);
+ m_TopElement->m_Value = m_Factory.FinalizeStrBuf();
+ }
+ void Value(TXMLCharPtr value) override
+ {
+ if (!m_TopElement) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ if (value == NULL)
+ value = "";
+ size_t len = strlen(value);
+ m_Factory.AppendStrBuf(value, (QT3DSU32)len);
+ m_TopElement->m_Value = m_Factory.FinalizeStrBuf();
+ }
+
+ void End() override
+ {
+ if (!m_TopElement) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ Leave();
+ }
+ void RemoveCurrent() override
+ {
+ SDOMElement *current(Current());
+ if (!current) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ if (current->m_Parent) {
+ m_TopElement = current->m_Parent;
+ m_TopElement->RemoveChild(*current);
+ }
+ }
+ void ReplaceCurrent(SDOMElement &inElement) override
+ {
+ SDOMElement *current(Current());
+ if (!current) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ if (current->m_Parent) {
+ current->m_Parent->ReplaceChild(*current, inElement);
+ m_TopElement = &inElement;
+ } else {
+ m_TopElement = &inElement;
+ inElement.m_Parent = NULL;
+ inElement.m_NextSibling = NULL;
+ }
+ }
+ void AppendChildren(SDOMElement &inElement) override
+ {
+ SDOMElement *current(Current());
+ if (!current) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ SDOMElement *theChild = inElement.m_FirstChild;
+ inElement.m_FirstChild = inElement.m_LastChild = NULL;
+ while (theChild) {
+ SDOMElement *theCurrentChild = theChild;
+ theChild = theChild->m_NextSibling;
+
+ theCurrentChild->m_Parent = NULL;
+ theCurrentChild->m_NextSibling = NULL;
+ current->AddChild(*theCurrentChild);
+ }
+ }
+ void RemoveAttribute(TXMLCharPtr inItem) override
+ {
+ SDOMElement *current(Current());
+ if (!current) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ current->RemoveAttribute(m_StringTable->RegisterStr(inItem), m_Flags);
+ }
+ void RemoveAttribute(TWideXMLCharPtr inItem) override
+ {
+ RemoveAttribute(m_StringTable->GetNarrowStr(inItem));
+ }
+
+ void MoveBefore(TXMLCharPtr inItem, TXMLCharPtr inSibling) override
+ {
+ SDOMElement *current(Current());
+ if (!current) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+
+ SDOMElement *theItem =
+ current->FindChildByName(m_StringTable->RegisterStr(inItem), m_Flags);
+ SDOMElement *theSibling =
+ current->FindChildByName(m_StringTable->RegisterStr(inSibling), m_Flags);
+ QT3DS_ASSERT(theItem && theSibling);
+ if (theItem && theSibling) {
+ current->RemoveChild(*theItem);
+ current->InsertChildBefore(*theItem, *theSibling);
+ }
+ }
+
+ void MoveBefore(TWideXMLCharPtr inItem, TWideXMLCharPtr inSibling) override
+ {
+ MoveBefore(m_StringTable->GetNarrowStr(inItem), m_StringTable->GetNarrowStr(inSibling));
+ }
+
+ // If current has no parent, then we are at the top
+ // of the tree and we should return 0. Or if there is no
+ // current.
+ // If there is one parent, we should return 1.
+ QT3DSU32 GetTabs() override
+ {
+ QT3DSU32 retval = 0;
+ SDOMElement *current(Current());
+ do {
+ if (current)
+ current = current->m_Parent;
+ if (current)
+ ++retval;
+ } while (current);
+ return retval;
+ }
+
+ SDOMElement *GetTopElement() override { return SDOMReader::GetTopElement(); }
+
+ std::shared_ptr<IDOMFactory> GetFactory() override { return m_FactoryPtr; }
+};
+
+struct SimpleXmlWriter
+{
+ IOutStream &m_Stream;
+ eastl::vector<eastl::pair<TXMLCharPtr, bool>> m_OpenElements;
+ bool m_ElementOpen;
+ wchar_t m_PrintBuf[256];
+ QT3DSU32 m_Tabs;
+ eastl::basic_string<char8_t> m_ConvertBuf;
+ eastl::basic_string<TWCharEASTLConverter::TCharType> m_WideBuffer;
+
+ SimpleXmlWriter(IOutStream &stream, QT3DSU32 inTabs = 0)
+ : m_Stream(stream)
+ , m_ElementOpen(false)
+ , m_Tabs(inTabs)
+ {
+ }
+ void Write(TWideXMLCharPtr data)
+ {
+ if (!IsTrivial(data)) {
+ qt3ds::foundation::ConvertUTF(
+ reinterpret_cast<const TWCharEASTLConverter::TCharType *>(data), 0,
+ m_ConvertBuf);
+ m_Stream.Write(m_ConvertBuf.begin(), m_ConvertBuf.size());
+ }
+ }
+ void Write(const char8_t *data)
+ {
+ if (!IsTrivial(data)) {
+ m_Stream.Write(data, (QT3DSU32)strlen(data));
+ }
+ }
+ void BeginWideWrite() { m_WideBuffer.clear(); }
+ void WriteTemp(wchar_t data) { m_WideBuffer.append(1, data); }
+ void WriteTemp(const wchar_t *data)
+ {
+ m_WideBuffer.append(reinterpret_cast<const TWCharEASTLConverter::TCharType *>(data));
+ }
+ void EndWideWrite() { Write(reinterpret_cast<const wchar_t *>(m_WideBuffer.c_str())); }
+ void Write(char8_t data) { m_Stream.Write(data); }
+ void Tabs()
+ {
+ QT3DSXML_FOREACH(idx, (m_OpenElements.size() + m_Tabs))
+ Write('\t');
+ }
+ void Close(bool newline)
+ {
+ if (m_ElementOpen) {
+ Write(L" >");
+ if (newline)
+ Write('\n');
+ }
+ m_ElementOpen = false;
+ }
+ void Begin(TXMLCharPtr name)
+ {
+ Close(true);
+ Tabs();
+ Write('<');
+ Write(name);
+ m_OpenElements.push_back(eastl::pair<TXMLCharPtr, bool>(name, false));
+ m_ElementOpen = true;
+ }
+ TWideXMLCharPtr ToStr(char8_t val)
+ {
+ m_PrintBuf[0] = val;
+ m_PrintBuf[1] = 0;
+ return m_PrintBuf;
+ }
+ template <typename TDataType>
+ TWideXMLCharPtr ToStr(TDataType val)
+ {
+ WStrOps<TDataType>().ToStr(val, NVDataRef<wchar_t>(m_PrintBuf, 256));
+ return m_PrintBuf;
+ }
+ void Att(TXMLCharPtr name, TXMLCharPtr value)
+ {
+ QT3DS_ASSERT(m_ElementOpen);
+ Write(' ');
+ Write(name);
+ Write("=\"");
+ QString str = QString::fromUtf8(nonNull(value)).toHtmlEscaped();
+ Write(str.toUtf8().constData());
+ Write("\"");
+ }
+ template <typename TData>
+ void Att(TXMLCharPtr name, TData value)
+ {
+ Att(name, ToStr(value));
+ }
+
+ void Value(TXMLCharPtr value)
+ {
+ if (!IsTrivial(value)) {
+ Close(false);
+ QString str = QString::fromUtf8(nonNull(value)).toHtmlEscaped();
+ Write(str.toUtf8().constData());
+ m_OpenElements.back().second = true;
+ }
+ }
+ void ChildValue(TXMLCharPtr name, TXMLCharPtr value)
+ {
+ Begin(name);
+ Value(value);
+ End();
+ }
+ void End(bool newlineAfterClose = true)
+ {
+ QT3DS_ASSERT(m_OpenElements.size());
+ eastl::pair<TXMLCharPtr, bool> topElem = m_OpenElements.back();
+ m_OpenElements.pop_back();
+ if (m_ElementOpen)
+ Write(" />");
+ else {
+ if (topElem.second == false)
+ Tabs();
+ Write("</");
+ Write(topElem.first);
+ Write(">");
+ }
+ m_ElementOpen = false;
+ if (newlineAfterClose == true)
+ Write('\n');
+ }
+};
+
+struct DOMParser
+{
+ typedef eastl::basic_string<TWCharEASTLConverter::TCharType> TStrType;
+ IDOMFactory &m_Factory;
+ SDOMElement *m_TopElement;
+ SDOMElement *m_FirstElement;
+
+ DOMParser(IDOMFactory &factory)
+ : m_Factory(factory)
+ , m_FirstElement(NULL)
+ {
+ }
+
+ template <QT3DSU32 THeaderLen>
+ struct SHeaderInStream : public IInStream
+ {
+ QT3DSU8 m_Header[THeaderLen];
+ QT3DSU32 m_BytesRead;
+ IInStream &m_InStream;
+ SHeaderInStream(IInStream &inStream)
+ : m_InStream(inStream)
+ , m_BytesRead(0)
+ {
+ }
+ bool readHeader()
+ {
+ QT3DSU32 amountRead = m_InStream.Read(NVDataRef<QT3DSU8>(m_Header, THeaderLen));
+ return amountRead == THeaderLen;
+ }
+ QT3DSU32 Read(NVDataRef<QT3DSU8> data) override
+ {
+ if (data.size() == 0)
+ return 0;
+ QT3DSU8 *writePtr(data.begin());
+ QT3DSU32 amountToRead(data.size());
+ QT3DSU32 amountRead = 0;
+ if (m_BytesRead < THeaderLen) {
+ QT3DSU32 headerLeft = qMin(THeaderLen - m_BytesRead, amountToRead);
+ memCopy(writePtr, m_Header + m_BytesRead, headerLeft);
+ writePtr += headerLeft;
+ amountToRead -= headerLeft;
+ amountRead += headerLeft;
+ }
+ if (amountToRead)
+ amountRead += m_InStream.Read(NVDataRef<QT3DSU8>(writePtr, amountToRead));
+ m_BytesRead += amountRead;
+ return amountRead;
+ }
+ };
+
+ static SDOMElement *ParseXMLFile(IDOMFactory &factory, IInStream &inStream,
+ CXmlErrorHandler *handler = NULL)
+ {
+ QXmlStreamReader sreader;
+
+ DOMParser domParser(factory);
+ QT3DSU8 dataBuf[2048];
+ QT3DSU32 amountRead = 0;
+ do {
+ amountRead = inStream.Read(toDataRef(dataBuf, 2048));
+ if (amountRead) {
+ QByteArray tmp = QByteArray::fromRawData((char*)dataBuf,amountRead);
+ sreader.addData(tmp);
+ }
+ } while (amountRead > 0);
+
+ while (!sreader.atEnd()) {
+ QXmlStreamReader::TokenType token = sreader.readNext();
+
+ if (token == QXmlStreamReader::StartElement) {
+ domParser.m_Factory.IgnoreStrBuf();
+ SDOMElement *newElem = domParser.m_Factory.NextElement(
+ (TXMLCharPtr)sreader.name().toUtf8().data());
+ if (domParser.m_FirstElement == NULL) {
+ domParser.m_FirstElement = newElem;
+ domParser.m_TopElement = newElem;
+ } else {
+ domParser.m_TopElement->AddChild(*newElem);
+ domParser.m_TopElement = newElem;
+ }
+ const QXmlStreamAttributes& attributes = sreader.attributes();
+ for (auto attrib : attributes) {
+ SDOMAttribute *att = domParser.m_Factory.NextAttribute(
+ (TXMLCharPtr)attrib.name().toUtf8().data(),
+ (TXMLCharPtr)attrib.value().toUtf8().data());
+ newElem->AddAttribute(*att);
+ }
+ } else if (token == QXmlStreamReader::Characters) {
+ QByteArray text = sreader.text().toUtf8();
+ domParser.m_Factory.AppendStrBuf(text.data(),text.length());
+ } else if (token == QXmlStreamReader::EndElement) {
+ domParser.m_TopElement->m_Value = domParser.m_Factory.FinalizeStrBuf();
+ domParser.m_TopElement = domParser.m_TopElement->m_Parent;
+ }
+ if (sreader.hasError()) {
+ if (handler) {
+ handler->OnXmlError(sreader.errorString(), sreader.lineNumber(),
+ sreader.columnNumber());
+ } else {
+ qWarning() << "XML parse error:" << sreader.errorString()
+ << "line:" << sreader.lineNumber()
+ << "column:" << sreader.columnNumber();
+ }
+ return nullptr;
+ }
+ }
+ return domParser.m_FirstElement;
+ }
+};
+
+class SimpleDomFactory : public IDOMFactory
+{
+ typedef eastl::basic_string<char8_t> TNarrowStr;
+ Pool<SDOMElement> m_ElementPool;
+ Pool<SDOMAttribute> m_AttributePool;
+ eastl::vector<char8_t *> m_BigStrings;
+ eastl::vector<char8_t> m_StringBuilder;
+ TNarrowStr m_ConvertBuffer;
+ std::shared_ptr<qt3dsdm::IStringTable> m_StringTable;
+
+public:
+ SimpleDomFactory(std::shared_ptr<qt3dsdm::IStringTable> strt)
+ : m_StringTable(strt)
+ {
+ }
+ ~SimpleDomFactory()
+ {
+ QT3DSXML_FOREACH(idx, m_BigStrings.size())
+ free(m_BigStrings[idx]);
+ }
+
+ TWideXMLCharPtr RegisterStr(TWideXMLCharPtr str)
+ {
+ if (str == NULL || *str == 0)
+ return L"";
+ return m_StringTable->RegisterStr(str);
+ }
+
+ TXMLCharPtr RegisterStr(TXMLCharPtr str)
+ {
+ if (str == NULL || *str == 0)
+ return "";
+ return m_StringTable->RegisterStr(str);
+ }
+
+ void Release() override { delete this; }
+ void AppendStrBuf(TXMLCharPtr str, QT3DSU32 len) override
+ {
+ if (len && *str) {
+ QT3DSU32 offset = m_StringBuilder.size();
+ m_StringBuilder.resize(offset + len);
+ memCopy(&m_StringBuilder[0] + offset, str, len * sizeof(char8_t));
+ }
+ }
+ // Str does not need to be null terminated.
+ void AppendStrBuf(TWideXMLCharPtr str, QT3DSU32 len) override
+ {
+ if (len && *str) {
+ const TWCharEASTLConverter::TCharType *bufPtr =
+ reinterpret_cast<const TWCharEASTLConverter::TCharType *>(str);
+ qt3ds::foundation::ConvertUTF(bufPtr, len, m_ConvertBuffer);
+ AppendStrBuf(m_ConvertBuffer.data(), m_ConvertBuffer.size());
+ }
+ }
+
+ // Null terminate what is there and return the buffer.
+ // This pointer needs to be persistent.
+ TXMLCharPtr FinalizeStrBuf() override
+ {
+ if (m_StringBuilder.size() == 0)
+ return "";
+ m_StringBuilder.push_back(0);
+ QT3DSU32 len = m_StringBuilder.size();
+ QT3DSU32 numBytes = len * sizeof(char8_t);
+ char8_t *newMem = (char8_t *)malloc(numBytes);
+ memCopy(newMem, &m_StringBuilder[0], numBytes);
+ m_BigStrings.push_back(newMem);
+ m_StringBuilder.clear();
+ return newMem;
+ }
+ void IgnoreStrBuf() override { m_StringBuilder.clear(); }
+
+ SDOMAttribute *NextAttribute(TXMLCharPtr name, TXMLCharPtr val) override
+ {
+ TXMLCharPtr n(m_StringTable->GetNarrowStr(name));
+ TXMLCharPtr v(RegisterValue(val));
+ return m_AttributePool.construct(n, v, __FILE__, __LINE__);
+ }
+
+ SDOMAttribute *NextAttribute(TWideXMLCharPtr name, TWideXMLCharPtr val) override
+ {
+ TXMLCharPtr n(m_StringTable->GetNarrowStr(name));
+ TXMLCharPtr v(RegisterValue(val));
+ return m_AttributePool.construct(n, v, __FILE__, __LINE__);
+ }
+
+ SDOMElement *NextElement(TXMLCharPtr name) override
+ {
+ IgnoreStrBuf();
+ TXMLCharPtr n(m_StringTable->GetNarrowStr(name));
+ return m_ElementPool.construct(n, __FILE__, __LINE__);
+ }
+ SDOMElement *NextElement(TWideXMLCharPtr name) override
+ {
+ IgnoreStrBuf();
+ TXMLCharPtr n(m_StringTable->GetNarrowStr(name));
+ return m_ElementPool.construct(n, __FILE__, __LINE__);
+ }
+
+ std::shared_ptr<qt3dsdm::IStringTable> GetStringTable() override { return m_StringTable; }
+};
+}
+
+bool IDOMReader::Value(DataModelDataType::Value type, SValue &outValue)
+{
+ TXMLCharPtr value;
+ if (Value(value)) {
+ WCharTReader reader(const_cast<char8_t *>(value), m_TempBuf, *GetStringTable());
+ outValue = WStrOps<SValue>().BufTo(type, reader);
+ return true;
+ }
+ return false;
+}
+
+std::shared_ptr<IDOMReader>
+IDOMReader::CreateDOMReader(SDOMElement &inRootElement,
+ std::shared_ptr<qt3dsdm::IStringTable> inStringTable,
+ std::shared_ptr<IDOMFactory> inFactory)
+{
+ return std::make_shared<SDOMReader>(std::ref(inRootElement), std::ref(inStringTable),
+ inFactory);
+}
+
+eastl::pair<std::shared_ptr<IDOMWriter>, std::shared_ptr<IDOMReader>>
+IDOMWriter::CreateDOMWriter(std::shared_ptr<IDOMFactory> inFactory, SDOMElement &inRootElement,
+ std::shared_ptr<qt3dsdm::IStringTable> inStringTable)
+{
+ std::shared_ptr<SDOMWriter> writer(std::make_shared<SDOMWriter>(
+ inFactory, std::ref(inStringTable), std::ref(inRootElement)));
+ return eastl::make_pair(writer, writer);
+}
+
+TXMLCharPtr IDOMFactory::RegisterValue(TWideXMLCharPtr inValue)
+{
+ if (IsTrivial(inValue))
+ return "";
+ IgnoreStrBuf();
+ AppendStrBuf(inValue, (QT3DSU32)wcslen(inValue));
+ return FinalizeStrBuf();
+}
+
+TXMLCharPtr IDOMFactory::RegisterValue(TXMLCharPtr inValue)
+{
+ if (IsTrivial(inValue))
+ return "";
+ IgnoreStrBuf();
+ AppendStrBuf(inValue, (QT3DSU32)strlen(inValue));
+ return FinalizeStrBuf();
+}
+
+std::shared_ptr<IDOMFactory>
+IDOMFactory::CreateDOMFactory(std::shared_ptr<qt3dsdm::IStringTable> inStrTable)
+{
+ return std::make_shared<SimpleDomFactory>(std::ref(inStrTable));
+}
+
+void CDOMSerializer::WriteXMLHeader(IOutStream &inStream)
+{
+ SimpleXmlWriter writer(inStream);
+ writer.Write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
+}
+
+// Lexigraphically sort the attributes.
+struct SAttributeComparator
+{
+ bool operator()(const SDOMAttribute *lhs, const SDOMAttribute *rhs)
+ {
+ return strcmp(lhs->m_Name, rhs->m_Name) < 0;
+ }
+};
+
+// Write an element with attributes sorted by name so a file diff is effective.
+void WriteElement(SDOMElement &inElement, SimpleXmlWriter &inWriter,
+ std::vector<SDOMAttribute *> &inAttSorter)
+{
+ inAttSorter.clear();
+ for (SDOMAttribute *att = inElement.m_FirstAttribute; att; att = att->m_NextAttribute)
+ inAttSorter.push_back(att);
+ // We decided that we don't want attribute sorting; the code that adds attributes needs
+ // to be consistent.
+ // std::sort( inAttSorter.begin(), inAttSorter.end(), SAttributeComparator() );
+ // This element doesn't add anything to the system in this case.
+ if (inElement.m_FirstAttribute == NULL && inElement.m_FirstChild == NULL
+ && IsTrivial(inElement.m_Value))
+ return;
+
+ inWriter.Begin(inElement.m_Name);
+
+ const char8_t *theLastAttName = 0;
+ for (size_t idx = 0, end = inAttSorter.size(); idx < end; ++idx) {
+ SDOMAttribute *theAtt(inAttSorter[idx]);
+ if (theAtt->m_Name != theLastAttName)
+ inWriter.Att(theAtt->m_Name, theAtt->m_Value);
+ else {
+ QT3DS_ASSERT(false);
+ }
+ theLastAttName = theAtt->m_Name;
+ }
+ // Elements can either have children or values but not both at this point.
+ if (inElement.m_FirstChild) {
+ for (SDOMElement *theChild = inElement.m_FirstChild; theChild;
+ theChild = theChild->m_NextSibling)
+ WriteElement(*theChild, inWriter, inAttSorter);
+ inWriter.End();
+ } else {
+ if (!IsTrivial(inElement.m_Value))
+ inWriter.Value(inElement.m_Value);
+
+ inWriter.End();
+ }
+}
+
+void CDOMSerializer::Write(SDOMElement &inElement, IOutStream &inStream, QT3DSU32 inTabs)
+{
+ // TODO: QXmlStreamWriter here?
+ std::vector<SDOMAttribute *> theAttributes;
+ SimpleXmlWriter writer(inStream, inTabs);
+ std::vector<SDOMAttribute *> theAttSorter;
+ WriteElement(inElement, writer, theAttSorter);
+}
+
+SDOMElement *CDOMSerializer::Read(IDOMFactory &inFactory, IInStream &inStream,
+ CXmlErrorHandler *inErrorHandler)
+{
+ return DOMParser::ParseXMLFile(inFactory, inStream, inErrorHandler);
+}