Home | History | Annotate | Download | only in fxcrt
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "../../include/fxcrt/fx_xml.h"
      8 #include "xml_int.h"
      9 CXML_Parser::~CXML_Parser()
     10 {
     11     if (m_bOwnedStream) {
     12         m_pDataAcc->Release();
     13     }
     14 }
     15 FX_BOOL CXML_Parser::Init(FX_LPBYTE pBuffer, size_t size)
     16 {
     17     m_pDataAcc = new CXML_DataBufAcc(pBuffer, size);
     18     return Init(TRUE);
     19 }
     20 FX_BOOL CXML_Parser::Init(IFX_FileRead *pFileRead)
     21 {
     22     m_pDataAcc = new CXML_DataStmAcc(pFileRead);
     23     return Init(TRUE);
     24 }
     25 FX_BOOL CXML_Parser::Init(IFX_BufferRead *pBuffer)
     26 {
     27     if (!pBuffer) {
     28         return FALSE;
     29     }
     30     m_pDataAcc = pBuffer;
     31     return Init(FALSE);
     32 }
     33 FX_BOOL CXML_Parser::Init(FX_BOOL bOwndedStream)
     34 {
     35     m_bOwnedStream = bOwndedStream;
     36     m_nOffset = 0;
     37     return ReadNextBlock();
     38 }
     39 FX_BOOL CXML_Parser::ReadNextBlock()
     40 {
     41     if (!m_pDataAcc->ReadNextBlock()) {
     42         return FALSE;
     43     }
     44     m_pBuffer = m_pDataAcc->GetBlockBuffer();
     45     m_dwBufferSize = m_pDataAcc->GetBlockSize();
     46     m_nBufferOffset = m_pDataAcc->GetBlockOffset();
     47     m_dwIndex = 0;
     48     return m_dwBufferSize > 0;
     49 }
     50 FX_BOOL CXML_Parser::IsEOF()
     51 {
     52     if (!m_pDataAcc->IsEOF()) {
     53         return FALSE;
     54     }
     55     return m_dwIndex >= m_dwBufferSize;
     56 }
     57 #define FXCRTM_XML_CHARTYPE_Normal			0x00
     58 #define FXCRTM_XML_CHARTYPE_SpaceChar		0x01
     59 #define FXCRTM_XML_CHARTYPE_Letter			0x02
     60 #define FXCRTM_XML_CHARTYPE_Digital			0x04
     61 #define FXCRTM_XML_CHARTYPE_NameIntro		0x08
     62 #define FXCRTM_XML_CHARTYPE_NameChar		0x10
     63 #define FXCRTM_XML_CHARTYPE_HexDigital		0x20
     64 #define FXCRTM_XML_CHARTYPE_HexLowerLetter	0x40
     65 #define FXCRTM_XML_CHARTYPE_HexUpperLetter	0x60
     66 #define FXCRTM_XML_CHARTYPE_HexChar			0x60
     67 FX_BYTE g_FXCRT_XML_ByteTypes[256] = {
     68     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
     69     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
     70     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,
     71     0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
     72     0x00, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
     73     0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x18,
     74     0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
     75     0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00,
     76     0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
     77     0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
     78     0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
     79     0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
     80     0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
     81     0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
     82     0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
     83     0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x01, 0x01,
     84 };
     85 FX_BOOL g_FXCRT_XML_IsWhiteSpace(FX_BYTE ch)
     86 {
     87     return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_SpaceChar) != 0;
     88 }
     89 FX_BOOL g_FXCRT_XML_IsLetter(FX_BYTE ch)
     90 {
     91     return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_Letter) != 0;
     92 }
     93 FX_BOOL g_FXCRT_XML_IsDigital(FX_BYTE ch)
     94 {
     95     return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_Digital) != 0;
     96 }
     97 FX_BOOL g_FXCRT_XML_IsNameIntro(FX_BYTE ch)
     98 {
     99     return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_NameIntro) != 0;
    100 }
    101 FX_BOOL g_FXCRT_XML_IsNameChar(FX_BYTE ch)
    102 {
    103     return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_NameChar) != 0;
    104 }
    105 FX_BOOL g_FXCRT_XML_IsHexChar(FX_BYTE ch)
    106 {
    107     return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_HexChar) != 0;
    108 }
    109 void CXML_Parser::SkipWhiteSpaces()
    110 {
    111     m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    112     if (IsEOF()) {
    113         return;
    114     }
    115     do {
    116         while (m_dwIndex < m_dwBufferSize && g_FXCRT_XML_IsWhiteSpace(m_pBuffer[m_dwIndex])) {
    117             m_dwIndex ++;
    118         }
    119         m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    120         if (m_dwIndex < m_dwBufferSize || IsEOF()) {
    121             break;
    122         }
    123     } while (ReadNextBlock());
    124 }
    125 void CXML_Parser::GetName(CFX_ByteString &space, CFX_ByteString &name)
    126 {
    127     m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    128     if (IsEOF()) {
    129         return;
    130     }
    131     CFX_ByteTextBuf buf;
    132     FX_BYTE ch;
    133     do {
    134         while (m_dwIndex < m_dwBufferSize) {
    135             ch = m_pBuffer[m_dwIndex];
    136             if (ch == ':') {
    137                 space = buf.GetByteString();
    138                 buf.Clear();
    139             } else if (g_FXCRT_XML_IsNameChar(ch)) {
    140                 buf.AppendChar(ch);
    141             } else {
    142                 break;
    143             }
    144             m_dwIndex ++;
    145         }
    146         m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    147         if (m_dwIndex < m_dwBufferSize || IsEOF()) {
    148             break;
    149         }
    150     } while (ReadNextBlock());
    151     name = buf.GetByteString();
    152 }
    153 void CXML_Parser::SkipLiterals(FX_BSTR str)
    154 {
    155     m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    156     if (IsEOF()) {
    157         return;
    158     }
    159     FX_INT32 i = 0, iLen = str.GetLength();
    160     do {
    161         while (m_dwIndex < m_dwBufferSize) {
    162             if (str.GetAt(i) != m_pBuffer[m_dwIndex ++]) {
    163                 i = 0;
    164             } else {
    165                 i ++;
    166                 if (i == iLen) {
    167                     break;
    168                 }
    169             }
    170         }
    171         m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    172         if (i == iLen) {
    173             return;
    174         }
    175         if (m_dwIndex < m_dwBufferSize || IsEOF()) {
    176             break;
    177         }
    178     } while (ReadNextBlock());
    179     while (!m_pDataAcc->IsEOF()) {
    180         ReadNextBlock();
    181         m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwBufferSize;
    182     }
    183     m_dwIndex = m_dwBufferSize;
    184 }
    185 FX_DWORD CXML_Parser::GetCharRef()
    186 {
    187     m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    188     if (IsEOF()) {
    189         return 0;
    190     }
    191     FX_BYTE ch;
    192     FX_INT32 iState = 0;
    193     CFX_ByteTextBuf buf;
    194     FX_DWORD code = 0;
    195     do {
    196         while (m_dwIndex < m_dwBufferSize) {
    197             ch = m_pBuffer[m_dwIndex];
    198             switch (iState) {
    199                 case 0:
    200                     if (ch == '#') {
    201                         m_dwIndex ++;
    202                         iState = 2;
    203                         break;
    204                     }
    205                     iState = 1;
    206                 case 1:
    207                     m_dwIndex ++;
    208                     if (ch == ';') {
    209                         CFX_ByteStringC ref = buf.GetByteString();
    210                         if (ref == FX_BSTRC("gt")) {
    211                             code = '>';
    212                         } else if (ref == FX_BSTRC("lt")) {
    213                             code = '<';
    214                         } else if (ref == FX_BSTRC("amp")) {
    215                             code = '&';
    216                         } else if (ref == FX_BSTRC("apos")) {
    217                             code = '\'';
    218                         } else if (ref == FX_BSTRC("quot")) {
    219                             code = '"';
    220                         }
    221                         iState = 10;
    222                         break;
    223                     }
    224                     buf.AppendByte(ch);
    225                     break;
    226                 case 2:
    227                     if (ch == 'x') {
    228                         m_dwIndex ++;
    229                         iState = 4;
    230                         break;
    231                     }
    232                     iState = 3;
    233                 case 3:
    234                     m_dwIndex ++;
    235                     if (ch == ';') {
    236                         iState = 10;
    237                         break;
    238                     }
    239                     if (g_FXCRT_XML_IsDigital(ch)) {
    240                         code = code * 10 + ch - '0';
    241                     }
    242                     break;
    243                 case 4:
    244                     m_dwIndex ++;
    245                     if (ch == ';') {
    246                         iState = 10;
    247                         break;
    248                     }
    249                     FX_BYTE nHex = g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_HexChar;
    250                     if (nHex) {
    251                         if (nHex == FXCRTM_XML_CHARTYPE_HexDigital) {
    252                             code = (code << 4) + ch - '0';
    253                         } else if (nHex == FXCRTM_XML_CHARTYPE_HexLowerLetter) {
    254                             code = (code << 4) + ch - 87;
    255                         } else {
    256                             code = (code << 4) + ch - 55;
    257                         }
    258                     }
    259                     break;
    260             }
    261             if (iState == 10) {
    262                 break;
    263             }
    264         }
    265         m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    266         if (iState == 10 || m_dwIndex < m_dwBufferSize || IsEOF()) {
    267             break;
    268         }
    269     } while (ReadNextBlock());
    270     return code;
    271 }
    272 void CXML_Parser::GetAttrValue(CFX_WideString &value)
    273 {
    274     m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    275     if (IsEOF()) {
    276         return;
    277     }
    278     CFX_UTF8Decoder decoder;
    279     FX_BYTE mark = 0, ch = 0;
    280     do {
    281         while (m_dwIndex < m_dwBufferSize) {
    282             ch = m_pBuffer[m_dwIndex];
    283             if (mark == 0) {
    284                 if (ch != '\'' && ch != '"') {
    285                     return;
    286                 }
    287                 mark = ch;
    288                 m_dwIndex ++;
    289                 ch = 0;
    290                 continue;
    291             }
    292             m_dwIndex ++;
    293             if (ch == mark) {
    294                 break;
    295             }
    296             if (ch == '&') {
    297                 decoder.AppendChar(GetCharRef());
    298                 if (IsEOF()) {
    299                     value = decoder.GetResult();
    300                     return;
    301                 }
    302             } else {
    303                 decoder.Input(ch);
    304             }
    305         }
    306         m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    307         if (ch == mark || m_dwIndex < m_dwBufferSize || IsEOF()) {
    308             break;
    309         }
    310     } while (ReadNextBlock());
    311     value = decoder.GetResult();
    312 }
    313 void CXML_Parser::GetTagName(CFX_ByteString &space, CFX_ByteString &name, FX_BOOL &bEndTag, FX_BOOL bStartTag)
    314 {
    315     m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    316     if (IsEOF()) {
    317         return;
    318     }
    319     bEndTag = FALSE;
    320     FX_BYTE ch;
    321     FX_INT32 iState = bStartTag ? 1 : 0;
    322     do {
    323         while (m_dwIndex < m_dwBufferSize) {
    324             ch = m_pBuffer[m_dwIndex];
    325             switch (iState) {
    326                 case 0:
    327                     m_dwIndex ++;
    328                     if (ch != '<') {
    329                         break;
    330                     }
    331                     iState = 1;
    332                     break;
    333                 case 1:
    334                     if (ch == '?') {
    335                         m_dwIndex ++;
    336                         SkipLiterals(FX_BSTRC("?>"));
    337                         iState = 0;
    338                         break;
    339                     } else if (ch == '!') {
    340                         m_dwIndex ++;
    341                         SkipLiterals(FX_BSTRC("-->"));
    342                         iState = 0;
    343                         break;
    344                     }
    345                     if (ch == '/') {
    346                         m_dwIndex ++;
    347                         GetName(space, name);
    348                         bEndTag = TRUE;
    349                     } else {
    350                         GetName(space, name);
    351                         bEndTag = FALSE;
    352                     }
    353                     return;
    354             }
    355         }
    356         m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    357         if (m_dwIndex < m_dwBufferSize || IsEOF()) {
    358             break;
    359         }
    360     } while (ReadNextBlock());
    361 }
    362 CXML_Element* CXML_Parser::ParseElement(CXML_Element* pParent, FX_BOOL bStartTag)
    363 {
    364     m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    365     if (IsEOF()) {
    366         return NULL;
    367     }
    368     CFX_ByteString tag_name, tag_space;
    369     FX_BOOL bEndTag;
    370     GetTagName(tag_space, tag_name, bEndTag, bStartTag);
    371     if (tag_name.IsEmpty() || bEndTag) {
    372         return NULL;
    373     }
    374     CXML_Element* pElement = new CXML_Element;
    375     pElement->m_pParent = pParent;
    376     pElement->SetTag(tag_space, tag_name);
    377     do {
    378         CFX_ByteString attr_space, attr_name;
    379         while (m_dwIndex < m_dwBufferSize) {
    380             SkipWhiteSpaces();
    381             if (IsEOF()) {
    382                 break;
    383             }
    384             if (!g_FXCRT_XML_IsNameIntro(m_pBuffer[m_dwIndex])) {
    385                 break;
    386             }
    387             GetName(attr_space, attr_name);
    388             SkipWhiteSpaces();
    389             if (IsEOF()) {
    390                 break;
    391             }
    392             if (m_pBuffer[m_dwIndex] != '=') {
    393                 break;
    394             }
    395             m_dwIndex ++;
    396             SkipWhiteSpaces();
    397             if (IsEOF()) {
    398                 break;
    399             }
    400             CFX_WideString attr_value;
    401             GetAttrValue(attr_value);
    402             pElement->m_AttrMap.SetAt(attr_space, attr_name, attr_value);
    403         }
    404         m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    405         if (m_dwIndex < m_dwBufferSize || IsEOF()) {
    406             break;
    407         }
    408     } while (ReadNextBlock());
    409     SkipWhiteSpaces();
    410     if (IsEOF()) {
    411         return pElement;
    412     }
    413     FX_BYTE ch = m_pBuffer[m_dwIndex ++];
    414     if (ch == '/') {
    415         m_dwIndex ++;
    416         m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    417         return pElement;
    418     }
    419     if (ch != '>') {
    420         m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    421         delete pElement;
    422         return NULL;
    423     }
    424     SkipWhiteSpaces();
    425     if (IsEOF()) {
    426         return pElement;
    427     }
    428     CFX_UTF8Decoder decoder;
    429     CFX_WideTextBuf content;
    430     FX_BOOL bCDATA = FALSE;
    431     FX_INT32 iState = 0;
    432     do {
    433         while (m_dwIndex < m_dwBufferSize) {
    434             ch = m_pBuffer[m_dwIndex ++];
    435             switch (iState) {
    436                 case 0:
    437                     if (ch == '<') {
    438                         iState = 1;
    439                     } else if (ch == '&') {
    440                         decoder.ClearStatus();
    441                         decoder.AppendChar(GetCharRef());
    442                     } else {
    443                         decoder.Input(ch);
    444                     }
    445                     break;
    446                 case 1:
    447                     if (ch == '!') {
    448                         iState = 2;
    449                     } else if (ch == '?') {
    450                         SkipLiterals(FX_BSTRC("?>"));
    451                         SkipWhiteSpaces();
    452                         iState = 0;
    453                     } else if (ch == '/') {
    454                         CFX_ByteString space, name;
    455                         GetName(space, name);
    456                         SkipWhiteSpaces();
    457                         m_dwIndex ++;
    458                         iState = 10;
    459                     } else {
    460                         content << decoder.GetResult();
    461                         CFX_WideString dataStr = content.GetWideString();
    462                         if (!bCDATA && !m_bSaveSpaceChars) {
    463                             dataStr.TrimRight(L" \t\r\n");
    464                         }
    465                         InsertContentSegment(bCDATA, dataStr, pElement);
    466                         content.Clear();
    467                         decoder.Clear();
    468                         bCDATA = FALSE;
    469                         iState = 0;
    470                         m_dwIndex --;
    471                         CXML_Element* pSubElement = ParseElement(pElement, TRUE);
    472                         if (pSubElement == NULL) {
    473                             break;
    474                         }
    475                         pSubElement->m_pParent = pElement;
    476                         pElement->m_Children.Add((FX_LPVOID)CXML_Element::Element);
    477                         pElement->m_Children.Add(pSubElement);
    478                         SkipWhiteSpaces();
    479                     }
    480                     break;
    481                 case 2:
    482                     if (ch == '[') {
    483                         SkipLiterals(FX_BSTRC("]]>"));
    484                     } else if (ch == '-') {
    485                         m_dwIndex ++;
    486                         SkipLiterals(FX_BSTRC("-->"));
    487                     } else {
    488                         SkipLiterals(FX_BSTRC(">"));
    489                     }
    490                     decoder.Clear();
    491                     SkipWhiteSpaces();
    492                     iState = 0;
    493                     break;
    494             }
    495             if (iState == 10) {
    496                 break;
    497             }
    498         }
    499         m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
    500         if (iState == 10 || m_dwIndex < m_dwBufferSize || IsEOF()) {
    501             break;
    502         }
    503     } while (ReadNextBlock());
    504     content << decoder.GetResult();
    505     CFX_WideString dataStr = content.GetWideString();
    506     if (!m_bSaveSpaceChars) {
    507         dataStr.TrimRight(L" \t\r\n");
    508     }
    509     InsertContentSegment(bCDATA, dataStr, pElement);
    510     content.Clear();
    511     decoder.Clear();
    512     bCDATA = FALSE;
    513     return pElement;
    514 }
    515 void CXML_Parser::InsertContentSegment(FX_BOOL bCDATA, FX_WSTR content, CXML_Element* pElement)
    516 {
    517     if (content.IsEmpty()) {
    518         return;
    519     }
    520     CXML_Content* pContent = new CXML_Content;
    521     pContent->Set(bCDATA, content);
    522     pElement->m_Children.Add((FX_LPVOID)CXML_Element::Content);
    523     pElement->m_Children.Add(pContent);
    524 }
    525 static CXML_Element* XML_ContinueParse(CXML_Parser &parser, FX_BOOL bSaveSpaceChars, FX_FILESIZE* pParsedSize)
    526 {
    527     parser.m_bSaveSpaceChars = bSaveSpaceChars;
    528     CXML_Element* pElement = parser.ParseElement(NULL, FALSE);
    529     if (pParsedSize) {
    530         *pParsedSize = parser.m_nOffset;
    531     }
    532     return pElement;
    533 }
    534 CXML_Element* CXML_Element::Parse(const void* pBuffer, size_t size, FX_BOOL bSaveSpaceChars, FX_FILESIZE* pParsedSize)
    535 {
    536     CXML_Parser parser;
    537     if (!parser.Init((FX_LPBYTE)pBuffer, size)) {
    538         return NULL;
    539     }
    540     return XML_ContinueParse(parser, bSaveSpaceChars, pParsedSize);
    541 }
    542 CXML_Element* CXML_Element::Parse(IFX_FileRead *pFile, FX_BOOL bSaveSpaceChars, FX_FILESIZE* pParsedSize)
    543 {
    544     CXML_Parser parser;
    545     if (!parser.Init(pFile)) {
    546         return NULL;
    547     }
    548     return XML_ContinueParse(parser, bSaveSpaceChars, pParsedSize);
    549 }
    550 CXML_Element* CXML_Element::Parse(IFX_BufferRead *pBuffer, FX_BOOL bSaveSpaceChars, FX_FILESIZE* pParsedSize)
    551 {
    552     CXML_Parser parser;
    553     if (!parser.Init(pBuffer)) {
    554         return NULL;
    555     }
    556     return XML_ContinueParse(parser, bSaveSpaceChars, pParsedSize);
    557 }
    558 CXML_Element::CXML_Element()
    559     : m_QSpaceName()
    560     , m_TagName()
    561     , m_AttrMap()
    562 {
    563 }
    564 CXML_Element::CXML_Element(FX_BSTR qSpace, FX_BSTR tagName)
    565     : m_QSpaceName()
    566     , m_TagName()
    567     , m_AttrMap()
    568 {
    569     m_QSpaceName = qSpace;
    570     m_TagName = tagName;
    571 }
    572 CXML_Element::CXML_Element(FX_BSTR qTagName)
    573     : m_pParent(NULL)
    574     , m_QSpaceName()
    575     , m_TagName()
    576     , m_AttrMap()
    577 {
    578     SetTag(qTagName);
    579 }
    580 CXML_Element::~CXML_Element()
    581 {
    582     Empty();
    583 }
    584 void CXML_Element::Empty()
    585 {
    586     RemoveChildren();
    587 }
    588 void CXML_Element::RemoveChildren()
    589 {
    590     for (int i = 0; i < m_Children.GetSize(); i += 2) {
    591         ChildType type = (ChildType)(FX_UINTPTR)m_Children.GetAt(i);
    592         if (type == Content) {
    593             CXML_Content* content = (CXML_Content*)m_Children.GetAt(i + 1);
    594             delete content;
    595         } else if (type == Element) {
    596             CXML_Element* child = (CXML_Element*)m_Children.GetAt(i + 1);
    597             child->RemoveChildren();
    598             delete child;
    599         }
    600     }
    601     m_Children.RemoveAll();
    602 }
    603 CFX_ByteString CXML_Element::GetTagName(FX_BOOL bQualified) const
    604 {
    605     if (!bQualified || m_QSpaceName.IsEmpty()) {
    606         return m_TagName;
    607     }
    608     CFX_ByteString bsTag = m_QSpaceName;
    609     bsTag += ":";
    610     bsTag += m_TagName;
    611     return bsTag;
    612 }
    613 CFX_ByteString CXML_Element::GetNamespace(FX_BOOL bQualified) const
    614 {
    615     if (bQualified) {
    616         return m_QSpaceName;
    617     }
    618     return GetNamespaceURI(m_QSpaceName);
    619 }
    620 CFX_ByteString CXML_Element::GetNamespaceURI(FX_BSTR qName) const
    621 {
    622     const CFX_WideString* pwsSpace;
    623     const CXML_Element *pElement = this;
    624     do {
    625         if (qName.IsEmpty()) {
    626             pwsSpace = pElement->m_AttrMap.Lookup(FX_BSTRC(""), FX_BSTRC("xmlns"));
    627         } else {
    628             pwsSpace = pElement->m_AttrMap.Lookup(FX_BSTRC("xmlns"), qName);
    629         }
    630         if (pwsSpace) {
    631             break;
    632         }
    633         pElement = pElement->GetParent();
    634     } while(pElement);
    635     return pwsSpace ? FX_UTF8Encode(*pwsSpace) : CFX_ByteString();
    636 }
    637 void CXML_Element::GetAttrByIndex(int index, CFX_ByteString& space, CFX_ByteString& name, CFX_WideString& value) const
    638 {
    639     if (index < 0 || index >= m_AttrMap.GetSize()) {
    640         return;
    641     }
    642     CXML_AttrItem& item = m_AttrMap.GetAt(index);
    643     space = item.m_QSpaceName;
    644     name = item.m_AttrName;
    645     value = item.m_Value;
    646 }
    647 FX_BOOL CXML_Element::HasAttr(FX_BSTR name) const
    648 {
    649     CFX_ByteStringC bsSpace, bsName;
    650     FX_XML_SplitQualifiedName(name, bsSpace, bsName);
    651     return m_AttrMap.Lookup(bsSpace, bsName) != NULL;
    652 }
    653 FX_BOOL CXML_Element::GetAttrValue(FX_BSTR name, CFX_WideString& attribute) const
    654 {
    655     CFX_ByteStringC bsSpace, bsName;
    656     FX_XML_SplitQualifiedName(name, bsSpace, bsName);
    657     return GetAttrValue(bsSpace, bsName, attribute);
    658 }
    659 FX_BOOL CXML_Element::GetAttrValue(FX_BSTR space, FX_BSTR name, CFX_WideString& attribute) const
    660 {
    661     const CFX_WideString* pValue = m_AttrMap.Lookup(space, name);
    662     if (pValue) {
    663         attribute = *pValue;
    664         return TRUE;
    665     }
    666     return FALSE;
    667 }
    668 FX_BOOL CXML_Element::GetAttrInteger(FX_BSTR name, int& attribute) const
    669 {
    670     CFX_ByteStringC bsSpace, bsName;
    671     FX_XML_SplitQualifiedName(name, bsSpace, bsName);
    672     const CFX_WideString* pwsValue = m_AttrMap.Lookup(bsSpace, bsName);
    673     if (pwsValue) {
    674         attribute = pwsValue->GetInteger();
    675         return TRUE;
    676     }
    677     return FALSE;
    678 }
    679 FX_BOOL	CXML_Element::GetAttrInteger(FX_BSTR space, FX_BSTR name, int& attribute) const
    680 {
    681     const CFX_WideString* pwsValue = m_AttrMap.Lookup(space, name);
    682     if (pwsValue) {
    683         attribute = pwsValue->GetInteger();
    684         return TRUE;
    685     }
    686     return FALSE;
    687 }
    688 FX_BOOL CXML_Element::GetAttrFloat(FX_BSTR name, FX_FLOAT& attribute) const
    689 {
    690     CFX_ByteStringC bsSpace, bsName;
    691     FX_XML_SplitQualifiedName(name, bsSpace, bsName);
    692     return GetAttrFloat(bsSpace, bsName, attribute);
    693 }
    694 FX_BOOL CXML_Element::GetAttrFloat(FX_BSTR space, FX_BSTR name, FX_FLOAT& attribute) const
    695 {
    696     const CFX_WideString* pValue = m_AttrMap.Lookup(space, name);
    697     if (pValue) {
    698         attribute = pValue->GetFloat();
    699         return TRUE;
    700     }
    701     return FALSE;
    702 }
    703 FX_DWORD CXML_Element::CountChildren() const
    704 {
    705     return m_Children.GetSize() / 2;
    706 }
    707 CXML_Element::ChildType CXML_Element::GetChildType(FX_DWORD index) const
    708 {
    709     index <<= 1;
    710     if (index >= (FX_DWORD)m_Children.GetSize()) {
    711         return Invalid;
    712     }
    713     return (ChildType)(FX_UINTPTR)m_Children.GetAt(index);
    714 }
    715 CFX_WideString CXML_Element::GetContent(FX_DWORD index) const
    716 {
    717     index <<= 1;
    718     if (index >= (FX_DWORD)m_Children.GetSize() ||
    719             (ChildType)(FX_UINTPTR)m_Children.GetAt(index) != Content) {
    720         return CFX_WideString();
    721     }
    722     CXML_Content* pContent = (CXML_Content*)m_Children.GetAt(index + 1);
    723     if (pContent) {
    724         return pContent->m_Content;
    725     }
    726     return CFX_WideString();
    727 }
    728 CXML_Element* CXML_Element::GetElement(FX_DWORD index) const
    729 {
    730     index <<= 1;
    731     if (index >= (FX_DWORD)m_Children.GetSize() ||
    732             (ChildType)(FX_UINTPTR)m_Children.GetAt(index) != Element) {
    733         return NULL;
    734     }
    735     return (CXML_Element*)m_Children.GetAt(index + 1);
    736 }
    737 FX_DWORD CXML_Element::CountElements(FX_BSTR space, FX_BSTR tag) const
    738 {
    739     int count = 0;
    740     for (int i = 0; i < m_Children.GetSize(); i += 2) {
    741         ChildType type = (ChildType)(FX_UINTPTR)m_Children.GetAt(i);
    742         if (type != Element) {
    743             continue;
    744         }
    745         CXML_Element* pKid = (CXML_Element*)m_Children.GetAt(i + 1);
    746         if ((space.IsEmpty() || pKid->m_QSpaceName == space) && pKid->m_TagName == tag) {
    747             count ++;
    748         }
    749     }
    750     return count;
    751 }
    752 CXML_Element* CXML_Element::GetElement(FX_BSTR space, FX_BSTR tag, int index) const
    753 {
    754     if (index < 0) {
    755         return NULL;
    756     }
    757     for (int i = 0; i < m_Children.GetSize(); i += 2) {
    758         ChildType type = (ChildType)(FX_UINTPTR)m_Children.GetAt(i);
    759         if (type != Element) {
    760             continue;
    761         }
    762         CXML_Element* pKid = (CXML_Element*)m_Children.GetAt(i + 1);
    763         if ((!space.IsEmpty() && pKid->m_QSpaceName != space) || pKid->m_TagName != tag) {
    764             continue;
    765         }
    766         if (index -- == 0) {
    767             return pKid;
    768         }
    769     }
    770     return NULL;
    771 }
    772 FX_DWORD CXML_Element::FindElement(CXML_Element *pChild) const
    773 {
    774     for (int i = 0; i < m_Children.GetSize(); i += 2) {
    775         if ((ChildType)(FX_UINTPTR)m_Children.GetAt(i) == Element &&
    776                 (CXML_Element*)m_Children.GetAt(i + 1) == pChild) {
    777             return (FX_DWORD)(i >> 1);
    778         }
    779     }
    780     return (FX_DWORD) - 1;
    781 }
    782 const CFX_WideString* CXML_AttrMap::Lookup(FX_BSTR space, FX_BSTR name) const
    783 {
    784     if (m_pMap == NULL) {
    785         return NULL;
    786     }
    787     for (int i = 0; i < m_pMap->GetSize(); i ++) {
    788         CXML_AttrItem& item = GetAt(i);
    789         if ((space.IsEmpty() || item.m_QSpaceName == space) && item.m_AttrName == name) {
    790             return &item.m_Value;
    791         }
    792     }
    793     return NULL;
    794 }
    795 void CXML_AttrMap::SetAt(FX_BSTR space, FX_BSTR name, FX_WSTR value)
    796 {
    797     for (int i = 0; i < GetSize(); i++) {
    798         CXML_AttrItem& item = GetAt(i);
    799         if ((space.IsEmpty() || item.m_QSpaceName == space) && item.m_AttrName == name) {
    800             item.m_Value = value;
    801             return;
    802         }
    803     }
    804     if (!m_pMap) {
    805         m_pMap = new CFX_ObjectArray<CXML_AttrItem>;
    806     }
    807     CXML_AttrItem* pItem = (CXML_AttrItem*)m_pMap->AddSpace();
    808     if (!pItem) {
    809         return;
    810     }
    811     pItem->m_QSpaceName = space;
    812     pItem->m_AttrName = name;
    813     pItem->m_Value = value;
    814 }
    815 void CXML_AttrMap::RemoveAt(FX_BSTR space, FX_BSTR name)
    816 {
    817     if (m_pMap == NULL) {
    818         return;
    819     }
    820     for (int i = 0; i < m_pMap->GetSize(); i ++) {
    821         CXML_AttrItem& item = GetAt(i);
    822         if ((space.IsEmpty() || item.m_QSpaceName == space) && item.m_AttrName == name) {
    823             m_pMap->RemoveAt(i);
    824             return;
    825         }
    826     }
    827 }
    828 int CXML_AttrMap::GetSize() const
    829 {
    830     return m_pMap == NULL ? 0 : m_pMap->GetSize();
    831 }
    832 CXML_AttrItem& CXML_AttrMap::GetAt(int index) const
    833 {
    834     ASSERT(m_pMap != NULL);
    835     return (*m_pMap)[index];
    836 }
    837 void CXML_AttrMap::RemoveAll()
    838 {
    839     if (!m_pMap) {
    840         return;
    841     }
    842     m_pMap->RemoveAll();
    843     delete m_pMap;
    844     m_pMap = NULL;
    845 }
    846