// 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 "core/fxcrt/xml/cxml_element.h" #include "core/fxcrt/xml/cxml_content.h" #include "core/fxcrt/xml/cxml_parser.h" namespace { void SplitQualifiedName(const ByteStringView& bsFullName, ByteStringView* bsSpace, ByteStringView* bsName) { if (bsFullName.IsEmpty()) return; auto iStart = bsFullName.Find(':'); if (iStart.has_value()) { *bsSpace = bsFullName.Left(iStart.value()); *bsName = bsFullName.Right(bsFullName.GetLength() - (iStart.value() + 1)); } else { *bsName = bsFullName; } } } // namespace // static std::unique_ptr CXML_Element::Parse(const void* pBuffer, size_t size) { CXML_Parser parser; if (!parser.Init(static_cast(pBuffer), size)) return nullptr; return parser.ParseElement(nullptr, false); } CXML_Element::CXML_Element(const CXML_Element* pParent, const ByteStringView& qSpace, const ByteStringView& tagname) : m_pParent(pParent), m_QSpaceName(qSpace), m_TagName(tagname) {} CXML_Element::~CXML_Element() {} CXML_Element* CXML_Element::AsElement() { return this; } const CXML_Element* CXML_Element::AsElement() const { return this; } ByteString CXML_Element::GetTagName() const { return m_TagName; } ByteString CXML_Element::GetNamespaceURI(const ByteString& qName) const { const CXML_Element* pElement = this; do { const WideString* pwsSpace; if (qName.IsEmpty()) pwsSpace = pElement->Lookup("", "xmlns"); else pwsSpace = pElement->Lookup("xmlns", qName); if (pwsSpace) return pwsSpace->UTF8Encode(); pElement = pElement->GetParent(); } while (pElement); return ByteString(); } void CXML_Element::GetAttrByIndex(size_t index, ByteString* space, ByteString* name, WideString* value) const { if (index >= m_AttrMap.size()) return; const CXML_AttrItem& item = m_AttrMap[index]; *space = item.m_QSpaceName; *name = item.m_AttrName; *value = item.m_Value; } WideString CXML_Element::GetAttrValue(const ByteStringView& name) const { ByteStringView bsSpace; ByteStringView bsName; SplitQualifiedName(name, &bsSpace, &bsName); WideString attr; const WideString* pValue = Lookup(ByteString(bsSpace), ByteString(bsName)); if (pValue) attr = *pValue; return attr; } int CXML_Element::GetAttrInteger(const ByteStringView& name) const { ByteStringView bsSpace; ByteStringView bsName; SplitQualifiedName(name, &bsSpace, &bsName); const WideString* pwsValue = Lookup(ByteString(bsSpace), ByteString(bsName)); return pwsValue ? pwsValue->GetInteger() : 0; } size_t CXML_Element::CountElements(const ByteStringView& space, const ByteStringView& tag) const { size_t count = 0; for (const auto& pChild : m_Children) { const CXML_Element* pKid = pChild->AsElement(); if (MatchesElement(pKid, space, tag)) count++; } return count; } CXML_Object* CXML_Element::GetChild(size_t index) const { return index < m_Children.size() ? m_Children[index].get() : nullptr; } CXML_Element* CXML_Element::GetElement(const ByteStringView& space, const ByteStringView& tag, size_t nth) const { for (const auto& pChild : m_Children) { CXML_Element* pKid = pChild->AsElement(); if (MatchesElement(pKid, space, tag)) { if (nth == 0) return pKid; --nth; } } return nullptr; } void CXML_Element::SetAttribute(const ByteString& space, const ByteString& name, const WideString& value) { for (CXML_AttrItem& item : m_AttrMap) { if (item.Matches(space, name)) { item.m_Value = value; return; } } m_AttrMap.push_back({space, name, WideString(value)}); } // static bool CXML_Element::MatchesElement(const CXML_Element* pKid, const ByteStringView& space, const ByteStringView& tag) { return pKid && pKid->m_TagName == tag && (space.IsEmpty() || pKid->m_QSpaceName == space); } const WideString* CXML_Element::Lookup(const ByteString& space, const ByteString& name) const { for (const CXML_AttrItem& item : m_AttrMap) { if (item.Matches(space, name)) return &item.m_Value; } return nullptr; }