| // 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" | |
| CXML_Element::CXML_Element(const CXML_Element* pParent, | |
| const CFX_ByteStringC& qSpace, | |
| const CFX_ByteStringC& tagname) | |
| : m_pParent(pParent), m_QSpaceName(qSpace), m_TagName(tagname) {} | |
| CXML_Element::~CXML_Element() { | |
| Empty(); | |
| } | |
| void CXML_Element::Empty() { | |
| RemoveChildren(); | |
| } | |
| void CXML_Element::RemoveChildren() { | |
| for (const ChildRecord& record : m_Children) { | |
| if (record.type == Content) { | |
| delete static_cast<CXML_Content*>(record.child); | |
| } else if (record.type == Element) { | |
| CXML_Element* child = static_cast<CXML_Element*>(record.child); | |
| child->RemoveChildren(); | |
| delete child; | |
| } | |
| } | |
| m_Children.clear(); | |
| } | |
| CFX_ByteString CXML_Element::GetTagName(bool bQualified) const { | |
| if (!bQualified || m_QSpaceName.IsEmpty()) { | |
| return m_TagName; | |
| } | |
| CFX_ByteString bsTag = m_QSpaceName; | |
| bsTag += ":"; | |
| bsTag += m_TagName; | |
| return bsTag; | |
| } | |
| CFX_ByteString CXML_Element::GetNamespace(bool bQualified) const { | |
| return bQualified ? m_QSpaceName : GetNamespaceURI(m_QSpaceName); | |
| } | |
| CFX_ByteString CXML_Element::GetNamespaceURI( | |
| const CFX_ByteString& qName) const { | |
| const CFX_WideString* pwsSpace; | |
| const CXML_Element* pElement = this; | |
| do { | |
| if (qName.IsEmpty()) | |
| pwsSpace = pElement->m_AttrMap.Lookup("", "xmlns"); | |
| else | |
| pwsSpace = pElement->m_AttrMap.Lookup("xmlns", qName); | |
| if (pwsSpace) | |
| break; | |
| pElement = pElement->GetParent(); | |
| } while (pElement); | |
| return pwsSpace ? pwsSpace->UTF8Encode() : CFX_ByteString(); | |
| } | |
| void CXML_Element::GetAttrByIndex(int index, | |
| CFX_ByteString* space, | |
| CFX_ByteString* name, | |
| CFX_WideString* value) const { | |
| if (index < 0 || index >= m_AttrMap.GetSize()) | |
| return; | |
| CXML_AttrItem& item = m_AttrMap.GetAt(index); | |
| *space = item.m_QSpaceName; | |
| *name = item.m_AttrName; | |
| *value = item.m_Value; | |
| } | |
| bool CXML_Element::HasAttr(const CFX_ByteStringC& name) const { | |
| CFX_ByteStringC bsSpace; | |
| CFX_ByteStringC bsName; | |
| FX_XML_SplitQualifiedName(name, bsSpace, bsName); | |
| return !!m_AttrMap.Lookup(CFX_ByteString(bsSpace), CFX_ByteString(bsName)); | |
| } | |
| bool CXML_Element::GetAttrValue(const CFX_ByteStringC& name, | |
| CFX_WideString& attribute) const { | |
| CFX_ByteStringC bsSpace; | |
| CFX_ByteStringC bsName; | |
| FX_XML_SplitQualifiedName(name, bsSpace, bsName); | |
| return GetAttrValue(bsSpace, bsName, attribute); | |
| } | |
| bool CXML_Element::GetAttrValue(const CFX_ByteStringC& space, | |
| const CFX_ByteStringC& name, | |
| CFX_WideString& attribute) const { | |
| const CFX_WideString* pValue = | |
| m_AttrMap.Lookup(CFX_ByteString(space), CFX_ByteString(name)); | |
| if (!pValue) | |
| return false; | |
| attribute = *pValue; | |
| return true; | |
| } | |
| bool CXML_Element::GetAttrInteger(const CFX_ByteStringC& name, | |
| int& attribute) const { | |
| CFX_ByteStringC bsSpace; | |
| CFX_ByteStringC bsName; | |
| FX_XML_SplitQualifiedName(name, bsSpace, bsName); | |
| const CFX_WideString* pwsValue = | |
| m_AttrMap.Lookup(CFX_ByteString(bsSpace), CFX_ByteString(bsName)); | |
| if (!pwsValue) | |
| return false; | |
| attribute = pwsValue->GetInteger(); | |
| return true; | |
| } | |
| bool CXML_Element::GetAttrInteger(const CFX_ByteStringC& space, | |
| const CFX_ByteStringC& name, | |
| int& attribute) const { | |
| const CFX_WideString* pwsValue = | |
| m_AttrMap.Lookup(CFX_ByteString(space), CFX_ByteString(name)); | |
| if (!pwsValue) | |
| return false; | |
| attribute = pwsValue->GetInteger(); | |
| return true; | |
| } | |
| bool CXML_Element::GetAttrFloat(const CFX_ByteStringC& name, | |
| float& attribute) const { | |
| CFX_ByteStringC bsSpace; | |
| CFX_ByteStringC bsName; | |
| FX_XML_SplitQualifiedName(name, bsSpace, bsName); | |
| return GetAttrFloat(bsSpace, bsName, attribute); | |
| } | |
| bool CXML_Element::GetAttrFloat(const CFX_ByteStringC& space, | |
| const CFX_ByteStringC& name, | |
| float& attribute) const { | |
| const CFX_WideString* pValue = | |
| m_AttrMap.Lookup(CFX_ByteString(space), CFX_ByteString(name)); | |
| if (!pValue) | |
| return false; | |
| attribute = pValue->GetFloat(); | |
| return true; | |
| } | |
| CXML_Element::ChildType CXML_Element::GetChildType(uint32_t index) const { | |
| return index < m_Children.size() ? m_Children[index].type : Invalid; | |
| } | |
| CFX_WideString CXML_Element::GetContent(uint32_t index) const { | |
| if (index < m_Children.size() && m_Children[index].type == Content) { | |
| CXML_Content* pContent = | |
| static_cast<CXML_Content*>(m_Children[index].child); | |
| if (pContent) | |
| return pContent->m_Content; | |
| } | |
| return CFX_WideString(); | |
| } | |
| CXML_Element* CXML_Element::GetElement(uint32_t index) const { | |
| if (index < m_Children.size() && m_Children[index].type == Element) | |
| return static_cast<CXML_Element*>(m_Children[index].child); | |
| return nullptr; | |
| } | |
| uint32_t CXML_Element::CountElements(const CFX_ByteStringC& space, | |
| const CFX_ByteStringC& tag) const { | |
| int count = 0; | |
| for (const ChildRecord& record : m_Children) { | |
| if (record.type != Element) | |
| continue; | |
| CXML_Element* pKid = static_cast<CXML_Element*>(record.child); | |
| if ((space.IsEmpty() || pKid->m_QSpaceName == space) && | |
| pKid->m_TagName == tag) { | |
| count++; | |
| } | |
| } | |
| return count; | |
| } | |
| CXML_Element* CXML_Element::GetElement(const CFX_ByteStringC& space, | |
| const CFX_ByteStringC& tag, | |
| int index) const { | |
| if (index < 0) | |
| return nullptr; | |
| for (const ChildRecord& record : m_Children) { | |
| if (record.type != Element) | |
| continue; | |
| CXML_Element* pKid = static_cast<CXML_Element*>(record.child); | |
| if ((space.IsEmpty() || pKid->m_QSpaceName == space) && | |
| pKid->m_TagName == tag) { | |
| if (index-- == 0) | |
| return pKid; | |
| } | |
| } | |
| return nullptr; | |
| } | |
| uint32_t CXML_Element::FindElement(CXML_Element* pChild) const { | |
| int index = 0; | |
| for (const ChildRecord& record : m_Children) { | |
| if (record.type == Element && | |
| static_cast<CXML_Element*>(record.child) == pChild) { | |
| return index; | |
| } | |
| ++index; | |
| } | |
| return 0xFFFFFFFF; | |
| } | |
| void CXML_Element::SetTag(const CFX_ByteStringC& qTagName) { | |
| ASSERT(!qTagName.IsEmpty()); | |
| CFX_ByteStringC bsSpace; | |
| CFX_ByteStringC bsName; | |
| FX_XML_SplitQualifiedName(qTagName, bsSpace, bsName); | |
| m_QSpaceName = bsSpace; | |
| m_TagName = bsName; | |
| } |