• 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_xmlelement.h"
8 
9 #include <utility>
10 
11 #include "core/fxcrt/cfx_widetextbuf.h"
12 #include "core/fxcrt/fx_extension.h"
13 #include "core/fxcrt/xml/cfx_xmlchardata.h"
14 #include "core/fxcrt/xml/cfx_xmldocument.h"
15 #include "core/fxcrt/xml/cfx_xmltext.h"
16 
CFX_XMLElement(const WideString & wsTag)17 CFX_XMLElement::CFX_XMLElement(const WideString& wsTag) : name_(wsTag) {
18   ASSERT(!name_.IsEmpty());
19 }
20 
21 CFX_XMLElement::~CFX_XMLElement() = default;
22 
GetType() const23 CFX_XMLNode::Type CFX_XMLElement::GetType() const {
24   return Type::kElement;
25 }
26 
Clone(CFX_XMLDocument * doc)27 CFX_XMLNode* CFX_XMLElement::Clone(CFX_XMLDocument* doc) {
28   auto* node = doc->CreateNode<CFX_XMLElement>(name_);
29   node->attrs_ = attrs_;
30 
31   // TODO(dsinclair): This clone is wrong. It doesn't clone all child nodes just
32   // text nodes?
33   for (CFX_XMLNode* pChild = GetFirstChild(); pChild;
34        pChild = pChild->GetNextSibling()) {
35     if (pChild->GetType() == Type::kText)
36       node->AppendLastChild(pChild->Clone(doc));
37   }
38   return node;
39 }
40 
GetLocalTagName() const41 WideString CFX_XMLElement::GetLocalTagName() const {
42   auto pos = name_.Find(L':');
43   return pos.has_value() ? name_.Last(name_.GetLength() - pos.value() - 1)
44                          : name_;
45 }
46 
GetNamespacePrefix() const47 WideString CFX_XMLElement::GetNamespacePrefix() const {
48   auto pos = name_.Find(L':');
49   return pos.has_value() ? name_.First(pos.value()) : WideString();
50 }
51 
GetNamespaceURI() const52 WideString CFX_XMLElement::GetNamespaceURI() const {
53   WideString attr(L"xmlns");
54   WideString wsPrefix = GetNamespacePrefix();
55   if (!wsPrefix.IsEmpty()) {
56     attr += L":";
57     attr += wsPrefix;
58   }
59   const CFX_XMLNode* pNode = this;
60   while (pNode && pNode->GetType() == Type::kElement) {
61     auto* pElement = static_cast<const CFX_XMLElement*>(pNode);
62     if (!pElement->HasAttribute(attr)) {
63       pNode = pNode->GetParent();
64       continue;
65     }
66     return pElement->GetAttribute(attr);
67   }
68   return WideString();
69 }
70 
GetTextData() const71 WideString CFX_XMLElement::GetTextData() const {
72   CFX_WideTextBuf buffer;
73   for (CFX_XMLNode* pChild = GetFirstChild(); pChild;
74        pChild = pChild->GetNextSibling()) {
75     CFX_XMLText* pText = ToXMLText(pChild);
76     if (pText)
77       buffer << pText->GetText();
78   }
79   return buffer.MakeString();
80 }
81 
Save(const RetainPtr<IFX_SeekableWriteStream> & pXMLStream)82 void CFX_XMLElement::Save(
83     const RetainPtr<IFX_SeekableWriteStream>& pXMLStream) {
84   ByteString bsNameEncoded = name_.ToUTF8();
85 
86   pXMLStream->WriteString("<");
87   pXMLStream->WriteString(bsNameEncoded.AsStringView());
88 
89   for (auto it : attrs_) {
90     // Note, the space between attributes is added by AttributeToString which
91     // writes a blank as the first character.
92     pXMLStream->WriteString(
93         AttributeToString(it.first, it.second).ToUTF8().AsStringView());
94   }
95 
96   if (!GetFirstChild()) {
97     pXMLStream->WriteString(" />\n");
98     return;
99   }
100 
101   pXMLStream->WriteString(">\n");
102 
103   for (CFX_XMLNode* pChild = GetFirstChild(); pChild;
104        pChild = pChild->GetNextSibling()) {
105     pChild->Save(pXMLStream);
106   }
107   pXMLStream->WriteString("</");
108   pXMLStream->WriteString(bsNameEncoded.AsStringView());
109   pXMLStream->WriteString(">\n");
110 }
111 
GetFirstChildNamed(WideStringView name) const112 CFX_XMLElement* CFX_XMLElement::GetFirstChildNamed(WideStringView name) const {
113   return GetNthChildNamed(name, 0);
114 }
115 
GetNthChildNamed(WideStringView name,size_t idx) const116 CFX_XMLElement* CFX_XMLElement::GetNthChildNamed(WideStringView name,
117                                                  size_t idx) const {
118   for (auto* child = GetFirstChild(); child; child = child->GetNextSibling()) {
119     CFX_XMLElement* elem = ToXMLElement(child);
120     if (!elem || elem->name_ != name)
121       continue;
122     if (idx == 0)
123       return elem;
124 
125     --idx;
126   }
127   return nullptr;
128 }
129 
HasAttribute(const WideString & name) const130 bool CFX_XMLElement::HasAttribute(const WideString& name) const {
131   return attrs_.find(name) != attrs_.end();
132 }
133 
GetAttribute(const WideString & name) const134 WideString CFX_XMLElement::GetAttribute(const WideString& name) const {
135   auto it = attrs_.find(name);
136   return it != attrs_.end() ? it->second : WideString();
137 }
138 
SetAttribute(const WideString & name,const WideString & value)139 void CFX_XMLElement::SetAttribute(const WideString& name,
140                                   const WideString& value) {
141   attrs_[name] = value;
142 }
143 
RemoveAttribute(const WideString & name)144 void CFX_XMLElement::RemoveAttribute(const WideString& name) {
145   attrs_.erase(name);
146 }
147 
AttributeToString(const WideString & name,const WideString & value)148 WideString CFX_XMLElement::AttributeToString(const WideString& name,
149                                              const WideString& value) {
150   WideString ret = L" ";
151   ret += name;
152   ret += L"=\"";
153   ret += EncodeEntities(value);
154   ret += L"\"";
155   return ret;
156 }
157