Home | History | Annotate | Download | only in xml
      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 
     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
     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 
     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 
     45 CXML_Element::~CXML_Element() {}
     46 
     47 CXML_Element* CXML_Element::AsElement() {
     48   return this;
     49 }
     50 
     51 const CXML_Element* CXML_Element::AsElement() const {
     52   return this;
     53 }
     54 
     55 ByteString CXML_Element::GetTagName() const {
     56   return m_TagName;
     57 }
     58 
     59 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 
     75 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 
     88 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 
    100 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 
    109 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 
    120 CXML_Object* CXML_Element::GetChild(size_t index) const {
    121   return index < m_Children.size() ? m_Children[index].get() : nullptr;
    122 }
    123 
    124 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 
    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
    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 
    158 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