blob: 17caebfa143a4fd2ab1ceb2ef6f5890e342ae2cf [file] [log] [blame]
// 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;
}