Home | History | Annotate | Download | only in xml
      1 // Copyright 2017 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 "core/fxcrt/xml/cfx_xmlnode.h"
      8 
      9 #include <vector>
     10 
     11 #include "core/fxcrt/fx_codepage.h"
     12 #include "core/fxcrt/xml/cfx_xmlchardata.h"
     13 #include "core/fxcrt/xml/cfx_xmlelement.h"
     14 #include "core/fxcrt/xml/cfx_xmlinstruction.h"
     15 #include "core/fxcrt/xml/cfx_xmltext.h"
     16 #include "third_party/base/stl_util.h"
     17 
     18 CFX_XMLNode::CFX_XMLNode()
     19     : m_pParent(nullptr),
     20       m_pChild(nullptr),
     21       m_pPrior(nullptr),
     22       m_pNext(nullptr) {}
     23 
     24 FX_XMLNODETYPE CFX_XMLNode::GetType() const {
     25   return FX_XMLNODE_Unknown;
     26 }
     27 
     28 CFX_XMLNode::~CFX_XMLNode() {
     29   DeleteChildren();
     30 }
     31 
     32 void CFX_XMLNode::DeleteChildren() {
     33   CFX_XMLNode* pChild = m_pChild;
     34   while (pChild) {
     35     CFX_XMLNode* pNext = pChild->m_pNext;
     36     delete pChild;
     37     pChild = pNext;
     38   }
     39   m_pChild = nullptr;
     40 }
     41 
     42 int32_t CFX_XMLNode::CountChildNodes() const {
     43   int32_t iCount = 0;
     44   CFX_XMLNode* pChild = m_pChild;
     45   while (pChild) {
     46     iCount++;
     47     pChild = pChild->m_pNext;
     48   }
     49   return iCount;
     50 }
     51 
     52 CFX_XMLNode* CFX_XMLNode::GetChildNode(int32_t index) const {
     53   CFX_XMLNode* pChild = m_pChild;
     54   while (pChild) {
     55     if (index == 0) {
     56       return pChild;
     57     }
     58     index--;
     59     pChild = pChild->m_pNext;
     60   }
     61   return nullptr;
     62 }
     63 
     64 int32_t CFX_XMLNode::GetChildNodeIndex(CFX_XMLNode* pNode) const {
     65   int32_t index = 0;
     66   CFX_XMLNode* pChild = m_pChild;
     67   while (pChild) {
     68     if (pChild == pNode) {
     69       return index;
     70     }
     71     index++;
     72     pChild = pChild->m_pNext;
     73   }
     74   return -1;
     75 }
     76 
     77 CFX_XMLNode* CFX_XMLNode::GetPath(const wchar_t* pPath,
     78                                   int32_t iLength,
     79                                   bool bQualifiedName) const {
     80   ASSERT(pPath);
     81   if (iLength < 0) {
     82     iLength = wcslen(pPath);
     83   }
     84   if (iLength == 0) {
     85     return nullptr;
     86   }
     87   WideString csPath;
     88   const wchar_t* pStart = pPath;
     89   const wchar_t* pEnd = pPath + iLength;
     90   wchar_t ch;
     91   while (pStart < pEnd) {
     92     ch = *pStart++;
     93     if (ch == L'/')
     94       break;
     95     csPath += ch;
     96   }
     97   iLength -= pStart - pPath;
     98   CFX_XMLNode* pFind = nullptr;
     99   if (csPath.GetLength() < 1) {
    100     pFind = GetNodeItem(CFX_XMLNode::Root);
    101   } else if (csPath.Compare(L"..") == 0) {
    102     pFind = m_pParent;
    103   } else if (csPath.Compare(L".") == 0) {
    104     pFind = (CFX_XMLNode*)this;
    105   } else {
    106     WideString wsTag;
    107     CFX_XMLNode* pNode = m_pChild;
    108     while (pNode) {
    109       if (pNode->GetType() == FX_XMLNODE_Element) {
    110         if (bQualifiedName)
    111           wsTag = static_cast<CFX_XMLElement*>(pNode)->GetName();
    112         else
    113           wsTag = static_cast<CFX_XMLElement*>(pNode)->GetLocalTagName();
    114 
    115         if (wsTag.Compare(csPath) == 0) {
    116           if (iLength < 1)
    117             pFind = pNode;
    118           else
    119             pFind = pNode->GetPath(pStart, iLength, bQualifiedName);
    120 
    121           if (pFind)
    122             return pFind;
    123         }
    124       }
    125       pNode = pNode->m_pNext;
    126     }
    127   }
    128   if (!pFind || iLength < 1)
    129     return pFind;
    130   return pFind->GetPath(pStart, iLength, bQualifiedName);
    131 }
    132 
    133 int32_t CFX_XMLNode::InsertChildNode(CFX_XMLNode* pNode, int32_t index) {
    134   pNode->m_pParent = this;
    135   if (!m_pChild) {
    136     m_pChild = pNode;
    137     pNode->m_pPrior = nullptr;
    138     pNode->m_pNext = nullptr;
    139     return 0;
    140   }
    141   if (index == 0) {
    142     pNode->m_pNext = m_pChild;
    143     pNode->m_pPrior = nullptr;
    144     m_pChild->m_pPrior = pNode;
    145     m_pChild = pNode;
    146     return 0;
    147   }
    148   int32_t iCount = 0;
    149   CFX_XMLNode* pFind = m_pChild;
    150   while (++iCount != index && pFind->m_pNext) {
    151     pFind = pFind->m_pNext;
    152   }
    153   pNode->m_pPrior = pFind;
    154   pNode->m_pNext = pFind->m_pNext;
    155   if (pFind->m_pNext)
    156     pFind->m_pNext->m_pPrior = pNode;
    157   pFind->m_pNext = pNode;
    158   return iCount;
    159 }
    160 
    161 void CFX_XMLNode::RemoveChildNode(CFX_XMLNode* pNode) {
    162   ASSERT(m_pChild && pNode);
    163   if (m_pChild == pNode) {
    164     m_pChild = pNode->m_pNext;
    165   } else {
    166     pNode->m_pPrior->m_pNext = pNode->m_pNext;
    167   }
    168   if (pNode->m_pNext)
    169     pNode->m_pNext->m_pPrior = pNode->m_pPrior;
    170   pNode->m_pParent = nullptr;
    171   pNode->m_pNext = nullptr;
    172   pNode->m_pPrior = nullptr;
    173 }
    174 
    175 CFX_XMLNode* CFX_XMLNode::GetNodeItem(CFX_XMLNode::NodeItem eItem) const {
    176   switch (eItem) {
    177     case CFX_XMLNode::Root: {
    178       CFX_XMLNode* pParent = (CFX_XMLNode*)this;
    179       while (pParent->m_pParent) {
    180         pParent = pParent->m_pParent;
    181       }
    182       return pParent;
    183     }
    184     case CFX_XMLNode::Parent:
    185       return m_pParent;
    186     case CFX_XMLNode::FirstSibling: {
    187       CFX_XMLNode* pItem = (CFX_XMLNode*)this;
    188       while (pItem->m_pPrior) {
    189         pItem = pItem->m_pPrior;
    190       }
    191       return pItem == (CFX_XMLNode*)this ? nullptr : pItem;
    192     }
    193     case CFX_XMLNode::PriorSibling:
    194       return m_pPrior;
    195     case CFX_XMLNode::NextSibling:
    196       return m_pNext;
    197     case CFX_XMLNode::LastSibling: {
    198       CFX_XMLNode* pItem = (CFX_XMLNode*)this;
    199       while (pItem->m_pNext)
    200         pItem = pItem->m_pNext;
    201       return pItem == (CFX_XMLNode*)this ? nullptr : pItem;
    202     }
    203     case CFX_XMLNode::FirstNeighbor: {
    204       CFX_XMLNode* pParent = (CFX_XMLNode*)this;
    205       while (pParent->m_pParent)
    206         pParent = pParent->m_pParent;
    207       return pParent == (CFX_XMLNode*)this ? nullptr : pParent;
    208     }
    209     case CFX_XMLNode::PriorNeighbor: {
    210       if (!m_pPrior)
    211         return m_pParent;
    212 
    213       CFX_XMLNode* pItem = m_pPrior;
    214       while (pItem->m_pChild) {
    215         pItem = pItem->m_pChild;
    216         while (pItem->m_pNext)
    217           pItem = pItem->m_pNext;
    218       }
    219       return pItem;
    220     }
    221     case CFX_XMLNode::NextNeighbor: {
    222       if (m_pChild)
    223         return m_pChild;
    224       if (m_pNext)
    225         return m_pNext;
    226       CFX_XMLNode* pItem = m_pParent;
    227       while (pItem) {
    228         if (pItem->m_pNext)
    229           return pItem->m_pNext;
    230         pItem = pItem->m_pParent;
    231       }
    232       return nullptr;
    233     }
    234     case CFX_XMLNode::LastNeighbor: {
    235       CFX_XMLNode* pItem = (CFX_XMLNode*)this;
    236       while (pItem->m_pParent) {
    237         pItem = pItem->m_pParent;
    238       }
    239       while (true) {
    240         while (pItem->m_pNext)
    241           pItem = pItem->m_pNext;
    242         if (!pItem->m_pChild)
    243           break;
    244         pItem = pItem->m_pChild;
    245       }
    246       return pItem == (CFX_XMLNode*)this ? nullptr : pItem;
    247     }
    248     case CFX_XMLNode::FirstChild:
    249       return m_pChild;
    250     case CFX_XMLNode::LastChild: {
    251       if (!m_pChild)
    252         return nullptr;
    253 
    254       CFX_XMLNode* pChild = m_pChild;
    255       while (pChild->m_pNext)
    256         pChild = pChild->m_pNext;
    257       return pChild;
    258     }
    259     default:
    260       break;
    261   }
    262   return nullptr;
    263 }
    264 
    265 int32_t CFX_XMLNode::GetNodeLevel() const {
    266   int32_t iLevel = 0;
    267   const CFX_XMLNode* pItem = m_pParent;
    268   while (pItem) {
    269     iLevel++;
    270     pItem = pItem->m_pParent;
    271   }
    272   return iLevel;
    273 }
    274 
    275 bool CFX_XMLNode::InsertNodeItem(CFX_XMLNode::NodeItem eItem,
    276                                  CFX_XMLNode* pNode) {
    277   switch (eItem) {
    278     case CFX_XMLNode::NextSibling: {
    279       pNode->m_pParent = m_pParent;
    280       pNode->m_pNext = m_pNext;
    281       pNode->m_pPrior = this;
    282       if (m_pNext) {
    283         m_pNext->m_pPrior = pNode;
    284       }
    285       m_pNext = pNode;
    286       return true;
    287     }
    288     case CFX_XMLNode::PriorSibling: {
    289       pNode->m_pParent = m_pParent;
    290       pNode->m_pNext = this;
    291       pNode->m_pPrior = m_pPrior;
    292       if (m_pPrior) {
    293         m_pPrior->m_pNext = pNode;
    294       } else if (m_pParent) {
    295         m_pParent->m_pChild = pNode;
    296       }
    297       m_pPrior = pNode;
    298       return true;
    299     }
    300     default:
    301       return false;
    302   }
    303 }
    304 
    305 CFX_XMLNode* CFX_XMLNode::RemoveNodeItem(CFX_XMLNode::NodeItem eItem) {
    306   CFX_XMLNode* pNode = nullptr;
    307   switch (eItem) {
    308     case CFX_XMLNode::NextSibling:
    309       if (m_pNext) {
    310         pNode = m_pNext;
    311         m_pNext = pNode->m_pNext;
    312         if (m_pNext) {
    313           m_pNext->m_pPrior = this;
    314         }
    315         pNode->m_pParent = nullptr;
    316         pNode->m_pNext = nullptr;
    317         pNode->m_pPrior = nullptr;
    318       }
    319       break;
    320     default:
    321       break;
    322   }
    323   return pNode;
    324 }
    325 
    326 std::unique_ptr<CFX_XMLNode> CFX_XMLNode::Clone() {
    327   return nullptr;
    328 }
    329 
    330 void CFX_XMLNode::SaveXMLNode(
    331     const RetainPtr<CFX_SeekableStreamProxy>& pXMLStream) {
    332   CFX_XMLNode* pNode = (CFX_XMLNode*)this;
    333   switch (pNode->GetType()) {
    334     case FX_XMLNODE_Instruction: {
    335       WideString ws;
    336       CFX_XMLInstruction* pInstruction = (CFX_XMLInstruction*)pNode;
    337       if (pInstruction->GetName().CompareNoCase(L"xml") == 0) {
    338         ws = L"<?xml version=\"1.0\" encoding=\"";
    339         uint16_t wCodePage = pXMLStream->GetCodePage();
    340         if (wCodePage == FX_CODEPAGE_UTF16LE) {
    341           ws += L"UTF-16";
    342         } else if (wCodePage == FX_CODEPAGE_UTF16BE) {
    343           ws += L"UTF-16be";
    344         } else {
    345           ws += L"UTF-8";
    346         }
    347         ws += L"\"?>";
    348         pXMLStream->WriteString(ws.AsStringView());
    349       } else {
    350         ws = WideString::Format(L"<?%ls", pInstruction->GetName().c_str());
    351         pXMLStream->WriteString(ws.AsStringView());
    352 
    353         for (auto it : pInstruction->GetAttributes()) {
    354           WideString wsValue = it.second;
    355           wsValue.Replace(L"&", L"&amp;");
    356           wsValue.Replace(L"<", L"&lt;");
    357           wsValue.Replace(L">", L"&gt;");
    358           wsValue.Replace(L"\'", L"&apos;");
    359           wsValue.Replace(L"\"", L"&quot;");
    360 
    361           ws = L" ";
    362           ws += it.first;
    363           ws += L"=\"";
    364           ws += wsValue;
    365           ws += L"\"";
    366           pXMLStream->WriteString(ws.AsStringView());
    367         }
    368 
    369         for (auto target : pInstruction->GetTargetData()) {
    370           ws = L" \"";
    371           ws += target;
    372           ws += L"\"";
    373           pXMLStream->WriteString(ws.AsStringView());
    374         }
    375         ws = L"?>";
    376         pXMLStream->WriteString(ws.AsStringView());
    377       }
    378       break;
    379     }
    380     case FX_XMLNODE_Element: {
    381       WideString ws;
    382       ws = L"<";
    383       ws += static_cast<CFX_XMLElement*>(pNode)->GetName();
    384       pXMLStream->WriteString(ws.AsStringView());
    385 
    386       for (auto it : static_cast<CFX_XMLElement*>(pNode)->GetAttributes()) {
    387         WideString wsValue = it.second;
    388         wsValue.Replace(L"&", L"&amp;");
    389         wsValue.Replace(L"<", L"&lt;");
    390         wsValue.Replace(L">", L"&gt;");
    391         wsValue.Replace(L"\'", L"&apos;");
    392         wsValue.Replace(L"\"", L"&quot;");
    393 
    394         ws = L" ";
    395         ws += it.first;
    396         ws += L"=\"";
    397         ws += wsValue;
    398         ws += L"\"";
    399         pXMLStream->WriteString(ws.AsStringView());
    400       }
    401       if (pNode->m_pChild) {
    402         ws = L"\n>";
    403         pXMLStream->WriteString(ws.AsStringView());
    404         CFX_XMLNode* pChild = pNode->m_pChild;
    405         while (pChild) {
    406           pChild->SaveXMLNode(pXMLStream);
    407           pChild = pChild->m_pNext;
    408         }
    409         ws = L"</";
    410         ws += static_cast<CFX_XMLElement*>(pNode)->GetName();
    411         ws += L"\n>";
    412       } else {
    413         ws = L"\n/>";
    414       }
    415       pXMLStream->WriteString(ws.AsStringView());
    416       break;
    417     }
    418     case FX_XMLNODE_Text: {
    419       WideString ws = static_cast<CFX_XMLText*>(pNode)->GetText();
    420       ws.Replace(L"&", L"&amp;");
    421       ws.Replace(L"<", L"&lt;");
    422       ws.Replace(L">", L"&gt;");
    423       ws.Replace(L"\'", L"&apos;");
    424       ws.Replace(L"\"", L"&quot;");
    425       pXMLStream->WriteString(ws.AsStringView());
    426       break;
    427     }
    428     case FX_XMLNODE_CharData: {
    429       WideString ws = L"<![CDATA[";
    430       ws += static_cast<CFX_XMLCharData*>(pNode)->GetText();
    431       ws += L"]]>";
    432       pXMLStream->WriteString(ws.AsStringView());
    433       break;
    434     }
    435     case FX_XMLNODE_Unknown:
    436     default:
    437       break;
    438   }
    439 }
    440