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