808 lines
20 KiB
C++
808 lines
20 KiB
C++
/**
|
|
* @file llxmltree.cpp
|
|
* @brief LLXmlTree implementation
|
|
*
|
|
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2010, Linden Research, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License only.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "linden_common.h"
|
|
|
|
#include "llxmltree.h"
|
|
#include "v3color.h"
|
|
#include "v4color.h"
|
|
#include "v4coloru.h"
|
|
#include "v3math.h"
|
|
#include "v3dmath.h"
|
|
#include "v4math.h"
|
|
#include "llquaternion.h"
|
|
#include "lluuid.h"
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// LLXmlTree
|
|
|
|
// static
|
|
LLStdStringTable LLXmlTree::sAttributeKeys(1024);
|
|
|
|
LLXmlTree::LLXmlTree()
|
|
: mRoot( NULL ),
|
|
mParser(0),
|
|
mNodeNames(512)
|
|
{
|
|
}
|
|
|
|
LLXmlTree::~LLXmlTree()
|
|
{
|
|
cleanup();
|
|
}
|
|
|
|
void LLXmlTree::cleanup()
|
|
{
|
|
delete mRoot;
|
|
mRoot = NULL;
|
|
mNodeNames.cleanup();
|
|
}
|
|
|
|
|
|
BOOL LLXmlTree::parseFile(const std::string &path, BOOL keep_contents)
|
|
{
|
|
delete mRoot;
|
|
mRoot = NULL;
|
|
|
|
LLXmlTreeParser parser(this);
|
|
BOOL success = parser.parseFile( path, &mRoot, keep_contents );
|
|
if( !success )
|
|
{
|
|
S32 line_number = parser.getCurrentLineNumber();
|
|
const char* error = parser.getErrorString();
|
|
llwarns << "LLXmlTree parse failed. Line " << line_number << ": " << error << llendl;
|
|
}
|
|
return success;
|
|
}
|
|
|
|
bool LLXmlTree::parseBufferStart(bool keep_contents)
|
|
{
|
|
if (mRoot) delete mRoot;
|
|
mRoot = NULL;
|
|
|
|
if (mParser) delete mParser;
|
|
mParser = new LLXmlTreeParser(this);
|
|
mParser->parseBufferStart(keep_contents);
|
|
return (mParser != 0);
|
|
}
|
|
|
|
bool LLXmlTree::parseBuffer(const char *buf, int len)
|
|
{
|
|
bool success = mParser->parseBuffer(buf, len);
|
|
if (!success) {
|
|
S32 line_number = mParser->getCurrentLineNumber();
|
|
const char* error = mParser->getErrorString();
|
|
llwarns << "LLXmlTree parse failed in line " << line_number << ": " << error << llendl;
|
|
delete mParser;
|
|
mParser = 0;
|
|
}
|
|
return success;
|
|
}
|
|
|
|
bool LLXmlTree::parseBufferFinalize()
|
|
{
|
|
bool success = mParser->parseBufferFinalize(&mRoot);
|
|
delete mParser;
|
|
mParser = 0;
|
|
return success;
|
|
}
|
|
|
|
|
|
void LLXmlTree::dump()
|
|
{
|
|
if( mRoot )
|
|
{
|
|
dumpNode( mRoot, " " );
|
|
}
|
|
}
|
|
|
|
void LLXmlTree::dumpNode( LLXmlTreeNode* node, const std::string& prefix )
|
|
{
|
|
node->dump( prefix );
|
|
|
|
std::string new_prefix = prefix + " ";
|
|
for( LLXmlTreeNode* child = node->getFirstChild(); child; child = node->getNextChild() )
|
|
{
|
|
dumpNode( child, new_prefix );
|
|
}
|
|
}
|
|
|
|
void LLXmlTree::write(std::string &buffer) const
|
|
{
|
|
if (mRoot) writeNode(mRoot, buffer, "");
|
|
}
|
|
|
|
void LLXmlTree::writeNode(LLXmlTreeNode *node, std::string &buffer, const std::string &indent) const
|
|
{
|
|
if (!node->getFirstChild()) {
|
|
node->writeNoChild(buffer, indent);
|
|
} else {
|
|
node->writeStart(buffer, indent);
|
|
std::string newIndent = indent + " ";
|
|
for (LLXmlTreeNode *child=node->getFirstChild(); child; child=node->getNextChild())
|
|
writeNode(child, buffer, newIndent);
|
|
node->writeEnd(buffer, indent);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// LLXmlTreeNode
|
|
|
|
LLXmlTreeNode::LLXmlTreeNode( const std::string& name, LLXmlTreeNode* parent, LLXmlTree* tree )
|
|
: mName(name),
|
|
mParent(parent),
|
|
mTree(tree)
|
|
{
|
|
}
|
|
|
|
LLXmlTreeNode::~LLXmlTreeNode()
|
|
{
|
|
attribute_map_t::iterator iter;
|
|
for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
|
|
delete iter->second;
|
|
child_list_t::iterator child_iter;
|
|
for (child_iter=mChildList.begin(); child_iter != mChildList.end(); child_iter++)
|
|
delete *child_iter;
|
|
}
|
|
|
|
void LLXmlTreeNode::dump( const std::string& prefix )
|
|
{
|
|
llinfos << prefix << mName ;
|
|
if( !mContents.empty() )
|
|
{
|
|
llcont << " contents = \"" << mContents << "\"";
|
|
}
|
|
attribute_map_t::iterator iter;
|
|
for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
|
|
{
|
|
LLStdStringHandle key = iter->first;
|
|
const std::string* value = iter->second;
|
|
llcont << prefix << " " << key << "=" << (value->empty() ? "NULL" : *value);
|
|
}
|
|
llcont << llendl;
|
|
}
|
|
|
|
void LLXmlTreeNode::writeNoChild(std::string &buffer, const std::string &indent) const
|
|
{
|
|
if (!mContents.empty()) {
|
|
writeStart(buffer, indent);
|
|
writeEnd(buffer, indent);
|
|
} else {
|
|
buffer += indent + '<' + mName;
|
|
writeAttributes(buffer);
|
|
buffer += "/>\n";
|
|
}
|
|
}
|
|
|
|
void LLXmlTreeNode::writeStart(std::string &buffer, const std::string &indent) const
|
|
{
|
|
buffer += indent + '<' + mName;
|
|
writeAttributes(buffer);
|
|
buffer += ">\n";
|
|
}
|
|
|
|
void LLXmlTreeNode::writeEnd(std::string &buffer, const std::string &indent) const
|
|
{
|
|
if (!mContents.empty()) {
|
|
buffer += indent + " " + mContents + '\n';
|
|
}
|
|
buffer += indent + "</" + mName + ">\n";
|
|
}
|
|
|
|
void LLXmlTreeNode::writeAttributes(std::string &buffer) const
|
|
{
|
|
attribute_map_t::const_iterator it, end = mAttributes.end();
|
|
for (it=mAttributes.begin(); it!=end; ++it) {
|
|
LLStdStringHandle key = it->first;
|
|
const std::string *value = it->second;
|
|
buffer += ' ' + *key + "=\"" + *value + '"';
|
|
}
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::hasAttribute(const std::string& name)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
attribute_map_t::iterator iter = mAttributes.find(canonical_name);
|
|
return (iter == mAttributes.end()) ? false : true;
|
|
}
|
|
|
|
void LLXmlTreeNode::addAttribute(const std::string& name, const std::string& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
const std::string *newstr = new std::string(value);
|
|
mAttributes[canonical_name] = newstr; // insert + copy
|
|
}
|
|
|
|
LLXmlTreeNode* LLXmlTreeNode::getFirstChild()
|
|
{
|
|
mChildListIter = mChildList.begin();
|
|
return getNextChild();
|
|
}
|
|
LLXmlTreeNode* LLXmlTreeNode::getNextChild()
|
|
{
|
|
if (mChildListIter == mChildList.end())
|
|
return 0;
|
|
else
|
|
return *mChildListIter++;
|
|
}
|
|
|
|
LLXmlTreeNode* LLXmlTreeNode::getChildByName(const std::string& name)
|
|
{
|
|
LLStdStringHandle tableptr = mTree->mNodeNames.checkString(name);
|
|
mChildMapIter = mChildMap.lower_bound(tableptr);
|
|
mChildMapEndIter = mChildMap.upper_bound(tableptr);
|
|
return getNextNamedChild();
|
|
}
|
|
|
|
LLXmlTreeNode* LLXmlTreeNode::getNextNamedChild()
|
|
{
|
|
if (mChildMapIter == mChildMapEndIter)
|
|
return NULL;
|
|
else
|
|
return (mChildMapIter++)->second;
|
|
}
|
|
|
|
void LLXmlTreeNode::appendContents(const std::string& str)
|
|
{
|
|
mContents.append( str );
|
|
}
|
|
|
|
void LLXmlTreeNode::addChild(LLXmlTreeNode* child)
|
|
{
|
|
llassert( child );
|
|
mChildList.push_back( child );
|
|
|
|
// Add a name mapping to this node
|
|
LLStdStringHandle tableptr = mTree->mNodeNames.insert(child->mName);
|
|
mChildMap.insert( child_map_t::value_type(tableptr, child));
|
|
|
|
child->mParent = this;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
// These functions assume that name is already in mAttritrubteKeys
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeBOOL(LLStdStringHandle canonical_name, BOOL& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s && LLStringUtil::convertToBOOL( *s, value );
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeU8(LLStdStringHandle canonical_name, U8& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s && LLStringUtil::convertToU8( *s, value );
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeS8(LLStdStringHandle canonical_name, S8& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s && LLStringUtil::convertToS8( *s, value );
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeS16(LLStdStringHandle canonical_name, S16& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s && LLStringUtil::convertToS16( *s, value );
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeU16(LLStdStringHandle canonical_name, U16& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s && LLStringUtil::convertToU16( *s, value );
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeU32(LLStdStringHandle canonical_name, U32& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s && LLStringUtil::convertToU32( *s, value );
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeS32(LLStdStringHandle canonical_name, S32& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s && LLStringUtil::convertToS32( *s, value );
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeF32(LLStdStringHandle canonical_name, F32& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s && LLStringUtil::convertToF32( *s, value );
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeF64(LLStdStringHandle canonical_name, F64& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s && LLStringUtil::convertToF64( *s, value );
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeColor(LLStdStringHandle canonical_name, LLColor4& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s ? LLColor4::parseColor(*s, &value) : FALSE;
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeColor4(LLStdStringHandle canonical_name, LLColor4& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s ? LLColor4::parseColor4(*s, &value) : FALSE;
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeColor4U(LLStdStringHandle canonical_name, LLColor4U& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s ? LLColor4U::parseColor4U(*s, &value ) : FALSE;
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeVector3(LLStdStringHandle canonical_name, LLVector3& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s ? LLVector3::parseVector3(*s, &value ) : FALSE;
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeVector3d(LLStdStringHandle canonical_name, LLVector3d& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s ? LLVector3d::parseVector3d(*s, &value ) : FALSE;
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeQuat(LLStdStringHandle canonical_name, LLQuaternion& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s ? LLQuaternion::parseQuat(*s, &value ) : FALSE;
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeUUID(LLStdStringHandle canonical_name, LLUUID& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
return s ? LLUUID::parseUUID(*s, &value ) : FALSE;
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getFastAttributeString(LLStdStringHandle canonical_name, std::string& value)
|
|
{
|
|
const std::string *s = getAttribute( canonical_name );
|
|
if( !s )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
value = *s;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
BOOL LLXmlTreeNode::getAttributeBOOL(const std::string& name, BOOL& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeBOOL(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeU8(const std::string& name, U8& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeU8(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeS8(const std::string& name, S8& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeS8(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeS16(const std::string& name, S16& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeS16(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeU16(const std::string& name, U16& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeU16(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeU32(const std::string& name, U32& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeU32(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeS32(const std::string& name, S32& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeS32(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeF32(const std::string& name, F32& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeF32(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeF64(const std::string& name, F64& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeF64(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeColor(const std::string& name, LLColor4& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeColor(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeColor4(const std::string& name, LLColor4& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeColor4(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeColor4U(const std::string& name, LLColor4U& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeColor4U(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeVector3(const std::string& name, LLVector3& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeVector3(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeVector3d(const std::string& name, LLVector3d& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeVector3d(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeQuat(const std::string& name, LLQuaternion& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeQuat(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeUUID(const std::string& name, LLUUID& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeUUID(canonical_name, value);
|
|
}
|
|
|
|
BOOL LLXmlTreeNode::getAttributeString(const std::string& name, std::string& value)
|
|
{
|
|
LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
|
|
return getFastAttributeString(canonical_name, value);
|
|
}
|
|
|
|
/*
|
|
The following xml <message> nodes will all return the string from getTextContents():
|
|
"The quick brown fox\n Jumps over the lazy dog"
|
|
|
|
1. HTML paragraph format:
|
|
<message>
|
|
<p>The quick brown fox</p>
|
|
<p> Jumps over the lazy dog</p>
|
|
</message>
|
|
2. Each quoted section -> paragraph:
|
|
<message>
|
|
"The quick brown fox"
|
|
" Jumps over the lazy dog"
|
|
</message>
|
|
3. Literal text with beginning and trailing whitespace removed:
|
|
<message>
|
|
The quick brown fox
|
|
Jumps over the lazy dog
|
|
</message>
|
|
|
|
*/
|
|
|
|
std::string LLXmlTreeNode::getTextContents()
|
|
{
|
|
std::string msg;
|
|
LLXmlTreeNode* p = getChildByName("p");
|
|
if (p)
|
|
{
|
|
// Case 1: node has <p>text</p> tags
|
|
while (p)
|
|
{
|
|
msg += p->getContents() + "\n";
|
|
p = getNextNamedChild();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::string::size_type n = mContents.find_first_not_of(" \t\n");
|
|
if (n != std::string::npos && mContents[n] == '\"')
|
|
{
|
|
// Case 2: node has quoted text
|
|
S32 num_lines = 0;
|
|
while(1)
|
|
{
|
|
// mContents[n] == '"'
|
|
++n;
|
|
std::string::size_type t = n;
|
|
std::string::size_type m = 0;
|
|
// fix-up escaped characters
|
|
while(1)
|
|
{
|
|
m = mContents.find_first_of("\\\"", t); // find first \ or "
|
|
if ((m == std::string::npos) || (mContents[m] == '\"'))
|
|
{
|
|
break;
|
|
}
|
|
mContents.erase(m,1);
|
|
t = m+1;
|
|
}
|
|
if (m == std::string::npos)
|
|
{
|
|
break;
|
|
}
|
|
// mContents[m] == '"'
|
|
num_lines++;
|
|
msg += mContents.substr(n,m-n) + "\n";
|
|
n = mContents.find_first_of("\"", m+1);
|
|
if (n == std::string::npos)
|
|
{
|
|
if (num_lines == 1)
|
|
{
|
|
msg.erase(msg.size()-1); // remove "\n" if only one line
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Case 3: node has embedded text (beginning and trailing whitespace trimmed)
|
|
msg = mContents;
|
|
}
|
|
}
|
|
return msg;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// LLXmlTreeParser
|
|
|
|
LLXmlTreeParser::LLXmlTreeParser(LLXmlTree* tree)
|
|
: mTree(tree),
|
|
mRoot( NULL ),
|
|
mCurrent( NULL ),
|
|
mDump( FALSE ),
|
|
mKeepContents(FALSE)
|
|
{
|
|
}
|
|
|
|
LLXmlTreeParser::~LLXmlTreeParser()
|
|
{
|
|
}
|
|
|
|
BOOL LLXmlTreeParser::parseFile(const std::string &path, LLXmlTreeNode** root, BOOL keep_contents)
|
|
{
|
|
llassert( !mRoot );
|
|
llassert( !mCurrent );
|
|
|
|
mKeepContents = keep_contents;
|
|
|
|
BOOL success = LLXmlParser::parseFile(path);
|
|
|
|
if (root) *root = mRoot;
|
|
mRoot = NULL;
|
|
|
|
if( success )
|
|
{
|
|
llassert( !mCurrent );
|
|
}
|
|
mCurrent = NULL;
|
|
|
|
return success;
|
|
}
|
|
|
|
void LLXmlTreeParser::parseBufferStart(BOOL keep_contents)
|
|
{
|
|
llassert(!mRoot);
|
|
llassert(!mCurrent);
|
|
mKeepContents = keep_contents;
|
|
}
|
|
|
|
bool LLXmlTreeParser::parseBuffer(const char *buf, int len)
|
|
{
|
|
return (LLXmlParser::parse(buf, len, false) != 0);
|
|
}
|
|
|
|
bool LLXmlTreeParser::parseBufferFinalize(LLXmlTreeNode** root)
|
|
{
|
|
bool success = (LLXmlParser::parse(0, 0, true) != 0);
|
|
|
|
if (root) *root = mRoot;
|
|
mRoot = NULL;
|
|
|
|
llassert(!success || !mCurrent);
|
|
mCurrent = NULL;
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
const std::string& LLXmlTreeParser::tabs()
|
|
{
|
|
static std::string s;
|
|
s = "";
|
|
S32 num_tabs = getDepth() - 1;
|
|
for( S32 i = 0; i < num_tabs; i++)
|
|
{
|
|
s += " ";
|
|
}
|
|
return s;
|
|
}
|
|
|
|
void LLXmlTreeParser::startElement(const char* name, const char **atts)
|
|
{
|
|
if( mDump )
|
|
{
|
|
llinfos << tabs() << "startElement " << name << llendl;
|
|
|
|
S32 i = 0;
|
|
while( atts[i] && atts[i+1] )
|
|
{
|
|
llinfos << tabs() << "attribute: " << atts[i] << "=" << atts[i+1] << llendl;
|
|
i += 2;
|
|
}
|
|
}
|
|
|
|
LLXmlTreeNode* child = CreateXmlTreeNode( std::string(name), mCurrent );
|
|
|
|
S32 i = 0;
|
|
while( atts[i] && atts[i+1] )
|
|
{
|
|
child->addAttribute( atts[i], atts[i+1] );
|
|
i += 2;
|
|
}
|
|
|
|
if( mCurrent )
|
|
{
|
|
mCurrent->addChild( child );
|
|
|
|
}
|
|
else
|
|
{
|
|
llassert( !mRoot );
|
|
mRoot = child;
|
|
}
|
|
mCurrent = child;
|
|
}
|
|
|
|
LLXmlTreeNode* LLXmlTreeParser::CreateXmlTreeNode(const std::string& name, LLXmlTreeNode* parent)
|
|
{
|
|
return new LLXmlTreeNode(name, parent, mTree);
|
|
}
|
|
|
|
|
|
void LLXmlTreeParser::endElement(const char* name)
|
|
{
|
|
if( mDump )
|
|
{
|
|
llinfos << tabs() << "endElement " << name << llendl;
|
|
}
|
|
|
|
if( !mCurrent->mContents.empty() )
|
|
{
|
|
LLStringUtil::trim(mCurrent->mContents);
|
|
LLStringUtil::removeCRLF(mCurrent->mContents);
|
|
}
|
|
|
|
mCurrent = mCurrent->getParent();
|
|
}
|
|
|
|
void LLXmlTreeParser::characterData(const char *s, int len)
|
|
{
|
|
std::string str;
|
|
if (s) str = std::string(s, len);
|
|
if( mDump )
|
|
{
|
|
llinfos << tabs() << "CharacterData " << str << llendl;
|
|
}
|
|
|
|
if (mKeepContents)
|
|
{
|
|
mCurrent->appendContents( str );
|
|
}
|
|
}
|
|
|
|
void LLXmlTreeParser::processingInstruction(const char *target, const char *data)
|
|
{
|
|
if( mDump )
|
|
{
|
|
llinfos << tabs() << "processingInstruction " << data << llendl;
|
|
}
|
|
}
|
|
|
|
void LLXmlTreeParser::comment(const char *data)
|
|
{
|
|
if( mDump )
|
|
{
|
|
llinfos << tabs() << "comment " << data << llendl;
|
|
}
|
|
}
|
|
|
|
void LLXmlTreeParser::startCdataSection()
|
|
{
|
|
if( mDump )
|
|
{
|
|
llinfos << tabs() << "startCdataSection" << llendl;
|
|
}
|
|
}
|
|
|
|
void LLXmlTreeParser::endCdataSection()
|
|
{
|
|
if( mDump )
|
|
{
|
|
llinfos << tabs() << "endCdataSection" << llendl;
|
|
}
|
|
}
|
|
|
|
void LLXmlTreeParser::defaultData(const char *s, int len)
|
|
{
|
|
if( mDump )
|
|
{
|
|
std::string str;
|
|
if (s) str = std::string(s, len);
|
|
llinfos << tabs() << "defaultData " << str << llendl;
|
|
}
|
|
}
|
|
|
|
void LLXmlTreeParser::unparsedEntityDecl(
|
|
const char* entity_name,
|
|
const char* base,
|
|
const char* system_id,
|
|
const char* public_id,
|
|
const char* notation_name)
|
|
{
|
|
if( mDump )
|
|
{
|
|
llinfos << tabs() << "unparsed entity:" << llendl;
|
|
llinfos << tabs() << " entityName " << entity_name << llendl;
|
|
llinfos << tabs() << " base " << base << llendl;
|
|
llinfos << tabs() << " systemId " << system_id << llendl;
|
|
llinfos << tabs() << " publicId " << public_id << llendl;
|
|
llinfos << tabs() << " notationName " << notation_name<< llendl;
|
|
}
|
|
}
|
|
|
|
void test_llxmltree()
|
|
{
|
|
LLXmlTree tree;
|
|
BOOL success = tree.parseFile( "test.xml" );
|
|
if( success )
|
|
{
|
|
tree.dump();
|
|
}
|
|
}
|
|
|