• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CFX_XMLNode()18 CFX_XMLNode::CFX_XMLNode()
19     : m_pParent(nullptr),
20       m_pChild(nullptr),
21       m_pPrior(nullptr),
22       m_pNext(nullptr) {}
23 
GetType() const24 FX_XMLNODETYPE CFX_XMLNode::GetType() const {
25   return FX_XMLNODE_Unknown;
26 }
27 
~CFX_XMLNode()28 CFX_XMLNode::~CFX_XMLNode() {
29   DeleteChildren();
30 }
31 
DeleteChildren()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 
CountChildNodes() const42 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 
GetChildNode(int32_t index) const52 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 
GetChildNodeIndex(CFX_XMLNode * pNode) const64 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 
GetPath(const wchar_t * pPath,int32_t iLength,bool bQualifiedName) const77 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 
InsertChildNode(CFX_XMLNode * pNode,int32_t index)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 
RemoveChildNode(CFX_XMLNode * pNode)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 
GetNodeItem(CFX_XMLNode::NodeItem eItem) const175 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 
GetNodeLevel() const265 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 
InsertNodeItem(CFX_XMLNode::NodeItem eItem,CFX_XMLNode * pNode)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 
RemoveNodeItem(CFX_XMLNode::NodeItem eItem)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 
Clone()326 std::unique_ptr<CFX_XMLNode> CFX_XMLNode::Clone() {
327   return nullptr;
328 }
329 
SaveXMLNode(const RetainPtr<CFX_SeekableStreamProxy> & pXMLStream)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