Files
GTASource/rage/scaleform/Src/GFxPlayer/XML/GFxXML.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

767 lines
22 KiB
C++

/**********************************************************************
Filename : GFxXML.cpp
Content : DOM support
Created : December 13, 2007
Authors : Prasad Silva
Copyright : (c) 2005-2008 Scaleform Corp. All Rights Reserved.
Licensees may use this file in accordance with the valid Scaleform
Commercial License Agreement provided with the software.
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE.
**********************************************************************/
#include "GConfig.h"
#ifndef GFC_NO_XML_SUPPORT
#include <GFxXML.h>
//
// Debug trace/dump helper functions
//
#ifdef GFC_BUILD_DEBUG
//
// Trace the document builder's DOM tree construction in debug output
//
// #define GFC_XML_DOCBUILDER_TRACE
//
//
// Dump all constructed DOM trees to standard out
// if provided to the document builder
// (Warning: Avoid this for large files)
//
// #define GFC_XML_DOCBUILDER_DOM_TREE_DUMP
//
// Maximum size of strings used for debug printing
#define MAX_DEBUG_STRING_LENGTH 256
//
// Helper to copy strings for debugging
//
void SafeStringCopyWithSentinel(const char* src, UPInt srcLen,
char* dest, UPInt destSz)
{
UPInt len = 0;
if (srcLen < destSz)
len = srcLen;
else
len = (destSz - 1);
G_strncpy(dest, len + 1, src, len);
// explicit sentinel just in case
dest[len] = '\0';
}
#ifdef GFC_XML_DOCBUILDER_DOM_TREE_DUMP
//
// Prints the DOM tree to stdout
//
char printDOMBuffer[128];
void PrintDOMTree(GFxXMLNode* proot, UPInt level = 0)
{
for (UPInt i=0; i < level; i++)
printf(" ");
switch (proot->Type)
{
case GFxXMLElementNodeType:
{
GFxXMLElementNode* pnode = static_cast<GFxXMLElementNode*>(proot);
if (pnode->Prefix.GetSize() > 0)
{
printf("ELEM - '%.16s:%.16s' ns:'%.16s' prefix:'%.16s'"
" localname: '%.16s'",
pnode->Prefix.ToCStr(),
pnode->Value.ToCStr(),
pnode->Namespace.ToCStr(),
pnode->Prefix.ToCStr(),
pnode->Value.ToCStr());
}
else
{
printf("ELEM - '%.16s' ns:'%.16s' prefix:''"
" localname: '%.16s'",
pnode->Value.ToCStr(),
pnode->Namespace.ToCStr(),
pnode->Value.ToCStr());
}
for (GFxXMLAttribute* attr = pnode->FirstAttribute;
attr != NULL; attr = attr->Next)
{
printf(" {%.16s,%.16s}", attr->Name.ToCStr(),
attr->Value.ToCStr());
}
printf("\n");
for (GFxXMLNode* child = pnode->FirstChild; child != NULL;
child = child->NextSibling)
PrintDOMTree(child, level+1);
break;
}
case GFxXMLTextNodeType:
{
printf("TEXT - '%.16s'\n", proot->Value.ToCStr());
break;
}
default:
{
printf("UNKN\n");
}
}
}
#endif // #ifdef GFC_XML_DOCBUILDER_DOM_TREE_DUMP
#endif // #ifdef GFC_BUILD_DEBUG
//
// Constructor
//
GFxXMLDOMBuilder::GFxXMLDOMBuilder(GPtr<GFxXMLSupportBase> pxmlParser,
bool ignorews)
: pXMLParserState(pxmlParser), pLocator(NULL), pDoc(NULL),
bIgnoreWhitespace(ignorews), bError(false)
{
#ifdef GFC_XML_DOCBUILDER_TRACE
GFC_DEBUG_MESSAGE(1, "GFxXMLDocumentBuilder::GFxXMLDocumentBuilder");
#endif
}
//
// Parse an XML file and build a DOM tree out of it
//
GPtr<GFxXMLDocument> GFxXMLDOMBuilder::ParseFile(const char* pfilename,
GFxFileOpenerBase* pfo,
GPtr<GFxXMLObjectManager> objMgr /* = NULL */)
{
// reset internal vars
bError = false;
TotalBytesToLoad = 0;
LoadedBytes = 0;
if (NULL == objMgr.GetPtr())
objMgr = *new GFxXMLObjectManager;
// create new document
pDoc = *objMgr->CreateDocument();
// commence parsing
if (pXMLParserState)
bError = !pXMLParserState->ParseFile(pfilename, pfo, this);
// NOTE: The locator could be invalid at this point
// Release internal reference to document
GPtr<GFxXMLDocument> pret = pDoc;
pDoc = 0;
if (pret.GetPtr() && bIgnoreWhitespace)
DropWhiteSpaceNodes(pret);
return pret;
}
//
// Parse an XML string and build a DOM tree out of it
//
GPtr<GFxXMLDocument> GFxXMLDOMBuilder::ParseString(const char* pdata, UPInt len,
GPtr<GFxXMLObjectManager> objMgr /* = NULL */)
{
// Reset internal vars
bError = false;
TotalBytesToLoad = 0;
LoadedBytes = 0;
if (NULL == objMgr.GetPtr())
objMgr = *new GFxXMLObjectManager;
// Create new document
pDoc = *objMgr->CreateDocument();
// Commence parsing
if (pXMLParserState)
bError = !pXMLParserState->ParseString(pdata, len, this);
// NOTE: The locator could be invalid at this point
// Release internal reference to document
GPtr<GFxXMLDocument> pret = pDoc;
pDoc = 0;
if (pret.GetPtr() && bIgnoreWhitespace)
DropWhiteSpaceNodes(pret);
return pret;
}
//
// Document begin reported by XML parser
//
void GFxXMLDOMBuilder::StartDocument()
{
#ifdef GFC_XML_DOCBUILDER_TRACE
GFC_DEBUG_ASSERT(pLocator, "Locator not set!");
GFC_DEBUG_MESSAGE(1, "GFxXMLDocumentBuilder::StartDocument");
#endif
// Create a parse stack
ParseStack.PushBack(pDoc);
// Copy the total number of bytes to load
TotalBytesToLoad = pLocator->TotalBytesToLoad;
}
//
// Document end reported by XML parser
//
void GFxXMLDOMBuilder::EndDocument()
{
#ifdef GFC_XML_DOCBUILDER_TRACE
GFC_DEBUG_ASSERT(pLocator, "Locator not set!");
char db0[MAX_DEBUG_STRING_LENGTH];
char db1[MAX_DEBUG_STRING_LENGTH];
SafeStringCopyWithSentinel(pLocator->XMLVersion.ToCStr(),
pLocator->XMLVersion.GetSize(),
db0, MAX_DEBUG_STRING_LENGTH);
SafeStringCopyWithSentinel(pLocator->Encoding.ToCStr(),
pLocator->Encoding.GetSize(),
db1, MAX_DEBUG_STRING_LENGTH);
GFC_DEBUG_MESSAGE3(1,
"GFxXMLDocumentBuilder::EndDocument('%.16s', '%.16s', %d)",
db0, db1, pLocator->StandAlone);
#endif
// Copy the number of bytes loaded
LoadedBytes = pLocator->LoadedBytes;
// Check parse stack
GASSERT(ParseStack.GetSize() == 1);
GASSERT(ParseStack[0].GetPtr() == pDoc.GetPtr());
// Drop reference to document
ParseStack.Clear();
// Check prefix ownership stacks
GASSERT(PrefixNamespaceStack.GetSize() == 0);
GASSERT(DefaultNamespaceStack.GetSize() == 0);
// Set the xml declaration values
GPtr<GFxXMLObjectManager> memMgr = pDoc->MemoryManager;
pDoc->XMLVersion = memMgr->CreateString(pLocator->XMLVersion.ToCStr(),
pLocator->XMLVersion.GetSize());
pDoc->Encoding = memMgr->CreateString(pLocator->Encoding.ToCStr(),
pLocator->Encoding.GetSize());
pDoc->Standalone = (SByte)pLocator->StandAlone;
#ifdef GFC_XML_DOCBUILDER_DOM_TREE_DUMP
PrintDOMTree(pDoc);
#endif
}
//
// Tag element begin reported by XML parser
//
void GFxXMLDOMBuilder::StartElement(const GFxXMLStringRef& prefix,
const GFxXMLStringRef& localname,
const GFxXMLParserAttributes& atts)
{
#ifdef GFC_XML_DOCBUILDER_TRACE
GFC_DEBUG_ASSERT(pLocator, "Locator not set!");
char db0[MAX_DEBUG_STRING_LENGTH];
char db1[MAX_DEBUG_STRING_LENGTH];
SafeStringCopyWithSentinel(prefix.ToCStr(), prefix.GetSize(),
db0, MAX_DEBUG_STRING_LENGTH);
SafeStringCopyWithSentinel(localname.ToCStr(), localname.GetSize(),
db1, MAX_DEBUG_STRING_LENGTH);
GFC_DEBUG_MESSAGE4(1,
"[%d, %d] GFxXMLDocumentBuilder::StartElement('%.16s', '%.16s')",
pLocator->Line, pLocator->Column, db0, db1);
for (UPInt i=0; i < atts.Length; i++)
{
GFxXMLParserAttribute& att = atts.Attributes[i];
SafeStringCopyWithSentinel(att.Name.ToCStr(), att.Name.GetSize(),
db0, MAX_DEBUG_STRING_LENGTH);
SafeStringCopyWithSentinel(att.Value.ToCStr(), att.Value.GetSize(),
db1, MAX_DEBUG_STRING_LENGTH);
GFC_DEBUG_MESSAGE2(1, "\tATTR: '%.16s' -> '%.16s'", db0, db1);
}
#endif
// Copy the number of bytes loaded
LoadedBytes = pLocator->LoadedBytes;
// Must have at least root node in stack
GASSERT(ParseStack.GetSize() > 0);
GPtr<GFxXMLObjectManager> memMgr = pDoc->MemoryManager;
// If appending required, consolidate it
if (pAppendChainRoot.GetPtr() != NULL)
{
GPtr<GFxXMLElementNode> pnode = ParseStack.Back();
pnode->AppendChild(pAppendChainRoot);
pAppendChainRoot->Value = memMgr->CreateString(AppendText.ToCStr(), AppendText.GetSize());
// Reset append chain
pAppendChainRoot = NULL;
AppendText.Clear();
}
// Create new node
GPtr<GFxXMLElementNode> elemNode = *memMgr->CreateElementNode(
memMgr->CreateString(localname.ToCStr(), localname.GetSize()));
// Add attributes
for (UPInt i=0; i < atts.Length; i++)
{
GFxXMLParserAttribute& att = atts.Attributes[i];
GFxXMLAttribute* patt = memMgr->CreateAttribute(
memMgr->CreateString(att.Name.ToCStr(), att.Name.GetSize()),
memMgr->CreateString(att.Value.ToCStr(), att.Value.GetSize()));
elemNode->AddAttribute(patt);
}
// Assign ownership to any floating namespaces
if (PrefixNamespaceStack.GetSize() > 0)
{
UPInt len = PrefixNamespaceStack.GetSize();
for (SInt i=(SInt)len-1; i >= 0; i--)
{
PrefixOwnership& po = PrefixNamespaceStack[i];
if (NULL != po.Owner.GetPtr())
break;
po.Owner = elemNode;
}
}
if (DefaultNamespaceStack.GetSize() > 0)
{
PrefixOwnership& po = DefaultNamespaceStack.Back();
if (NULL == po.Owner.GetPtr())
po.Owner = elemNode;
}
// Assign appropriate namespace to node
if (prefix.GetSize() > 0)
{
bool found = false;
// Assign prefix namespace - it has higher precedence
// TODO: change to hash lookup?
if (PrefixNamespaceStack.GetSize() > 0)
{
UPInt len = PrefixNamespaceStack.GetSize();
for (SInt i=(SInt)len-1; i >= 0; i--)
{
PrefixOwnership po = PrefixNamespaceStack[i];
if (po.Prefix->Name ==
GFxXMLDOMStringCompareWrapper(prefix.ToCStr(), prefix.GetSize()))
{
found = true;
elemNode->Prefix = po.Prefix->Name;
elemNode->Namespace = po.Prefix->Value;
break;
}
}
}
if (!found)
{
// Prefix was not found. create a dummy one.
elemNode->Prefix = memMgr->CreateString(prefix.ToCStr(),
prefix.GetSize());
elemNode->Namespace = memMgr->EmptyString();
}
}
else if (DefaultNamespaceStack.GetSize() > 0)
{
// Assign default namespace
PrefixOwnership os = DefaultNamespaceStack.Back();
elemNode->Prefix = os.Prefix->Name;
elemNode->Namespace = os.Prefix->Value;
}
// Attach to parent
GPtr<GFxXMLElementNode> parentNode = ParseStack.Back();
parentNode->AppendChild(elemNode);
// Push to parse stack
ParseStack.PushBack(elemNode);
}
//
// Tag element end reported by XML parser
//
void GFxXMLDOMBuilder::EndElement(const GFxXMLStringRef& prefix,
const GFxXMLStringRef& localname)
{
GUNUSED2(prefix, localname);
#ifdef GFC_XML_DOCBUILDER_TRACE
GFC_DEBUG_ASSERT(pLocator, "Locator not set!");
char db0[MAX_DEBUG_STRING_LENGTH];
char db1[MAX_DEBUG_STRING_LENGTH];
SafeStringCopyWithSentinel(prefix.ToCStr(), prefix.GetSize(), db0,
MAX_DEBUG_STRING_LENGTH);
SafeStringCopyWithSentinel(localname.ToCStr(), localname.GetSize(),
db1, MAX_DEBUG_STRING_LENGTH);
GFC_DEBUG_MESSAGE4(1,
"[%d, %d] GFxXMLDocumentBuilder::EndElement('%.16s', '%.16s')",
pLocator->Line, pLocator->Column, db0, db1);
#endif
// Copy the number of bytes loaded
LoadedBytes = pLocator->LoadedBytes;
GASSERT(ParseStack.GetSize() > 1); // must be at least root node + 1
GPtr<GFxXMLElementNode> pnode = ParseStack.Back();
GASSERT(pnode.GetPtr() != pDoc.GetPtr()); // must not be root node
// If appending required, consolidate it
if (pAppendChainRoot.GetPtr() != NULL)
{
GPtr<GFxXMLObjectManager> memMgr = pDoc->MemoryManager;
pnode->AppendChild(pAppendChainRoot);
// Accumulate append text while removing the nodes
pAppendChainRoot->Value = memMgr->CreateString(AppendText.ToCStr(), AppendText.GetSize());
// Reset append chain
pAppendChainRoot = NULL;
AppendText.Clear();
}
// Remove namespace ownership
// A top-down traversal of the namespace stacks is guaranteed to
// return any owned namespaces. if not found, no ownership.
if (PrefixNamespaceStack.GetSize() > 0)
{
UPInt len = PrefixNamespaceStack.GetSize();
for (SInt i=(SInt)len-1; i >= 0; i--)
{
PrefixOwnership po = PrefixNamespaceStack[i];
if (po.Owner != pnode)
break;
PrefixNamespaceStack.PopBack();
}
}
if (DefaultNamespaceStack.GetSize() > 0)
{
PrefixOwnership po = DefaultNamespaceStack.Back();
if (po.Owner == pnode)
DefaultNamespaceStack.PopBack();
}
// Pop stack
ParseStack.PopBack();
}
//
// Namespace mapping reported by XML parser
//
// Next tag element will define the namespace scope.
//
void GFxXMLDOMBuilder::PrefixMapping(const GFxXMLStringRef& prefix,
const GFxXMLStringRef& uri)
{
#ifdef GFC_XML_DOCBUILDER_TRACE
GFC_DEBUG_ASSERT(pLocator, "Locator not set!");
char db0[MAX_DEBUG_STRING_LENGTH];
char db1[MAX_DEBUG_STRING_LENGTH];
SafeStringCopyWithSentinel(prefix.ToCStr(), prefix.GetSize(),
db0, MAX_DEBUG_STRING_LENGTH);
SafeStringCopyWithSentinel(uri.ToCStr(), uri.GetSize(), db1,
MAX_DEBUG_STRING_LENGTH);
GFC_DEBUG_MESSAGE4(1,
"[%d, %d] GFxXMLDocumentBuilder::StartPrefixMapping('%.16s', '%.16s')",
pLocator->Line, pLocator->Column, db0, db1);
#endif
// Copy the number of bytes loaded
LoadedBytes = pLocator->LoadedBytes;
GPtr<GFxXMLObjectManager> memMgr = pDoc->MemoryManager;
GPtr<GFxXMLPrefix> pPfxObj = *memMgr->CreatePrefix(
memMgr->CreateString(prefix.ToCStr(), prefix.GetSize()),
memMgr->CreateString(uri.ToCStr(), uri.GetSize()));
// Add prefix namespaces to prefix stack
if (prefix.GetSize() > 0)
{
// Owner will be set when next start element is encountered.
PrefixNamespaceStack.PushBack(PrefixOwnership(pPfxObj, NULL));
}
// Add default namespaces to dns stack
else
{
// Why is this in a separate stack?
// Elements without a prefix may inherit a default namespace
// from any of its ancestors. keeping it in a separate stack
// makes lookup Theta(1).
// Owner will be set when next start element is encountered.
DefaultNamespaceStack.PushBack(PrefixOwnership(pPfxObj, NULL));
}
}
//
// Text data reported by XML parser
//
void GFxXMLDOMBuilder::Characters(const GFxXMLStringRef& text)
{
#ifdef GFC_XML_DOCBUILDER_TRACE
GFC_DEBUG_ASSERT(pLocator, "Locator not set!");
char db0[MAX_DEBUG_STRING_LENGTH];
SafeStringCopyWithSentinel(text.ToCStr(), text.GetSize(), db0,
MAX_DEBUG_STRING_LENGTH);
GFC_DEBUG_MESSAGE3(1,
"[%d, %d] GFxXMLDocumentBuilder::Characters('%.16s')",
pLocator->Line, pLocator->Column, db0);
#endif
// Copy the number of bytes loaded
LoadedBytes = pLocator->LoadedBytes;
GASSERT(ParseStack.GetSize() > 0);
GPtr<GFxXMLObjectManager> memMgr = pDoc->MemoryManager;
if (pAppendChainRoot.GetPtr() == NULL)
{
pAppendChainRoot = *memMgr->CreateTextNode(memMgr->EmptyString());
AppendText.AppendString(text.ToCStr(), text.GetSize());
}
else
{
AppendText.AppendString(text.ToCStr(), text.GetSize());
}
}
//
// Ignored whitespace reported by XML parser
//
void GFxXMLDOMBuilder::IgnorableWhitespace(const GFxXMLStringRef& ws)
{
GUNUSED(ws);
#ifdef GFC_XML_DOCBUILDER_TRACE
GFC_DEBUG_ASSERT(pLocator, "Locator not set!");
char db0[MAX_DEBUG_STRING_LENGTH];
SafeStringCopyWithSentinel(ws.ToCStr(), ws.GetSize(), db0,
MAX_DEBUG_STRING_LENGTH);
GFC_DEBUG_MESSAGE3(1,
"[%d, %d] GFxXMLDocumentBuilder::IgnorableWhitespace('%.16s')",
pLocator->Line, pLocator->Column, db0);
#endif
// copy the number of bytes loaded
LoadedBytes = pLocator->LoadedBytes;
// Do nothing
}
//
// Skipped entity reported by XML parser
//
void GFxXMLDOMBuilder::SkippedEntity(const GFxXMLStringRef& name)
{
GUNUSED(name);
#ifdef GFC_XML_DOCBUILDER_TRACE
GFC_DEBUG_ASSERT(pLocator, "Locator not set!");
char db0[MAX_DEBUG_STRING_LENGTH];
SafeStringCopyWithSentinel(name.ToCStr(), name.GetSize(),
db0, MAX_DEBUG_STRING_LENGTH);
GFC_DEBUG_MESSAGE3(1,
"[%d, %d] GFxXMLDocumentBuilder::SkippedEntity('%.16s')",
pLocator->Line, pLocator->Column, db0);
#endif
// Copy the number of bytes loaded
LoadedBytes = pLocator->LoadedBytes;
// Do nothing
}
//
// Document locater registration
//
void GFxXMLDOMBuilder::SetDocumentLocator(const GFxXMLParserLocator* plocator)
{
#ifdef GFC_XML_DOCBUILDER_TRACE
GFC_DEBUG_MESSAGE(1, "GFxXMLDocumentBuilder::SetDocumentLocator");
#endif
pLocator = plocator;
}
//
// Comment found by XML parser
//
void GFxXMLDOMBuilder::Comment(const GFxXMLStringRef& text)
{
GUNUSED(text);
#ifdef GFC_XML_DOCBUILDER_TRACE
GFC_DEBUG_ASSERT(pLocator, "Locator not set!");
char db0[MAX_DEBUG_STRING_LENGTH];
SafeStringCopyWithSentinel(text.ToCStr(), text.GetSize(), db0,
MAX_DEBUG_STRING_LENGTH);
GFC_DEBUG_MESSAGE3(1, "[%d, %d] GFxXMLDocumentBuilder::Comment('%.16s')",
pLocator->Line, pLocator->Column, db0);
#endif
// Copy the number of bytes loaded
LoadedBytes = pLocator->LoadedBytes;
// Do nothing
}
//
// Error reported by XML parser
//
void GFxXMLDOMBuilder::Error(const GFxXMLParserException& exception)
{
GUNUSED(exception);
#ifdef GFC_XML_DOCBUILDER_TRACE
GFC_DEBUG_ASSERT(pLocator, "Locator not set!");
char db0[MAX_DEBUG_STRING_LENGTH];
SafeStringCopyWithSentinel(exception.ErrorMessage.ToCStr(),
exception.ErrorMessage.GetSize(), db0, MAX_DEBUG_STRING_LENGTH);
GFC_DEBUG_MESSAGE3(1, "[%d, %d] GFxXMLDocumentBuilder::Error('%.64s')",
pLocator->Line, pLocator->Column, db0);
#endif
// Copy the number of bytes loaded
LoadedBytes = pLocator->LoadedBytes;
GFC_DEBUG_ERROR3(1, "Document builder @ line:%d col:%d - %.64s\n",
pLocator->Line,
pLocator->Column,
exception.ErrorMessage.ToCStr());
bError = true;
}
//
// Fatal error reported by XML parser
//
void GFxXMLDOMBuilder::FatalError(const GFxXMLParserException& exception)
{
GUNUSED(exception);
#ifdef GFC_XML_DOCBUILDER_TRACE
GFC_DEBUG_ASSERT(pLocator, "Locator not set!");
char db0[MAX_DEBUG_STRING_LENGTH];
SafeStringCopyWithSentinel(exception.ErrorMessage.ToCStr(),
exception.ErrorMessage.GetSize(), db0, MAX_DEBUG_STRING_LENGTH);
GFC_DEBUG_MESSAGE3(1, "[%d, %d] GFxXMLDocumentBuilder::FatalError('%.64s')",
pLocator->Line, pLocator->Column, db0);
#endif
// Copy the number of bytes loaded
LoadedBytes = pLocator->LoadedBytes;
GFC_DEBUG_ERROR3(1, "Document builder @ line:%d col:%d - %.64s\n",
pLocator->Line,
pLocator->Column,
exception.ErrorMessage.ToCStr());
bError = true;
}
//
// Warning reported by XML parser
//
void GFxXMLDOMBuilder::Warning(const GFxXMLParserException& exception)
{
GUNUSED(exception);
#ifdef GFC_XML_DOCBUILDER_TRACE
GFC_DEBUG_ASSERT(pLocator, "Locator not set!");
char db0[MAX_DEBUG_STRING_LENGTH];
SafeStringCopyWithSentinel(exception.ErrorMessage.ToCStr(),
exception.ErrorMessage.GetSize(), db0, MAX_DEBUG_STRING_LENGTH);
GFC_DEBUG_MESSAGE3(1, "[%d, %d] GFxXMLDocumentBuilder::Warning('%.64s')",
pLocator->Line, pLocator->Column, db0);
#endif
// Copy the number of bytes loaded
LoadedBytes = pLocator->LoadedBytes;
GFC_DEBUG_WARNING3(1, "Document builder @ line:%d col:%d - %.64s\n",
pLocator->Line,
pLocator->Column,
exception.ErrorMessage.ToCStr());
}
//
// Return true if the text node only contains whitespace
//
bool CheckWhiteSpaceNode(GFxXMLTextNode* textNode)
{
const char* buffer = textNode->Value.GetBuffer();
bool allws = true;
UInt32 utf8char;
while ( (utf8char = GUTF8Util::DecodeNextChar(&buffer)) != 0 )
{
if (!G_iswspace((wchar_t)utf8char))
{
allws = false;
break;
}
}
return allws;
}
//
// Helper function for DOM traversal
//
void DropWhiteSpaceNodesHelper(GFxXMLElementNode* elemNode)
{
GFxXMLNode* child = elemNode->FirstChild;
GFxXMLNode* temp = child;
while (child != NULL)
{
temp = child->NextSibling;
if (child->Type == GFxXMLElementNodeType)
DropWhiteSpaceNodesHelper((GFxXMLElementNode*)child);
else if (child->Type == GFxXMLTextNodeType)
{
if (CheckWhiteSpaceNode((GFxXMLTextNode*)child))
{
// Remove it
elemNode->RemoveChild(child);
}
}
child = temp;
}
}
//
// Drop all text nodes containing only whitespace from the DOM tree.
// This emulates the behavior of not processing unnecessary whitespace
// in the XML document.
//
void GFxXMLDOMBuilder::DropWhiteSpaceNodes(GFxXMLDocument* document)
{
for (GFxXMLNode* child = document->FirstChild; child != NULL;
child = child->NextSibling)
{
if (child->Type == GFxXMLElementNodeType)
DropWhiteSpaceNodesHelper((GFxXMLElementNode*)child);
}
}
#endif // #ifndef GFC_NO_XML_SUPPORT