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