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"&"); 356 wsValue.Replace(L"<", L"<"); 357 wsValue.Replace(L">", L">"); 358 wsValue.Replace(L"\'", L"'"); 359 wsValue.Replace(L"\"", L"""); 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"&"); 389 wsValue.Replace(L"<", L"<"); 390 wsValue.Replace(L">", L">"); 391 wsValue.Replace(L"\'", L"'"); 392 wsValue.Replace(L"\"", L"""); 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"&"); 421 ws.Replace(L"<", L"<"); 422 ws.Replace(L">", L">"); 423 ws.Replace(L"\'", L"'"); 424 ws.Replace(L"\"", L"""); 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