• 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/cxml_element.h"
8 
9 #include "core/fxcrt/xml/cxml_content.h"
10 #include "core/fxcrt/xml/cxml_parser.h"
11 
12 namespace {
13 
SplitQualifiedName(const ByteStringView & bsFullName,ByteStringView * bsSpace,ByteStringView * bsName)14 void SplitQualifiedName(const ByteStringView& bsFullName,
15                         ByteStringView* bsSpace,
16                         ByteStringView* bsName) {
17   if (bsFullName.IsEmpty())
18     return;
19 
20   auto iStart = bsFullName.Find(':');
21   if (iStart.has_value()) {
22     *bsSpace = bsFullName.Left(iStart.value());
23     *bsName = bsFullName.Right(bsFullName.GetLength() - (iStart.value() + 1));
24   } else {
25     *bsName = bsFullName;
26   }
27 }
28 
29 }  // namespace
30 
31 // static
Parse(const void * pBuffer,size_t size)32 std::unique_ptr<CXML_Element> CXML_Element::Parse(const void* pBuffer,
33                                                   size_t size) {
34   CXML_Parser parser;
35   if (!parser.Init(static_cast<const uint8_t*>(pBuffer), size))
36     return nullptr;
37   return parser.ParseElement(nullptr, false);
38 }
39 
CXML_Element(const CXML_Element * pParent,const ByteStringView & qSpace,const ByteStringView & tagname)40 CXML_Element::CXML_Element(const CXML_Element* pParent,
41                            const ByteStringView& qSpace,
42                            const ByteStringView& tagname)
43     : m_pParent(pParent), m_QSpaceName(qSpace), m_TagName(tagname) {}
44 
~CXML_Element()45 CXML_Element::~CXML_Element() {}
46 
AsElement()47 CXML_Element* CXML_Element::AsElement() {
48   return this;
49 }
50 
AsElement() const51 const CXML_Element* CXML_Element::AsElement() const {
52   return this;
53 }
54 
GetTagName() const55 ByteString CXML_Element::GetTagName() const {
56   return m_TagName;
57 }
58 
GetNamespaceURI(const ByteString & qName) const59 ByteString CXML_Element::GetNamespaceURI(const ByteString& qName) const {
60   const CXML_Element* pElement = this;
61   do {
62     const WideString* pwsSpace;
63     if (qName.IsEmpty())
64       pwsSpace = pElement->Lookup("", "xmlns");
65     else
66       pwsSpace = pElement->Lookup("xmlns", qName);
67     if (pwsSpace)
68       return pwsSpace->UTF8Encode();
69 
70     pElement = pElement->GetParent();
71   } while (pElement);
72   return ByteString();
73 }
74 
GetAttrByIndex(size_t index,ByteString * space,ByteString * name,WideString * value) const75 void CXML_Element::GetAttrByIndex(size_t index,
76                                   ByteString* space,
77                                   ByteString* name,
78                                   WideString* value) const {
79   if (index >= m_AttrMap.size())
80     return;
81 
82   const CXML_AttrItem& item = m_AttrMap[index];
83   *space = item.m_QSpaceName;
84   *name = item.m_AttrName;
85   *value = item.m_Value;
86 }
87 
GetAttrValue(const ByteStringView & name) const88 WideString CXML_Element::GetAttrValue(const ByteStringView& name) const {
89   ByteStringView bsSpace;
90   ByteStringView bsName;
91   SplitQualifiedName(name, &bsSpace, &bsName);
92 
93   WideString attr;
94   const WideString* pValue = Lookup(ByteString(bsSpace), ByteString(bsName));
95   if (pValue)
96     attr = *pValue;
97   return attr;
98 }
99 
GetAttrInteger(const ByteStringView & name) const100 int CXML_Element::GetAttrInteger(const ByteStringView& name) const {
101   ByteStringView bsSpace;
102   ByteStringView bsName;
103   SplitQualifiedName(name, &bsSpace, &bsName);
104 
105   const WideString* pwsValue = Lookup(ByteString(bsSpace), ByteString(bsName));
106   return pwsValue ? pwsValue->GetInteger() : 0;
107 }
108 
CountElements(const ByteStringView & space,const ByteStringView & tag) const109 size_t CXML_Element::CountElements(const ByteStringView& space,
110                                    const ByteStringView& tag) const {
111   size_t count = 0;
112   for (const auto& pChild : m_Children) {
113     const CXML_Element* pKid = pChild->AsElement();
114     if (MatchesElement(pKid, space, tag))
115       count++;
116   }
117   return count;
118 }
119 
GetChild(size_t index) const120 CXML_Object* CXML_Element::GetChild(size_t index) const {
121   return index < m_Children.size() ? m_Children[index].get() : nullptr;
122 }
123 
GetElement(const ByteStringView & space,const ByteStringView & tag,size_t nth) const124 CXML_Element* CXML_Element::GetElement(const ByteStringView& space,
125                                        const ByteStringView& tag,
126                                        size_t nth) const {
127   for (const auto& pChild : m_Children) {
128     CXML_Element* pKid = pChild->AsElement();
129     if (MatchesElement(pKid, space, tag)) {
130       if (nth == 0)
131         return pKid;
132       --nth;
133     }
134   }
135   return nullptr;
136 }
137 
SetAttribute(const ByteString & space,const ByteString & name,const WideString & value)138 void CXML_Element::SetAttribute(const ByteString& space,
139                                 const ByteString& name,
140                                 const WideString& value) {
141   for (CXML_AttrItem& item : m_AttrMap) {
142     if (item.Matches(space, name)) {
143       item.m_Value = value;
144       return;
145     }
146   }
147   m_AttrMap.push_back({space, name, WideString(value)});
148 }
149 
150 // static
MatchesElement(const CXML_Element * pKid,const ByteStringView & space,const ByteStringView & tag)151 bool CXML_Element::MatchesElement(const CXML_Element* pKid,
152                                   const ByteStringView& space,
153                                   const ByteStringView& tag) {
154   return pKid && pKid->m_TagName == tag &&
155          (space.IsEmpty() || pKid->m_QSpaceName == space);
156 }
157 
Lookup(const ByteString & space,const ByteString & name) const158 const WideString* CXML_Element::Lookup(const ByteString& space,
159                                        const ByteString& name) const {
160   for (const CXML_AttrItem& item : m_AttrMap) {
161     if (item.Matches(space, name))
162       return &item.m_Value;
163   }
164   return nullptr;
165 }
166