diff options
Diffstat (limited to 'xfa/fde/xml/cfde_xmlnode.cpp')
-rw-r--r-- | xfa/fde/xml/cfde_xmlnode.cpp | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/xfa/fde/xml/cfde_xmlnode.cpp b/xfa/fde/xml/cfde_xmlnode.cpp new file mode 100644 index 0000000000..bd86c0b071 --- /dev/null +++ b/xfa/fde/xml/cfde_xmlnode.cpp @@ -0,0 +1,458 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "xfa/fde/xml/cfde_xmlnode.h" + +#include <vector> + +#include "third_party/base/stl_util.h" +#include "xfa/fde/xml/cfde_xmlchardata.h" +#include "xfa/fde/xml/cfde_xmlelement.h" +#include "xfa/fde/xml/cfde_xmlinstruction.h" +#include "xfa/fde/xml/cfde_xmltext.h" +#include "xfa/fgas/crt/fgas_codepage.h" + +CFDE_XMLNode::CFDE_XMLNode() + : m_pParent(nullptr), + m_pChild(nullptr), + m_pPrior(nullptr), + m_pNext(nullptr) {} + +FDE_XMLNODETYPE CFDE_XMLNode::GetType() const { + return FDE_XMLNODE_Unknown; +} + +CFDE_XMLNode::~CFDE_XMLNode() { + DeleteChildren(); +} + +void CFDE_XMLNode::DeleteChildren() { + CFDE_XMLNode* pChild = m_pChild; + while (pChild) { + CFDE_XMLNode* pNext = pChild->m_pNext; + delete pChild; + pChild = pNext; + } + m_pChild = nullptr; +} + +int32_t CFDE_XMLNode::CountChildNodes() const { + int32_t iCount = 0; + CFDE_XMLNode* pChild = m_pChild; + while (pChild) { + iCount++; + pChild = pChild->m_pNext; + } + return iCount; +} + +CFDE_XMLNode* CFDE_XMLNode::GetChildNode(int32_t index) const { + CFDE_XMLNode* pChild = m_pChild; + while (pChild) { + if (index == 0) { + return pChild; + } + index--; + pChild = pChild->m_pNext; + } + return nullptr; +} + +int32_t CFDE_XMLNode::GetChildNodeIndex(CFDE_XMLNode* pNode) const { + int32_t index = 0; + CFDE_XMLNode* pChild = m_pChild; + while (pChild) { + if (pChild == pNode) { + return index; + } + index++; + pChild = pChild->m_pNext; + } + return -1; +} + +CFDE_XMLNode* CFDE_XMLNode::GetPath(const wchar_t* pPath, + int32_t iLength, + bool bQualifiedName) const { + ASSERT(pPath); + if (iLength < 0) { + iLength = FXSYS_wcslen(pPath); + } + if (iLength == 0) { + return nullptr; + } + CFX_WideString csPath; + const wchar_t* pStart = pPath; + const wchar_t* pEnd = pPath + iLength; + wchar_t ch; + while (pStart < pEnd) { + ch = *pStart++; + if (ch == L'/') { + break; + } else { + csPath += ch; + } + } + iLength -= pStart - pPath; + CFDE_XMLNode* pFind = nullptr; + if (csPath.GetLength() < 1) { + pFind = GetNodeItem(CFDE_XMLNode::Root); + } else if (csPath.Compare(L"..") == 0) { + pFind = m_pParent; + } else if (csPath.Compare(L".") == 0) { + pFind = (CFDE_XMLNode*)this; + } else { + CFX_WideString wsTag; + CFDE_XMLNode* pNode = m_pChild; + while (pNode) { + if (pNode->GetType() == FDE_XMLNODE_Element) { + if (bQualifiedName) { + ((CFDE_XMLElement*)pNode)->GetTagName(wsTag); + } else { + ((CFDE_XMLElement*)pNode)->GetLocalTagName(wsTag); + } + if (wsTag.Compare(csPath) == 0) { + if (iLength < 1) { + pFind = pNode; + } else { + pFind = pNode->GetPath(pStart, iLength, bQualifiedName); + } + if (pFind) + return pFind; + } + } + pNode = pNode->m_pNext; + } + } + if (!pFind || iLength < 1) + return pFind; + return pFind->GetPath(pStart, iLength, bQualifiedName); +} + +int32_t CFDE_XMLNode::InsertChildNode(CFDE_XMLNode* pNode, int32_t index) { + pNode->m_pParent = this; + if (!m_pChild) { + m_pChild = pNode; + pNode->m_pPrior = nullptr; + pNode->m_pNext = nullptr; + return 0; + } + if (index == 0) { + pNode->m_pNext = m_pChild; + pNode->m_pPrior = nullptr; + m_pChild->m_pPrior = pNode; + m_pChild = pNode; + return 0; + } + int32_t iCount = 0; + CFDE_XMLNode* pFind = m_pChild; + while (++iCount != index && pFind->m_pNext) { + pFind = pFind->m_pNext; + } + pNode->m_pPrior = pFind; + pNode->m_pNext = pFind->m_pNext; + if (pFind->m_pNext) + pFind->m_pNext->m_pPrior = pNode; + pFind->m_pNext = pNode; + return iCount; +} + +void CFDE_XMLNode::RemoveChildNode(CFDE_XMLNode* pNode) { + ASSERT(m_pChild && pNode); + if (m_pChild == pNode) { + m_pChild = pNode->m_pNext; + } else { + pNode->m_pPrior->m_pNext = pNode->m_pNext; + } + if (pNode->m_pNext) + pNode->m_pNext->m_pPrior = pNode->m_pPrior; + pNode->m_pParent = nullptr; + pNode->m_pNext = nullptr; + pNode->m_pPrior = nullptr; +} + +CFDE_XMLNode* CFDE_XMLNode::GetNodeItem(CFDE_XMLNode::NodeItem eItem) const { + switch (eItem) { + case CFDE_XMLNode::Root: { + CFDE_XMLNode* pParent = (CFDE_XMLNode*)this; + while (pParent->m_pParent) { + pParent = pParent->m_pParent; + } + return pParent; + } + case CFDE_XMLNode::Parent: + return m_pParent; + case CFDE_XMLNode::FirstSibling: { + CFDE_XMLNode* pItem = (CFDE_XMLNode*)this; + while (pItem->m_pPrior) { + pItem = pItem->m_pPrior; + } + return pItem == (CFDE_XMLNode*)this ? nullptr : pItem; + } + case CFDE_XMLNode::PriorSibling: + return m_pPrior; + case CFDE_XMLNode::NextSibling: + return m_pNext; + case CFDE_XMLNode::LastSibling: { + CFDE_XMLNode* pItem = (CFDE_XMLNode*)this; + while (pItem->m_pNext) + pItem = pItem->m_pNext; + return pItem == (CFDE_XMLNode*)this ? nullptr : pItem; + } + case CFDE_XMLNode::FirstNeighbor: { + CFDE_XMLNode* pParent = (CFDE_XMLNode*)this; + while (pParent->m_pParent) + pParent = pParent->m_pParent; + return pParent == (CFDE_XMLNode*)this ? nullptr : pParent; + } + case CFDE_XMLNode::PriorNeighbor: { + if (!m_pPrior) + return m_pParent; + + CFDE_XMLNode* pItem = m_pPrior; + while (pItem->m_pChild) { + pItem = pItem->m_pChild; + while (pItem->m_pNext) + pItem = pItem->m_pNext; + } + return pItem; + } + case CFDE_XMLNode::NextNeighbor: { + if (m_pChild) + return m_pChild; + if (m_pNext) + return m_pNext; + CFDE_XMLNode* pItem = m_pParent; + while (pItem) { + if (pItem->m_pNext) + return pItem->m_pNext; + pItem = pItem->m_pParent; + } + return nullptr; + } + case CFDE_XMLNode::LastNeighbor: { + CFDE_XMLNode* pItem = (CFDE_XMLNode*)this; + while (pItem->m_pParent) { + pItem = pItem->m_pParent; + } + while (true) { + while (pItem->m_pNext) + pItem = pItem->m_pNext; + if (!pItem->m_pChild) + break; + pItem = pItem->m_pChild; + } + return pItem == (CFDE_XMLNode*)this ? nullptr : pItem; + } + case CFDE_XMLNode::FirstChild: + return m_pChild; + case CFDE_XMLNode::LastChild: { + if (!m_pChild) + return nullptr; + + CFDE_XMLNode* pChild = m_pChild; + while (pChild->m_pNext) + pChild = pChild->m_pNext; + return pChild; + } + default: + break; + } + return nullptr; +} + +int32_t CFDE_XMLNode::GetNodeLevel() const { + int32_t iLevel = 0; + const CFDE_XMLNode* pItem = m_pParent; + while (pItem) { + iLevel++; + pItem = pItem->m_pParent; + } + return iLevel; +} + +bool CFDE_XMLNode::InsertNodeItem(CFDE_XMLNode::NodeItem eItem, + CFDE_XMLNode* pNode) { + switch (eItem) { + case CFDE_XMLNode::NextSibling: { + pNode->m_pParent = m_pParent; + pNode->m_pNext = m_pNext; + pNode->m_pPrior = this; + if (m_pNext) { + m_pNext->m_pPrior = pNode; + } + m_pNext = pNode; + return true; + } + case CFDE_XMLNode::PriorSibling: { + pNode->m_pParent = m_pParent; + pNode->m_pNext = this; + pNode->m_pPrior = m_pPrior; + if (m_pPrior) { + m_pPrior->m_pNext = pNode; + } else if (m_pParent) { + m_pParent->m_pChild = pNode; + } + m_pPrior = pNode; + return true; + } + default: + return false; + } +} + +CFDE_XMLNode* CFDE_XMLNode::RemoveNodeItem(CFDE_XMLNode::NodeItem eItem) { + CFDE_XMLNode* pNode = nullptr; + switch (eItem) { + case CFDE_XMLNode::NextSibling: + if (m_pNext) { + pNode = m_pNext; + m_pNext = pNode->m_pNext; + if (m_pNext) { + m_pNext->m_pPrior = this; + } + pNode->m_pParent = nullptr; + pNode->m_pNext = nullptr; + pNode->m_pPrior = nullptr; + } + break; + default: + break; + } + return pNode; +} + +CFDE_XMLNode* CFDE_XMLNode::Clone(bool bRecursive) { + return nullptr; +} + +void CFDE_XMLNode::SaveXMLNode(const CFX_RetainPtr<IFGAS_Stream>& pXMLStream) { + CFDE_XMLNode* pNode = (CFDE_XMLNode*)this; + switch (pNode->GetType()) { + case FDE_XMLNODE_Instruction: { + CFX_WideString ws; + CFDE_XMLInstruction* pInstruction = (CFDE_XMLInstruction*)pNode; + if (pInstruction->m_wsTarget.CompareNoCase(L"xml") == 0) { + ws = L"<?xml version=\"1.0\" encoding=\""; + uint16_t wCodePage = pXMLStream->GetCodePage(); + if (wCodePage == FX_CODEPAGE_UTF16LE) { + ws += L"UTF-16"; + } else if (wCodePage == FX_CODEPAGE_UTF16BE) { + ws += L"UTF-16be"; + } else { + ws += L"UTF-8"; + } + ws += L"\"?>"; + pXMLStream->WriteString(ws.c_str(), ws.GetLength()); + } else { + ws.Format(L"<?%s", pInstruction->m_wsTarget.c_str()); + pXMLStream->WriteString(ws.c_str(), ws.GetLength()); + std::vector<CFX_WideString>& attributes = pInstruction->m_Attributes; + int32_t i; + int32_t iCount = pdfium::CollectionSize<int32_t>(attributes); + CFX_WideString wsValue; + for (i = 0; i < iCount; i += 2) { + ws = L" "; + ws += attributes[i]; + ws += L"=\""; + wsValue = attributes[i + 1]; + wsValue.Replace(L"&", L"&"); + wsValue.Replace(L"<", L"<"); + wsValue.Replace(L">", L">"); + wsValue.Replace(L"\'", L"'"); + wsValue.Replace(L"\"", L"""); + ws += wsValue; + ws += L"\""; + pXMLStream->WriteString(ws.c_str(), ws.GetLength()); + } + std::vector<CFX_WideString>& targetdata = pInstruction->m_TargetData; + iCount = pdfium::CollectionSize<int32_t>(targetdata); + for (i = 0; i < iCount; i++) { + ws = L" \""; + ws += targetdata[i]; + ws += L"\""; + pXMLStream->WriteString(ws.c_str(), ws.GetLength()); + } + ws = L"?>"; + pXMLStream->WriteString(ws.c_str(), ws.GetLength()); + } + } break; + case FDE_XMLNODE_Element: { + CFX_WideString ws; + ws = L"<"; + ws += ((CFDE_XMLElement*)pNode)->m_wsTag; + pXMLStream->WriteString(ws.c_str(), ws.GetLength()); + std::vector<CFX_WideString>& attributes = + static_cast<CFDE_XMLElement*>(pNode)->m_Attributes; + int32_t iCount = pdfium::CollectionSize<int32_t>(attributes); + CFX_WideString wsValue; + for (int32_t i = 0; i < iCount; i += 2) { + ws = L" "; + ws += attributes[i]; + ws += L"=\""; + wsValue = attributes[i + 1]; + wsValue.Replace(L"&", L"&"); + wsValue.Replace(L"<", L"<"); + wsValue.Replace(L">", L">"); + wsValue.Replace(L"\'", L"'"); + wsValue.Replace(L"\"", L"""); + ws += wsValue; + ws += L"\""; + pXMLStream->WriteString(ws.c_str(), ws.GetLength()); + } + if (pNode->m_pChild) { + ws = L"\n>"; + pXMLStream->WriteString(ws.c_str(), ws.GetLength()); + CFDE_XMLNode* pChild = pNode->m_pChild; + while (pChild) { + pChild->SaveXMLNode(pXMLStream); + pChild = pChild->m_pNext; + } + ws = L"</"; + ws += ((CFDE_XMLElement*)pNode)->m_wsTag; + ws += L"\n>"; + } else { + ws = L"\n/>"; + } + pXMLStream->WriteString(ws.c_str(), ws.GetLength()); + } break; + case FDE_XMLNODE_Text: { + CFX_WideString ws = ((CFDE_XMLText*)pNode)->m_wsText; + ws.Replace(L"&", L"&"); + ws.Replace(L"<", L"<"); + ws.Replace(L">", L">"); + ws.Replace(L"\'", L"'"); + ws.Replace(L"\"", L"""); + pXMLStream->WriteString(ws.c_str(), ws.GetLength()); + } break; + case FDE_XMLNODE_CharData: { + CFX_WideString ws = L"<![CDATA["; + ws += ((CFDE_XMLCharData*)pNode)->m_wsCharData; + ws += L"]]>"; + pXMLStream->WriteString(ws.c_str(), ws.GetLength()); + } break; + case FDE_XMLNODE_Unknown: + break; + default: + break; + } +} + +void CFDE_XMLNode::CloneChildren(CFDE_XMLNode* pClone) { + if (!m_pChild) { + return; + } + CFDE_XMLNode* pNext = m_pChild; + CFDE_XMLNode* pCloneNext = pNext->Clone(true); + pClone->InsertChildNode(pCloneNext); + pNext = pNext->m_pNext; + while (pNext) { + CFDE_XMLNode* pChild = pNext->Clone(true); + pCloneNext->InsertNodeItem(CFDE_XMLNode::NextSibling, pChild); + pCloneNext = pChild; + pNext = pNext->m_pNext; + } +} |