blob: 0b71836ef9cfd057184f08d192d5521e0c0e8a64 [file] [log] [blame]
// Copyright 2014 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 "xml_int.h"
#include "core/include/fxcrt/fx_ext.h"
#include "core/include/fxcrt/fx_xml.h"
CXML_Parser::~CXML_Parser() {
if (m_bOwnedStream) {
m_pDataAcc->Release();
}
}
FX_BOOL CXML_Parser::Init(uint8_t* pBuffer, size_t size) {
m_pDataAcc = new CXML_DataBufAcc(pBuffer, size);
return Init(TRUE);
}
FX_BOOL CXML_Parser::Init(IFX_FileRead* pFileRead) {
m_pDataAcc = new CXML_DataStmAcc(pFileRead);
return Init(TRUE);
}
FX_BOOL CXML_Parser::Init(IFX_BufferRead* pBuffer) {
if (!pBuffer) {
return FALSE;
}
m_pDataAcc = pBuffer;
return Init(FALSE);
}
FX_BOOL CXML_Parser::Init(FX_BOOL bOwndedStream) {
m_bOwnedStream = bOwndedStream;
m_nOffset = 0;
return ReadNextBlock();
}
FX_BOOL CXML_Parser::ReadNextBlock() {
if (!m_pDataAcc->ReadNextBlock()) {
return FALSE;
}
m_pBuffer = m_pDataAcc->GetBlockBuffer();
m_dwBufferSize = m_pDataAcc->GetBlockSize();
m_nBufferOffset = m_pDataAcc->GetBlockOffset();
m_dwIndex = 0;
return m_dwBufferSize > 0;
}
FX_BOOL CXML_Parser::IsEOF() {
if (!m_pDataAcc->IsEOF()) {
return FALSE;
}
return m_dwIndex >= m_dwBufferSize;
}
#define FXCRTM_XML_CHARTYPE_Normal 0x00
#define FXCRTM_XML_CHARTYPE_SpaceChar 0x01
#define FXCRTM_XML_CHARTYPE_Letter 0x02
#define FXCRTM_XML_CHARTYPE_Digital 0x04
#define FXCRTM_XML_CHARTYPE_NameIntro 0x08
#define FXCRTM_XML_CHARTYPE_NameChar 0x10
#define FXCRTM_XML_CHARTYPE_HexDigital 0x20
#define FXCRTM_XML_CHARTYPE_HexLowerLetter 0x40
#define FXCRTM_XML_CHARTYPE_HexUpperLetter 0x60
#define FXCRTM_XML_CHARTYPE_HexChar 0x60
uint8_t g_FXCRT_XML_ByteTypes[256] = {
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,
0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x1A,
0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x18,
0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
0x1A, 0x1A, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x1A, 0x1A, 0x1A,
0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
0x1A, 0x1A, 0x01, 0x01,
};
FX_BOOL g_FXCRT_XML_IsWhiteSpace(uint8_t ch) {
return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_SpaceChar) != 0;
}
FX_BOOL g_FXCRT_XML_IsLetter(uint8_t ch) {
return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_Letter) != 0;
}
FX_BOOL g_FXCRT_XML_IsDigital(uint8_t ch) {
return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_Digital) != 0;
}
FX_BOOL g_FXCRT_XML_IsNameIntro(uint8_t ch) {
return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_NameIntro) != 0;
}
FX_BOOL g_FXCRT_XML_IsNameChar(uint8_t ch) {
return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_NameChar) != 0;
}
FX_BOOL g_FXCRT_XML_IsHexChar(uint8_t ch) {
return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_HexChar) != 0;
}
void CXML_Parser::SkipWhiteSpaces() {
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
if (IsEOF()) {
return;
}
do {
while (m_dwIndex < m_dwBufferSize &&
g_FXCRT_XML_IsWhiteSpace(m_pBuffer[m_dwIndex])) {
m_dwIndex++;
}
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
if (m_dwIndex < m_dwBufferSize || IsEOF()) {
break;
}
} while (ReadNextBlock());
}
void CXML_Parser::GetName(CFX_ByteString& space, CFX_ByteString& name) {
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
if (IsEOF()) {
return;
}
CFX_ByteTextBuf buf;
uint8_t ch;
do {
while (m_dwIndex < m_dwBufferSize) {
ch = m_pBuffer[m_dwIndex];
if (ch == ':') {
space = buf.GetByteString();
buf.Clear();
} else if (g_FXCRT_XML_IsNameChar(ch)) {
buf.AppendChar(ch);
} else {
break;
}
m_dwIndex++;
}
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
if (m_dwIndex < m_dwBufferSize || IsEOF()) {
break;
}
} while (ReadNextBlock());
name = buf.GetByteString();
}
void CXML_Parser::SkipLiterals(const CFX_ByteStringC& str) {
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
if (IsEOF()) {
return;
}
int32_t i = 0, iLen = str.GetLength();
do {
while (m_dwIndex < m_dwBufferSize) {
if (str.GetAt(i) != m_pBuffer[m_dwIndex++]) {
i = 0;
} else {
i++;
if (i == iLen) {
break;
}
}
}
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
if (i == iLen) {
return;
}
if (m_dwIndex < m_dwBufferSize || IsEOF()) {
break;
}
} while (ReadNextBlock());
while (!m_pDataAcc->IsEOF()) {
ReadNextBlock();
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwBufferSize;
}
m_dwIndex = m_dwBufferSize;
}
FX_DWORD CXML_Parser::GetCharRef() {
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
if (IsEOF()) {
return 0;
}
uint8_t ch;
int32_t iState = 0;
CFX_ByteTextBuf buf;
FX_DWORD code = 0;
do {
while (m_dwIndex < m_dwBufferSize) {
ch = m_pBuffer[m_dwIndex];
switch (iState) {
case 0:
if (ch == '#') {
m_dwIndex++;
iState = 2;
break;
}
iState = 1;
case 1:
m_dwIndex++;
if (ch == ';') {
CFX_ByteStringC ref = buf.GetByteString();
if (ref == "gt") {
code = '>';
} else if (ref == "lt") {
code = '<';
} else if (ref == "amp") {
code = '&';
} else if (ref == "apos") {
code = '\'';
} else if (ref == "quot") {
code = '"';
}
iState = 10;
break;
}
buf.AppendByte(ch);
break;
case 2:
if (ch == 'x') {
m_dwIndex++;
iState = 4;
break;
}
iState = 3;
case 3:
m_dwIndex++;
if (ch == ';') {
iState = 10;
break;
}
if (g_FXCRT_XML_IsDigital(ch))
code = code * 10 + FXSYS_toDecimalDigit(ch);
break;
case 4:
m_dwIndex++;
if (ch == ';') {
iState = 10;
break;
}
uint8_t nHex =
g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_HexChar;
if (nHex) {
if (nHex == FXCRTM_XML_CHARTYPE_HexDigital) {
code = (code << 4) + FXSYS_toDecimalDigit(ch);
} else if (nHex == FXCRTM_XML_CHARTYPE_HexLowerLetter) {
code = (code << 4) + ch - 87;
} else {
code = (code << 4) + ch - 55;
}
}
break;
}
if (iState == 10) {
break;
}
}
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
if (iState == 10 || m_dwIndex < m_dwBufferSize || IsEOF()) {
break;
}
} while (ReadNextBlock());
return code;
}
void CXML_Parser::GetAttrValue(CFX_WideString& value) {
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
if (IsEOF()) {
return;
}
CFX_UTF8Decoder decoder;
uint8_t mark = 0, ch = 0;
do {
while (m_dwIndex < m_dwBufferSize) {
ch = m_pBuffer[m_dwIndex];
if (mark == 0) {
if (ch != '\'' && ch != '"') {
return;
}
mark = ch;
m_dwIndex++;
ch = 0;
continue;
}
m_dwIndex++;
if (ch == mark) {
break;
}
if (ch == '&') {
decoder.AppendChar(GetCharRef());
if (IsEOF()) {
value = decoder.GetResult();
return;
}
} else {
decoder.Input(ch);
}
}
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
if (ch == mark || m_dwIndex < m_dwBufferSize || IsEOF()) {
break;
}
} while (ReadNextBlock());
value = decoder.GetResult();
}
void CXML_Parser::GetTagName(CFX_ByteString& space,
CFX_ByteString& name,
FX_BOOL& bEndTag,
FX_BOOL bStartTag) {
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
if (IsEOF()) {
return;
}
bEndTag = FALSE;
uint8_t ch;
int32_t iState = bStartTag ? 1 : 0;
do {
while (m_dwIndex < m_dwBufferSize) {
ch = m_pBuffer[m_dwIndex];
switch (iState) {
case 0:
m_dwIndex++;
if (ch != '<') {
break;
}
iState = 1;
break;
case 1:
if (ch == '?') {
m_dwIndex++;
SkipLiterals("?>");
iState = 0;
break;
} else if (ch == '!') {
m_dwIndex++;
SkipLiterals("-->");
iState = 0;
break;
}
if (ch == '/') {
m_dwIndex++;
GetName(space, name);
bEndTag = TRUE;
} else {
GetName(space, name);
bEndTag = FALSE;
}
return;
}
}
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
if (m_dwIndex < m_dwBufferSize || IsEOF()) {
break;
}
} while (ReadNextBlock());
}
CXML_Element* CXML_Parser::ParseElement(CXML_Element* pParent,
FX_BOOL bStartTag) {
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
if (IsEOF()) {
return NULL;
}
CFX_ByteString tag_name, tag_space;
FX_BOOL bEndTag;
GetTagName(tag_space, tag_name, bEndTag, bStartTag);
if (tag_name.IsEmpty() || bEndTag) {
return NULL;
}
CXML_Element* pElement = new CXML_Element;
pElement->m_pParent = pParent;
pElement->SetTag(tag_space, tag_name);
do {
CFX_ByteString attr_space, attr_name;
while (m_dwIndex < m_dwBufferSize) {
SkipWhiteSpaces();
if (IsEOF()) {
break;
}
if (!g_FXCRT_XML_IsNameIntro(m_pBuffer[m_dwIndex])) {
break;
}
GetName(attr_space, attr_name);
SkipWhiteSpaces();
if (IsEOF()) {
break;
}
if (m_pBuffer[m_dwIndex] != '=') {
break;
}
m_dwIndex++;
SkipWhiteSpaces();
if (IsEOF()) {
break;
}
CFX_WideString attr_value;
GetAttrValue(attr_value);
pElement->m_AttrMap.SetAt(attr_space, attr_name, attr_value);
}
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
if (m_dwIndex < m_dwBufferSize || IsEOF()) {
break;
}
} while (ReadNextBlock());
SkipWhiteSpaces();
if (IsEOF()) {
return pElement;
}
uint8_t ch = m_pBuffer[m_dwIndex++];
if (ch == '/') {
m_dwIndex++;
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
return pElement;
}
if (ch != '>') {
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
delete pElement;
return NULL;
}
SkipWhiteSpaces();
if (IsEOF()) {
return pElement;
}
CFX_UTF8Decoder decoder;
CFX_WideTextBuf content;
FX_BOOL bCDATA = FALSE;
int32_t iState = 0;
do {
while (m_dwIndex < m_dwBufferSize) {
ch = m_pBuffer[m_dwIndex++];
switch (iState) {
case 0:
if (ch == '<') {
iState = 1;
} else if (ch == '&') {
decoder.ClearStatus();
decoder.AppendChar(GetCharRef());
} else {
decoder.Input(ch);
}
break;
case 1:
if (ch == '!') {
iState = 2;
} else if (ch == '?') {
SkipLiterals("?>");
SkipWhiteSpaces();
iState = 0;
} else if (ch == '/') {
CFX_ByteString space, name;
GetName(space, name);
SkipWhiteSpaces();
m_dwIndex++;
iState = 10;
} else {
content << decoder.GetResult();
CFX_WideString dataStr = content.GetWideString();
if (!bCDATA && !m_bSaveSpaceChars) {
dataStr.TrimRight(L" \t\r\n");
}
InsertContentSegment(bCDATA, dataStr, pElement);
content.Clear();
decoder.Clear();
bCDATA = FALSE;
iState = 0;
m_dwIndex--;
CXML_Element* pSubElement = ParseElement(pElement, TRUE);
if (!pSubElement) {
break;
}
pSubElement->m_pParent = pElement;
pElement->m_Children.Add((void*)CXML_Element::Element);
pElement->m_Children.Add(pSubElement);
SkipWhiteSpaces();
}
break;
case 2:
if (ch == '[') {
SkipLiterals("]]>");
} else if (ch == '-') {
m_dwIndex++;
SkipLiterals("-->");
} else {
SkipLiterals(">");
}
decoder.Clear();
SkipWhiteSpaces();
iState = 0;
break;
}
if (iState == 10) {
break;
}
}
m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
if (iState == 10 || m_dwIndex < m_dwBufferSize || IsEOF()) {
break;
}
} while (ReadNextBlock());
content << decoder.GetResult();
CFX_WideString dataStr = content.GetWideString();
if (!m_bSaveSpaceChars) {
dataStr.TrimRight(L" \t\r\n");
}
InsertContentSegment(bCDATA, dataStr, pElement);
content.Clear();
decoder.Clear();
bCDATA = FALSE;
return pElement;
}
void CXML_Parser::InsertContentSegment(FX_BOOL bCDATA,
const CFX_WideStringC& content,
CXML_Element* pElement) {
if (content.IsEmpty()) {
return;
}
CXML_Content* pContent = new CXML_Content;
pContent->Set(bCDATA, content);
pElement->m_Children.Add((void*)CXML_Element::Content);
pElement->m_Children.Add(pContent);
}
static CXML_Element* XML_ContinueParse(CXML_Parser& parser,
FX_BOOL bSaveSpaceChars,
FX_FILESIZE* pParsedSize) {
parser.m_bSaveSpaceChars = bSaveSpaceChars;
CXML_Element* pElement = parser.ParseElement(NULL, FALSE);
if (pParsedSize) {
*pParsedSize = parser.m_nOffset;
}
return pElement;
}
CXML_Element* CXML_Element::Parse(const void* pBuffer,
size_t size,
FX_BOOL bSaveSpaceChars,
FX_FILESIZE* pParsedSize) {
CXML_Parser parser;
if (!parser.Init((uint8_t*)pBuffer, size)) {
return NULL;
}
return XML_ContinueParse(parser, bSaveSpaceChars, pParsedSize);
}
CXML_Element* CXML_Element::Parse(IFX_FileRead* pFile,
FX_BOOL bSaveSpaceChars,
FX_FILESIZE* pParsedSize) {
CXML_Parser parser;
if (!parser.Init(pFile)) {
return NULL;
}
return XML_ContinueParse(parser, bSaveSpaceChars, pParsedSize);
}
CXML_Element* CXML_Element::Parse(IFX_BufferRead* pBuffer,
FX_BOOL bSaveSpaceChars,
FX_FILESIZE* pParsedSize) {
CXML_Parser parser;
if (!parser.Init(pBuffer)) {
return NULL;
}
return XML_ContinueParse(parser, bSaveSpaceChars, pParsedSize);
}
CXML_Element::CXML_Element() : m_QSpaceName(), m_TagName(), m_AttrMap() {}
CXML_Element::CXML_Element(const CFX_ByteStringC& qSpace,
const CFX_ByteStringC& tagName)
: m_QSpaceName(), m_TagName(), m_AttrMap() {
m_QSpaceName = qSpace;
m_TagName = tagName;
}
CXML_Element::CXML_Element(const CFX_ByteStringC& qTagName)
: m_pParent(NULL), m_QSpaceName(), m_TagName(), m_AttrMap() {
SetTag(qTagName);
}
CXML_Element::~CXML_Element() {
Empty();
}
void CXML_Element::Empty() {
RemoveChildren();
}
void CXML_Element::RemoveChildren() {
for (int i = 0; i < m_Children.GetSize(); i += 2) {
ChildType type = (ChildType)(uintptr_t)m_Children.GetAt(i);
if (type == Content) {
CXML_Content* content = (CXML_Content*)m_Children.GetAt(i + 1);
delete content;
} else if (type == Element) {
CXML_Element* child = (CXML_Element*)m_Children.GetAt(i + 1);
child->RemoveChildren();
delete child;
}
}
m_Children.RemoveAll();
}
CFX_ByteString CXML_Element::GetTagName(FX_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(FX_BOOL bQualified) const {
if (bQualified) {
return m_QSpaceName;
}
return GetNamespaceURI(m_QSpaceName);
}
CFX_ByteString CXML_Element::GetNamespaceURI(
const CFX_ByteStringC& 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 ? FX_UTF8Encode(*pwsSpace) : 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;
}
FX_BOOL CXML_Element::HasAttr(const CFX_ByteStringC& name) const {
CFX_ByteStringC bsSpace, bsName;
FX_XML_SplitQualifiedName(name, bsSpace, bsName);
return m_AttrMap.Lookup(bsSpace, bsName) != NULL;
}
FX_BOOL CXML_Element::GetAttrValue(const CFX_ByteStringC& name,
CFX_WideString& attribute) const {
CFX_ByteStringC bsSpace, bsName;
FX_XML_SplitQualifiedName(name, bsSpace, bsName);
return GetAttrValue(bsSpace, bsName, attribute);
}
FX_BOOL CXML_Element::GetAttrValue(const CFX_ByteStringC& space,
const CFX_ByteStringC& name,
CFX_WideString& attribute) const {
const CFX_WideString* pValue = m_AttrMap.Lookup(space, name);
if (pValue) {
attribute = *pValue;
return TRUE;
}
return FALSE;
}
FX_BOOL CXML_Element::GetAttrInteger(const CFX_ByteStringC& name,
int& attribute) const {
CFX_ByteStringC bsSpace, bsName;
FX_XML_SplitQualifiedName(name, bsSpace, bsName);
const CFX_WideString* pwsValue = m_AttrMap.Lookup(bsSpace, bsName);
if (pwsValue) {
attribute = pwsValue->GetInteger();
return TRUE;
}
return FALSE;
}
FX_BOOL CXML_Element::GetAttrInteger(const CFX_ByteStringC& space,
const CFX_ByteStringC& name,
int& attribute) const {
const CFX_WideString* pwsValue = m_AttrMap.Lookup(space, name);
if (pwsValue) {
attribute = pwsValue->GetInteger();
return TRUE;
}
return FALSE;
}
FX_BOOL CXML_Element::GetAttrFloat(const CFX_ByteStringC& name,
FX_FLOAT& attribute) const {
CFX_ByteStringC bsSpace, bsName;
FX_XML_SplitQualifiedName(name, bsSpace, bsName);
return GetAttrFloat(bsSpace, bsName, attribute);
}
FX_BOOL CXML_Element::GetAttrFloat(const CFX_ByteStringC& space,
const CFX_ByteStringC& name,
FX_FLOAT& attribute) const {
const CFX_WideString* pValue = m_AttrMap.Lookup(space, name);
if (pValue) {
attribute = pValue->GetFloat();
return TRUE;
}
return FALSE;
}
FX_DWORD CXML_Element::CountChildren() const {
return m_Children.GetSize() / 2;
}
CXML_Element::ChildType CXML_Element::GetChildType(FX_DWORD index) const {
index <<= 1;
if (index >= (FX_DWORD)m_Children.GetSize()) {
return Invalid;
}
return (ChildType)(uintptr_t)m_Children.GetAt(index);
}
CFX_WideString CXML_Element::GetContent(FX_DWORD index) const {
index <<= 1;
if (index >= (FX_DWORD)m_Children.GetSize() ||
(ChildType)(uintptr_t)m_Children.GetAt(index) != Content) {
return CFX_WideString();
}
CXML_Content* pContent = (CXML_Content*)m_Children.GetAt(index + 1);
if (pContent) {
return pContent->m_Content;
}
return CFX_WideString();
}
CXML_Element* CXML_Element::GetElement(FX_DWORD index) const {
index <<= 1;
if (index >= (FX_DWORD)m_Children.GetSize() ||
(ChildType)(uintptr_t)m_Children.GetAt(index) != Element) {
return NULL;
}
return (CXML_Element*)m_Children.GetAt(index + 1);
}
FX_DWORD CXML_Element::CountElements(const CFX_ByteStringC& space,
const CFX_ByteStringC& tag) const {
int count = 0;
for (int i = 0; i < m_Children.GetSize(); i += 2) {
ChildType type = (ChildType)(uintptr_t)m_Children.GetAt(i);
if (type != Element) {
continue;
}
CXML_Element* pKid = (CXML_Element*)m_Children.GetAt(i + 1);
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 NULL;
}
for (int i = 0; i < m_Children.GetSize(); i += 2) {
ChildType type = (ChildType)(uintptr_t)m_Children.GetAt(i);
if (type != Element) {
continue;
}
CXML_Element* pKid = (CXML_Element*)m_Children.GetAt(i + 1);
if ((!space.IsEmpty() && pKid->m_QSpaceName != space) ||
pKid->m_TagName != tag) {
continue;
}
if (index-- == 0) {
return pKid;
}
}
return NULL;
}
FX_DWORD CXML_Element::FindElement(CXML_Element* pChild) const {
for (int i = 0; i < m_Children.GetSize(); i += 2) {
if ((ChildType)(uintptr_t)m_Children.GetAt(i) == Element &&
(CXML_Element*)m_Children.GetAt(i + 1) == pChild) {
return (FX_DWORD)(i >> 1);
}
}
return (FX_DWORD)-1;
}
const CFX_WideString* CXML_AttrMap::Lookup(const CFX_ByteStringC& space,
const CFX_ByteStringC& name) const {
if (!m_pMap) {
return NULL;
}
for (int i = 0; i < m_pMap->GetSize(); i++) {
CXML_AttrItem& item = GetAt(i);
if ((space.IsEmpty() || item.m_QSpaceName == space) &&
item.m_AttrName == name) {
return &item.m_Value;
}
}
return NULL;
}
void CXML_AttrMap::SetAt(const CFX_ByteStringC& space,
const CFX_ByteStringC& name,
const CFX_WideStringC& value) {
for (int i = 0; i < GetSize(); i++) {
CXML_AttrItem& item = GetAt(i);
if ((space.IsEmpty() || item.m_QSpaceName == space) &&
item.m_AttrName == name) {
item.m_Value = value;
return;
}
}
if (!m_pMap) {
m_pMap = new CFX_ObjectArray<CXML_AttrItem>;
}
CXML_AttrItem* pItem = (CXML_AttrItem*)m_pMap->AddSpace();
if (!pItem) {
return;
}
pItem->m_QSpaceName = space;
pItem->m_AttrName = name;
pItem->m_Value = value;
}
void CXML_AttrMap::RemoveAt(const CFX_ByteStringC& space,
const CFX_ByteStringC& name) {
if (!m_pMap) {
return;
}
for (int i = 0; i < m_pMap->GetSize(); i++) {
CXML_AttrItem& item = GetAt(i);
if ((space.IsEmpty() || item.m_QSpaceName == space) &&
item.m_AttrName == name) {
m_pMap->RemoveAt(i);
return;
}
}
}
int CXML_AttrMap::GetSize() const {
return m_pMap ? m_pMap->GetSize() : 0;
}
CXML_AttrItem& CXML_AttrMap::GetAt(int index) const {
return (*m_pMap)[index];
}
void CXML_AttrMap::RemoveAll() {
if (!m_pMap) {
return;
}
m_pMap->RemoveAll();
delete m_pMap;
m_pMap = NULL;
}