| // 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; |
| } |