summaryrefslogtreecommitdiff
path: root/core/src/fxcrt/fx_xml_parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/fxcrt/fx_xml_parser.cpp')
-rw-r--r--core/src/fxcrt/fx_xml_parser.cpp1017
1 files changed, 1017 insertions, 0 deletions
diff --git a/core/src/fxcrt/fx_xml_parser.cpp b/core/src/fxcrt/fx_xml_parser.cpp
new file mode 100644
index 0000000000..85e9544342
--- /dev/null
+++ b/core/src/fxcrt/fx_xml_parser.cpp
@@ -0,0 +1,1017 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "../../include/fxcrt/fx_xml.h"
+#include "xml_int.h"
+CXML_Parser::~CXML_Parser()
+{
+ if (m_bOwnedStream) {
+ m_pDataAcc->Release();
+ }
+}
+FX_BOOL CXML_Parser::Init(FX_LPBYTE pBuffer, size_t size)
+{
+ if (m_pAllocator) {
+ m_pDataAcc = FX_NewAtAllocator(m_pAllocator)CXML_DataBufAcc(pBuffer, size, m_pAllocator);
+ } else {
+ m_pDataAcc = FX_NEW CXML_DataBufAcc(pBuffer, size, NULL);
+ }
+ if (!m_pDataAcc) {
+ return FALSE;
+ }
+ return Init(TRUE);
+}
+FX_BOOL CXML_Parser::Init(IFX_FileRead *pFileRead)
+{
+ if (m_pAllocator) {
+ m_pDataAcc = FX_NewAtAllocator(m_pAllocator)CXML_DataStmAcc(pFileRead, m_pAllocator);
+ } else {
+ m_pDataAcc = FX_NEW CXML_DataStmAcc(pFileRead, NULL);
+ }
+ if (!m_pDataAcc) {
+ return FALSE;
+ }
+ return Init(TRUE);
+}
+FX_BOOL CXML_Parser::Init(IFX_BufferRead *pBuffer)
+{
+ if (!pBuffer) {
+ return FALSE;
+ }
+ m_pDataAcc = pBuffer;
+ return Init(FALSE);
+}
+FX_BOOL CXML_Parser::Init(FX_BOOL bOwndedStream)
+{
+ m_bOwnedStream = bOwndedStream;
+ m_nOffset = 0;
+ return ReadNextBlock();
+}
+FX_BOOL CXML_Parser::ReadNextBlock()
+{
+ if (!m_pDataAcc->ReadNextBlock()) {
+ return FALSE;
+ }
+ m_pBuffer = m_pDataAcc->GetBlockBuffer();
+ m_dwBufferSize = m_pDataAcc->GetBlockSize();
+ m_nBufferOffset = m_pDataAcc->GetBlockOffset();
+ m_dwIndex = 0;
+ return m_dwBufferSize > 0;
+}
+FX_BOOL CXML_Parser::IsEOF()
+{
+ if (!m_pDataAcc->IsEOF()) {
+ return FALSE;
+ }
+ return m_dwIndex >= m_dwBufferSize;
+}
+#define FXCRTM_XML_CHARTYPE_Normal 0x00
+#define FXCRTM_XML_CHARTYPE_SpaceChar 0x01
+#define FXCRTM_XML_CHARTYPE_Letter 0x02
+#define FXCRTM_XML_CHARTYPE_Digital 0x04
+#define FXCRTM_XML_CHARTYPE_NameIntro 0x08
+#define FXCRTM_XML_CHARTYPE_NameChar 0x10
+#define FXCRTM_XML_CHARTYPE_HexDigital 0x20
+#define FXCRTM_XML_CHARTYPE_HexLowerLetter 0x40
+#define FXCRTM_XML_CHARTYPE_HexUpperLetter 0x60
+#define FXCRTM_XML_CHARTYPE_HexChar 0x60
+FX_BYTE g_FXCRT_XML_ByteTypes[256] = {
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,
+ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
+ 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x18,
+ 0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
+ 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
+ 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
+ 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
+ 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
+ 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
+ 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
+ 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
+ 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x01, 0x01,
+};
+FX_BOOL g_FXCRT_XML_IsWhiteSpace(FX_BYTE ch)
+{
+ return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_SpaceChar) != 0;
+}
+FX_BOOL g_FXCRT_XML_IsLetter(FX_BYTE ch)
+{
+ return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_Letter) != 0;
+}
+FX_BOOL g_FXCRT_XML_IsDigital(FX_BYTE ch)
+{
+ return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_Digital) != 0;
+}
+FX_BOOL g_FXCRT_XML_IsNameIntro(FX_BYTE ch)
+{
+ return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_NameIntro) != 0;
+}
+FX_BOOL g_FXCRT_XML_IsNameChar(FX_BYTE ch)
+{
+ return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_NameChar) != 0;
+}
+FX_BOOL g_FXCRT_XML_IsHexChar(FX_BYTE ch)
+{
+ return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_HexChar) != 0;
+}
+void CXML_Parser::SkipWhiteSpaces()
+{
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (IsEOF()) {
+ return;
+ }
+ do {
+ while (m_dwIndex < m_dwBufferSize && g_FXCRT_XML_IsWhiteSpace(m_pBuffer[m_dwIndex])) {
+ m_dwIndex ++;
+ }
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (m_dwIndex < m_dwBufferSize || IsEOF()) {
+ break;
+ }
+ } while (ReadNextBlock());
+}
+void CXML_Parser::GetName(CFX_ByteStringL &space, CFX_ByteStringL &name)
+{
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (IsEOF()) {
+ return;
+ }
+ CFX_ByteTextBuf buf(m_pAllocator);
+ FX_BYTE ch;
+ do {
+ while (m_dwIndex < m_dwBufferSize) {
+ ch = m_pBuffer[m_dwIndex];
+ if (ch == ':') {
+ buf.GetByteStringL(space);
+ buf.Clear();
+ } else if (g_FXCRT_XML_IsNameChar(ch)) {
+ buf.AppendChar(ch);
+ } else {
+ break;
+ }
+ m_dwIndex ++;
+ }
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (m_dwIndex < m_dwBufferSize || IsEOF()) {
+ break;
+ }
+ } while (ReadNextBlock());
+ buf.GetByteStringL(name);
+}
+void CXML_Parser::SkipLiterals(FX_BSTR str)
+{
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (IsEOF()) {
+ return;
+ }
+ FX_INT32 i = 0, iLen = str.GetLength();
+ do {
+ while (m_dwIndex < m_dwBufferSize) {
+ if (str.GetAt(i) != m_pBuffer[m_dwIndex ++]) {
+ i = 0;
+ } else {
+ i ++;
+ if (i == iLen) {
+ break;
+ }
+ }
+ }
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (i == iLen) {
+ return;
+ }
+ if (m_dwIndex < m_dwBufferSize || IsEOF()) {
+ break;
+ }
+ } while (ReadNextBlock());
+ while (!m_pDataAcc->IsEOF()) {
+ ReadNextBlock();
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwBufferSize;
+ }
+ m_dwIndex = m_dwBufferSize;
+}
+FX_DWORD CXML_Parser::GetCharRef()
+{
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (IsEOF()) {
+ return 0;
+ }
+ FX_BYTE ch;
+ FX_INT32 iState = 0;
+ CFX_ByteTextBuf buf(m_pAllocator);
+ FX_DWORD code = 0;
+ do {
+ while (m_dwIndex < m_dwBufferSize) {
+ ch = m_pBuffer[m_dwIndex];
+ switch (iState) {
+ case 0:
+ if (ch == '#') {
+ m_dwIndex ++;
+ iState = 2;
+ break;
+ }
+ iState = 1;
+ case 1:
+ m_dwIndex ++;
+ if (ch == ';') {
+ CFX_ByteStringC ref = buf.GetByteString();
+ if (ref == FX_BSTRC("gt")) {
+ code = '>';
+ } else if (ref == FX_BSTRC("lt")) {
+ code = '<';
+ } else if (ref == FX_BSTRC("amp")) {
+ code = '&';
+ } else if (ref == FX_BSTRC("apos")) {
+ code = '\'';
+ } else if (ref == FX_BSTRC("quot")) {
+ code = '"';
+ }
+ iState = 10;
+ break;
+ }
+ buf.AppendByte(ch);
+ break;
+ case 2:
+ if (ch == 'x') {
+ m_dwIndex ++;
+ iState = 4;
+ break;
+ }
+ iState = 3;
+ case 3:
+ m_dwIndex ++;
+ if (ch == ';') {
+ iState = 10;
+ break;
+ }
+ if (g_FXCRT_XML_IsDigital(ch)) {
+ code = code * 10 + ch - '0';
+ }
+ break;
+ case 4:
+ m_dwIndex ++;
+ if (ch == ';') {
+ iState = 10;
+ break;
+ }
+ FX_BYTE nHex = g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_HexChar;
+ if (nHex) {
+ if (nHex == FXCRTM_XML_CHARTYPE_HexDigital) {
+ code = (code << 4) + ch - '0';
+ } else if (nHex == FXCRTM_XML_CHARTYPE_HexLowerLetter) {
+ code = (code << 4) + ch - 87;
+ } else {
+ code = (code << 4) + ch - 55;
+ }
+ }
+ break;
+ }
+ if (iState == 10) {
+ break;
+ }
+ }
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (iState == 10 || m_dwIndex < m_dwBufferSize || IsEOF()) {
+ break;
+ }
+ } while (ReadNextBlock());
+ return code;
+}
+void CXML_Parser::GetAttrValue(CFX_WideStringL &value)
+{
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (IsEOF()) {
+ return;
+ }
+ CFX_UTF8Decoder decoder(m_pAllocator);
+ FX_BYTE mark = 0, ch;
+ do {
+ while (m_dwIndex < m_dwBufferSize) {
+ ch = m_pBuffer[m_dwIndex];
+ if (mark == 0) {
+ if (ch != '\'' && ch != '"') {
+ return;
+ }
+ mark = ch;
+ m_dwIndex ++;
+ ch = 0;
+ continue;
+ }
+ m_dwIndex ++;
+ if (ch == mark) {
+ break;
+ }
+ if (ch == '&') {
+ decoder.AppendChar(GetCharRef());
+ if (IsEOF()) {
+ decoder.GetResult(value);
+ return;
+ }
+ } else {
+ decoder.Input(ch);
+ }
+ }
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (ch == mark || m_dwIndex < m_dwBufferSize || IsEOF()) {
+ break;
+ }
+ } while (ReadNextBlock());
+ decoder.GetResult(value);
+}
+void CXML_Parser::GetTagName(CFX_ByteStringL &space, CFX_ByteStringL &name, FX_BOOL &bEndTag, FX_BOOL bStartTag)
+{
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (IsEOF()) {
+ return;
+ }
+ bEndTag = FALSE;
+ FX_BYTE ch;
+ FX_INT32 iState = bStartTag ? 1 : 0;
+ do {
+ while (m_dwIndex < m_dwBufferSize) {
+ ch = m_pBuffer[m_dwIndex];
+ switch (iState) {
+ case 0:
+ m_dwIndex ++;
+ if (ch != '<') {
+ break;
+ }
+ iState = 1;
+ break;
+ case 1:
+ if (ch == '?') {
+ m_dwIndex ++;
+ SkipLiterals(FX_BSTRC("?>"));
+ iState = 0;
+ break;
+ } else if (ch == '!') {
+ m_dwIndex ++;
+ SkipLiterals(FX_BSTRC("-->"));
+ iState = 0;
+ break;
+ }
+ if (ch == '/') {
+ m_dwIndex ++;
+ GetName(space, name);
+ bEndTag = TRUE;
+ } else {
+ GetName(space, name);
+ bEndTag = FALSE;
+ }
+ return;
+ }
+ }
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (m_dwIndex < m_dwBufferSize || IsEOF()) {
+ break;
+ }
+ } while (ReadNextBlock());
+}
+CXML_Element* CXML_Parser::ParseElement(CXML_Element* pParent, FX_BOOL bStartTag)
+{
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (IsEOF()) {
+ return NULL;
+ }
+ CFX_ByteStringL tag_name, tag_space;
+ FX_BOOL bEndTag;
+ GetTagName(tag_space, tag_name, bEndTag, bStartTag);
+ if (tag_name.IsEmpty() || bEndTag) {
+ tag_space.Empty(m_pAllocator);
+ return NULL;
+ }
+ CXML_Element* pElement;
+ if (m_pAllocator) {
+ pElement = FX_NewAtAllocator(m_pAllocator)CXML_Element(m_pAllocator);
+ } else {
+ pElement = FX_NEW CXML_Element;
+ }
+ if (pElement) {
+ pElement->m_pParent = pParent;
+ pElement->SetTag(tag_space, tag_name);
+ }
+ tag_space.Empty(m_pAllocator);
+ tag_name.Empty(m_pAllocator);
+ if (!pElement) {
+ return NULL;
+ }
+ do {
+ CFX_ByteStringL attr_space, attr_name;
+ while (m_dwIndex < m_dwBufferSize) {
+ SkipWhiteSpaces();
+ if (IsEOF()) {
+ break;
+ }
+ if (!g_FXCRT_XML_IsNameIntro(m_pBuffer[m_dwIndex])) {
+ break;
+ }
+ attr_space.Empty(m_pAllocator);
+ attr_name.Empty(m_pAllocator);
+ GetName(attr_space, attr_name);
+ SkipWhiteSpaces();
+ if (IsEOF()) {
+ break;
+ }
+ if (m_pBuffer[m_dwIndex] != '=') {
+ break;
+ }
+ m_dwIndex ++;
+ SkipWhiteSpaces();
+ if (IsEOF()) {
+ break;
+ }
+ CFX_WideStringL attr_value;
+ GetAttrValue(attr_value);
+ pElement->m_AttrMap.SetAt(attr_space, attr_name, attr_value, m_pAllocator);
+ attr_value.Empty(m_pAllocator);
+ }
+ attr_space.Empty(m_pAllocator);
+ attr_name.Empty(m_pAllocator);
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (m_dwIndex < m_dwBufferSize || IsEOF()) {
+ break;
+ }
+ } while (ReadNextBlock());
+ SkipWhiteSpaces();
+ if (IsEOF()) {
+ return pElement;
+ }
+ FX_BYTE ch = m_pBuffer[m_dwIndex ++];
+ if (ch == '/') {
+ m_dwIndex ++;
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ return pElement;
+ }
+ if (ch != '>') {
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (m_pAllocator) {
+ FX_DeleteAtAllocator(pElement, m_pAllocator, CXML_Element);
+ } else {
+ delete pElement;
+ }
+ return NULL;
+ }
+ SkipWhiteSpaces();
+ if (IsEOF()) {
+ return pElement;
+ }
+ CFX_UTF8Decoder decoder(m_pAllocator);
+ CFX_WideTextBuf content(m_pAllocator);
+ FX_BOOL bCDATA = FALSE;
+ FX_INT32 iState = 0;
+ do {
+ while (m_dwIndex < m_dwBufferSize) {
+ ch = m_pBuffer[m_dwIndex ++];
+ switch (iState) {
+ case 0:
+ if (ch == '<') {
+ iState = 1;
+ } else if (ch == '&') {
+ decoder.ClearStatus();
+ decoder.AppendChar(GetCharRef());
+ } else {
+ decoder.Input(ch);
+ }
+ break;
+ case 1:
+ if (ch == '!') {
+ iState = 2;
+ } else if (ch == '?') {
+ SkipLiterals(FX_BSTRC("?>"));
+ SkipWhiteSpaces();
+ iState = 0;
+ } else if (ch == '/') {
+ CFX_ByteStringL space, name;
+ GetName(space, name);
+ space.Empty(m_pAllocator);
+ name.Empty(m_pAllocator);
+ SkipWhiteSpaces();
+ m_dwIndex ++;
+ iState = 10;
+ } else {
+ content << decoder.GetResult();
+ CFX_WideStringL dataStr;
+ content.GetWideStringL(dataStr);
+ if (!bCDATA && !m_bSaveSpaceChars) {
+ dataStr.TrimRight((FX_LPCWSTR)L" \t\r\n");
+ }
+ InsertContentSegment(bCDATA, dataStr, pElement);
+ dataStr.Empty(m_pAllocator);
+ content.Clear();
+ decoder.Clear();
+ bCDATA = FALSE;
+ iState = 0;
+ m_dwIndex --;
+ CXML_Element* pSubElement = ParseElement(pElement, TRUE);
+ if (pSubElement == NULL) {
+ break;
+ }
+ pSubElement->m_pParent = pElement;
+ pElement->m_Children.Add((FX_LPVOID)CXML_Element::Element);
+ pElement->m_Children.Add(pSubElement);
+ SkipWhiteSpaces();
+ }
+ break;
+ case 2:
+ if (ch == '[') {
+ SkipLiterals(FX_BSTRC("]]>"));
+ } else if (ch == '-') {
+ m_dwIndex ++;
+ SkipLiterals(FX_BSTRC("-->"));
+ } else {
+ SkipLiterals(FX_BSTRC(">"));
+ }
+ decoder.Clear();
+ SkipWhiteSpaces();
+ iState = 0;
+ break;
+ }
+ if (iState == 10) {
+ break;
+ }
+ }
+ m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
+ if (iState == 10 || m_dwIndex < m_dwBufferSize || IsEOF()) {
+ break;
+ }
+ } while (ReadNextBlock());
+ content << decoder.GetResult();
+ CFX_WideStringL dataStr;
+ content.GetWideStringL(dataStr);
+ if (!m_bSaveSpaceChars) {
+ dataStr.TrimRight((FX_LPCWSTR)L" \t\r\n");
+ }
+ InsertContentSegment(bCDATA, dataStr, pElement);
+ dataStr.Empty(m_pAllocator);
+ content.Clear();
+ decoder.Clear();
+ bCDATA = FALSE;
+ return pElement;
+}
+void CXML_Parser::InsertContentSegment(FX_BOOL bCDATA, FX_WSTR content, CXML_Element* pElement)
+{
+ if (content.IsEmpty()) {
+ return;
+ }
+ CXML_Content* pContent;
+ if (m_pAllocator) {
+ pContent = FX_NewAtAllocator(m_pAllocator)CXML_Content;
+ } else {
+ pContent = FX_NEW CXML_Content;
+ }
+ if (!pContent) {
+ return;
+ }
+ pContent->Set(bCDATA, content, m_pAllocator);
+ pElement->m_Children.Add((FX_LPVOID)CXML_Element::Content);
+ pElement->m_Children.Add(pContent);
+}
+static CXML_Element* XML_ContinueParse(CXML_Parser &parser, FX_BOOL bSaveSpaceChars, FX_FILESIZE* pParsedSize)
+{
+ parser.m_bSaveSpaceChars = bSaveSpaceChars;
+ CXML_Element* pElement = parser.ParseElement(NULL, FALSE);
+ if (pParsedSize) {
+ *pParsedSize = parser.m_nOffset;
+ }
+ return pElement;
+}
+CXML_Element* CXML_Element::Parse(const void* pBuffer, size_t size, FX_BOOL bSaveSpaceChars, FX_FILESIZE* pParsedSize, IFX_Allocator* pAllocator)
+{
+ CXML_Parser parser(pAllocator);
+ if (!parser.Init((FX_LPBYTE)pBuffer, size)) {
+ return NULL;
+ }
+ return XML_ContinueParse(parser, bSaveSpaceChars, pParsedSize);
+}
+CXML_Element* CXML_Element::Parse(IFX_FileRead *pFile, FX_BOOL bSaveSpaceChars, FX_FILESIZE* pParsedSize, IFX_Allocator* pAllocator)
+{
+ CXML_Parser parser(pAllocator);
+ if (!parser.Init(pFile)) {
+ return NULL;
+ }
+ return XML_ContinueParse(parser, bSaveSpaceChars, pParsedSize);
+}
+CXML_Element* CXML_Element::Parse(IFX_BufferRead *pBuffer, FX_BOOL bSaveSpaceChars, FX_FILESIZE* pParsedSize, IFX_Allocator* pAllocator)
+{
+ CXML_Parser parser(pAllocator);
+ if (!parser.Init(pBuffer)) {
+ return NULL;
+ }
+ return XML_ContinueParse(parser, bSaveSpaceChars, pParsedSize);
+}
+CXML_Element::CXML_Element(IFX_Allocator* pAllocator)
+ : m_pParent(NULL)
+ , m_QSpaceName()
+ , m_TagName()
+ , m_AttrMap()
+ , m_Children(pAllocator)
+{
+}
+CXML_Element::CXML_Element(FX_BSTR qSpace, FX_BSTR tagName, IFX_Allocator* pAllocator)
+ : m_pParent(NULL)
+ , m_QSpaceName()
+ , m_TagName()
+ , m_AttrMap()
+ , m_Children(pAllocator)
+{
+ m_QSpaceName.Set(qSpace, pAllocator);
+ m_TagName.Set(tagName, pAllocator);
+}
+CXML_Element::CXML_Element(FX_BSTR qTagName, IFX_Allocator* pAllocator)
+ : m_pParent(NULL)
+ , m_QSpaceName()
+ , m_TagName()
+ , m_AttrMap()
+ , m_Children(pAllocator)
+{
+ SetTag(qTagName);
+}
+CXML_Element::~CXML_Element()
+{
+ Empty();
+}
+void CXML_Element::Empty()
+{
+ IFX_Allocator* pAllocator = m_Children.m_pAllocator;
+ m_QSpaceName.Empty(pAllocator);
+ m_TagName.Empty(pAllocator);
+ m_AttrMap.RemoveAll(pAllocator);
+ RemoveChildren();
+}
+void CXML_Element::RemoveChildren()
+{
+ IFX_Allocator* pAllocator = m_Children.m_pAllocator;
+ for (int i = 0; i < m_Children.GetSize(); i += 2) {
+ ChildType type = (ChildType)(FX_UINTPTR)m_Children.GetAt(i);
+ if (type == Content) {
+ CXML_Content* content = (CXML_Content*)m_Children.GetAt(i + 1);
+ if (pAllocator) {
+ FX_DeleteAtAllocator(content, pAllocator, CXML_Content);
+ } else {
+ delete content;
+ }
+ } else if (type == Element) {
+ CXML_Element* child = (CXML_Element*)m_Children.GetAt(i + 1);
+ child->RemoveChildren();
+ if (pAllocator) {
+ FX_DeleteAtAllocator(child, pAllocator, CXML_Element);
+ } else {
+ delete child;
+ }
+ }
+ }
+ m_Children.RemoveAll();
+}
+CFX_ByteString CXML_Element::GetTagName(FX_BOOL bQualified) const
+{
+ if (!bQualified || m_QSpaceName.IsEmpty()) {
+ return m_TagName;
+ }
+ CFX_ByteString bsTag = m_QSpaceName;
+ bsTag += ":";
+ bsTag += m_TagName;
+ return bsTag;
+}
+void CXML_Element::GetTagName(CFX_ByteStringL &tagName, FX_BOOL bQualified) const
+{
+ IFX_Allocator* pAllocator = m_Children.m_pAllocator;
+ if (!bQualified || m_QSpaceName.IsEmpty()) {
+ tagName.Set(m_TagName, pAllocator);
+ return;
+ }
+ FX_LPSTR str = tagName.AllocBuffer(m_QSpaceName.GetLength() + m_TagName.GetLength() + 2, pAllocator);
+ if (!str) {
+ return;
+ }
+ FXSYS_memcpy32(str, m_QSpaceName.GetCStr(), m_QSpaceName.GetLength());
+ str += m_QSpaceName.GetLength();
+ *str = ':';
+ str ++;
+ FXSYS_memcpy32(str, m_TagName.GetCStr(), m_TagName.GetLength());
+ str += m_TagName.GetLength();
+ *str = '\0';
+}
+CFX_ByteString CXML_Element::GetNamespace(FX_BOOL bQualified) const
+{
+ if (bQualified) {
+ return m_QSpaceName;
+ }
+ return GetNamespaceURI(m_QSpaceName);
+}
+void CXML_Element::GetNamespace(CFX_ByteStringL &nameSpace, FX_BOOL bQualified) const
+{
+ IFX_Allocator* pAllocator = m_Children.m_pAllocator;
+ if (bQualified) {
+ nameSpace.Set(m_QSpaceName, pAllocator);
+ return;
+ }
+ GetNamespaceURI(m_QSpaceName, nameSpace);
+}
+CFX_ByteString CXML_Element::GetNamespaceURI(FX_BSTR qName) const
+{
+ const CFX_WideStringL* pwsSpace;
+ const CXML_Element *pElement = this;
+ do {
+ if (qName.IsEmpty()) {
+ pwsSpace = pElement->m_AttrMap.Lookup(FX_BSTRC(""), FX_BSTRC("xmlns"));
+ } else {
+ pwsSpace = pElement->m_AttrMap.Lookup(FX_BSTRC("xmlns"), qName);
+ }
+ if (pwsSpace) {
+ break;
+ }
+ pElement = pElement->GetParent();
+ } while(pElement);
+ return pwsSpace ? FX_UTF8Encode(*pwsSpace) : CFX_ByteString();
+}
+void CXML_Element::GetNamespaceURI(FX_BSTR qName, CFX_ByteStringL &uri) const
+{
+ IFX_Allocator* pAllocator = m_Children.m_pAllocator;
+ const CFX_WideStringL* pwsSpace;
+ const CXML_Element *pElement = this;
+ do {
+ if (qName.IsEmpty()) {
+ pwsSpace = pElement->m_AttrMap.Lookup(FX_BSTRC(""), FX_BSTRC("xmlns"));
+ } else {
+ pwsSpace = pElement->m_AttrMap.Lookup(FX_BSTRC("xmlns"), qName);
+ }
+ if (pwsSpace) {
+ break;
+ }
+ pElement = pElement->GetParent();
+ } while(pElement);
+ if (pwsSpace) {
+ FX_UTF8Encode(pwsSpace->GetPtr(), pwsSpace->GetLength(), uri, pAllocator);
+ }
+}
+void CXML_Element::GetAttrByIndex(int index, CFX_ByteString& space, CFX_ByteString& name, CFX_WideString& value) const
+{
+ if (index < 0 || index >= m_AttrMap.GetSize()) {
+ return;
+ }
+ CXML_AttrItem& item = m_AttrMap.GetAt(index);
+ space = item.m_QSpaceName;
+ name = item.m_AttrName;
+ value = item.m_Value;
+}
+void CXML_Element::GetAttrByIndex(int index, CFX_ByteStringL &space, CFX_ByteStringL &name, CFX_WideStringL &value) const
+{
+ if (index < 0 || index >= m_AttrMap.GetSize()) {
+ return;
+ }
+ IFX_Allocator* pAllocator = m_Children.m_pAllocator;
+ CXML_AttrItem& item = m_AttrMap.GetAt(index);
+ space.Set(item.m_QSpaceName, pAllocator);
+ name.Set(item.m_AttrName, pAllocator);
+ value.Set(item.m_Value, pAllocator);
+}
+FX_BOOL CXML_Element::HasAttr(FX_BSTR name) const
+{
+ CFX_ByteStringC bsSpace, bsName;
+ FX_XML_SplitQualifiedName(name, bsSpace, bsName);
+ return m_AttrMap.Lookup(bsSpace, bsName) != NULL;
+}
+FX_BOOL CXML_Element::GetAttrValue(FX_BSTR name, CFX_WideString& attribute) const
+{
+ CFX_ByteStringC bsSpace, bsName;
+ FX_XML_SplitQualifiedName(name, bsSpace, bsName);
+ const CFX_WideStringL* pValue = m_AttrMap.Lookup(bsSpace, bsName);
+ if (pValue) {
+ attribute = CFX_WideString(pValue->GetPtr(), pValue->GetLength());
+ return TRUE;
+ }
+ return FALSE;
+}
+const CFX_WideStringL* CXML_Element::GetAttrValuePtr(FX_BSTR name) const
+{
+ CFX_ByteStringC bsSpace, bsName;
+ FX_XML_SplitQualifiedName(name, bsSpace, bsName);
+ return m_AttrMap.Lookup(bsSpace, bsName);
+}
+FX_BOOL CXML_Element::GetAttrValue(FX_BSTR space, FX_BSTR name, CFX_WideString& attribute) const
+{
+ const CFX_WideStringL* pValue = m_AttrMap.Lookup(space, name);
+ if (pValue) {
+ attribute = CFX_WideString(pValue->GetPtr(), pValue->GetLength());
+ return TRUE;
+ }
+ return FALSE;
+}
+const CFX_WideStringL* CXML_Element::GetAttrValuePtr(FX_BSTR space, FX_BSTR name) const
+{
+ return m_AttrMap.Lookup(space, name);
+}
+FX_BOOL CXML_Element::GetAttrInteger(FX_BSTR name, int& attribute) const
+{
+ CFX_ByteStringC bsSpace, bsName;
+ FX_XML_SplitQualifiedName(name, bsSpace, bsName);
+ const CFX_WideStringL* pwsValue = m_AttrMap.Lookup(bsSpace, bsName);
+ if (pwsValue) {
+ attribute = pwsValue->GetInteger();
+ return TRUE;
+ }
+ return FALSE;
+}
+FX_BOOL CXML_Element::GetAttrInteger(FX_BSTR space, FX_BSTR name, int& attribute) const
+{
+ const CFX_WideStringL* pwsValue = m_AttrMap.Lookup(space, name);
+ if (pwsValue) {
+ attribute = pwsValue->GetInteger();
+ return TRUE;
+ }
+ return FALSE;
+}
+FX_BOOL CXML_Element::GetAttrFloat(FX_BSTR name, FX_FLOAT& attribute) const
+{
+ CFX_ByteStringC bsSpace, bsName;
+ FX_XML_SplitQualifiedName(name, bsSpace, bsName);
+ return GetAttrFloat(bsSpace, bsName, attribute);
+}
+FX_BOOL CXML_Element::GetAttrFloat(FX_BSTR space, FX_BSTR name, FX_FLOAT& attribute) const
+{
+ CFX_WideString value;
+ const CFX_WideStringL* pValue = m_AttrMap.Lookup(space, name);
+ if (pValue) {
+ attribute = pValue->GetFloat();
+ return TRUE;
+ }
+ return FALSE;
+}
+FX_DWORD CXML_Element::CountChildren() const
+{
+ return m_Children.GetSize() / 2;
+}
+CXML_Element::ChildType CXML_Element::GetChildType(FX_DWORD index) const
+{
+ index <<= 1;
+ if (index >= (FX_DWORD)m_Children.GetSize()) {
+ return Invalid;
+ }
+ return (ChildType)(FX_UINTPTR)m_Children.GetAt(index);
+}
+CFX_WideString CXML_Element::GetContent(FX_DWORD index) const
+{
+ index <<= 1;
+ if (index >= (FX_DWORD)m_Children.GetSize() ||
+ (ChildType)(FX_UINTPTR)m_Children.GetAt(index) != Content) {
+ return CFX_WideString();
+ }
+ CXML_Content* pContent = (CXML_Content*)m_Children.GetAt(index + 1);
+ if (pContent) {
+ return pContent->m_Content;
+ }
+ return CFX_WideString();
+}
+const CFX_WideStringL* CXML_Element::GetContentPtr(FX_DWORD index) const
+{
+ index <<= 1;
+ if (index >= (FX_DWORD)m_Children.GetSize() ||
+ (ChildType)(FX_UINTPTR)m_Children.GetAt(index) != Content) {
+ return NULL;
+ }
+ CXML_Content* pContent = (CXML_Content*)m_Children.GetAt(index + 1);
+ if (pContent) {
+ return &pContent->m_Content;
+ }
+ return NULL;
+}
+CXML_Element* CXML_Element::GetElement(FX_DWORD index) const
+{
+ index <<= 1;
+ if (index >= (FX_DWORD)m_Children.GetSize() ||
+ (ChildType)(FX_UINTPTR)m_Children.GetAt(index) != Element) {
+ return NULL;
+ }
+ return (CXML_Element*)m_Children.GetAt(index + 1);
+}
+FX_DWORD CXML_Element::CountElements(FX_BSTR space, FX_BSTR tag) const
+{
+ int count = 0;
+ for (int i = 0; i < m_Children.GetSize(); i += 2) {
+ ChildType type = (ChildType)(FX_UINTPTR)m_Children.GetAt(i);
+ if (type != Element) {
+ continue;
+ }
+ CXML_Element* pKid = (CXML_Element*)m_Children.GetAt(i + 1);
+ if ((space.IsEmpty() || pKid->m_QSpaceName == space) && pKid->m_TagName == tag) {
+ count ++;
+ }
+ }
+ return count;
+}
+CXML_Element* CXML_Element::GetElement(FX_BSTR space, FX_BSTR tag, int index) const
+{
+ if (index < 0) {
+ return NULL;
+ }
+ for (int i = 0; i < m_Children.GetSize(); i += 2) {
+ ChildType type = (ChildType)(FX_UINTPTR)m_Children.GetAt(i);
+ if (type != Element) {
+ continue;
+ }
+ CXML_Element* pKid = (CXML_Element*)m_Children.GetAt(i + 1);
+ if ((!space.IsEmpty() && pKid->m_QSpaceName != space) || pKid->m_TagName != tag) {
+ continue;
+ }
+ if (index -- == 0) {
+ return pKid;
+ }
+ }
+ return NULL;
+}
+FX_DWORD CXML_Element::FindElement(CXML_Element *pChild) const
+{
+ for (int i = 0; i < m_Children.GetSize(); i += 2) {
+ if ((ChildType)(FX_UINTPTR)m_Children.GetAt(i) == Element &&
+ (CXML_Element*)m_Children.GetAt(i + 1) == pChild) {
+ return (FX_DWORD)(i >> 1);
+ }
+ }
+ return (FX_DWORD) - 1;
+}
+const CFX_WideStringL* CXML_AttrMap::Lookup(FX_BSTR space, FX_BSTR name) const
+{
+ if (m_pMap == NULL) {
+ return NULL;
+ }
+ for (int i = 0; i < m_pMap->GetSize(); i ++) {
+ CXML_AttrItem& item = GetAt(i);
+ if ((space.IsEmpty() || item.m_QSpaceName == space) && item.m_AttrName == name) {
+ return &item.m_Value;
+ }
+ }
+ return NULL;
+}
+void CXML_AttrMap::SetAt(FX_BSTR space, FX_BSTR name, FX_WSTR value, IFX_Allocator* pAllocator)
+{
+ for (int i = 0; i < GetSize(); i ++) {
+ CXML_AttrItem& item = GetAt(i);
+ if ((space.IsEmpty() || item.m_QSpaceName == space) && item.m_AttrName == name) {
+ item.m_Value.Set(value, pAllocator);
+ return;
+ }
+ }
+ if (!m_pMap) {
+ if (pAllocator) {
+ m_pMap = FX_NewAtAllocator(pAllocator)CFX_ObjectArray<CXML_AttrItem>(pAllocator);
+ } else {
+ m_pMap = FX_NEW CFX_ObjectArray<CXML_AttrItem>;
+ }
+ }
+ if (!m_pMap) {
+ return;
+ }
+ CXML_AttrItem* pItem = (CXML_AttrItem*)m_pMap->AddSpace();
+ if (!pItem) {
+ return;
+ }
+ pItem->m_QSpaceName.Set(space, pAllocator);
+ pItem->m_AttrName.Set(name, pAllocator);
+ pItem->m_Value.Set(value, pAllocator);
+}
+void CXML_AttrMap::RemoveAt(FX_BSTR space, FX_BSTR name, IFX_Allocator* pAllocator)
+{
+ if (m_pMap == NULL) {
+ return;
+ }
+ for (int i = 0; i < m_pMap->GetSize(); i ++) {
+ CXML_AttrItem& item = GetAt(i);
+ if ((space.IsEmpty() || item.m_QSpaceName == space) && item.m_AttrName == name) {
+ item.Empty(pAllocator);
+ m_pMap->RemoveAt(i);
+ return;
+ }
+ }
+}
+int CXML_AttrMap::GetSize() const
+{
+ return m_pMap == NULL ? 0 : m_pMap->GetSize();
+}
+CXML_AttrItem& CXML_AttrMap::GetAt(int index) const
+{
+ ASSERT(m_pMap != NULL);
+ return (*m_pMap)[index];
+}
+void CXML_AttrMap::RemoveAll(IFX_Allocator* pAllocator)
+{
+ if (!m_pMap) {
+ return;
+ }
+ for (int i = 0; i < m_pMap->GetSize(); i ++) {
+ CXML_AttrItem& item = (*m_pMap)[i];
+ item.Empty(pAllocator);
+ }
+ m_pMap->RemoveAll();
+ if (pAllocator) {
+ FX_DeleteAtAllocator(m_pMap, pAllocator, CFX_ObjectArray<CXML_AttrItem>);
+ } else {
+ delete m_pMap;
+ }
+ m_pMap = NULL;
+}