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