Files
SingularityViewer/indra/llxml/llxmltree.cpp
Siana Gearz 179f4ddabb The Octopus Feature
___
                     .-'   `'.
                    /         \
                    |         ;
                    |         |           ___.--,
           _.._     |0) ~ (0) |    _.---'`__.-( (_.
    __.--'`_.. '.__.\    '--. \_.-' ,.--'`     `""`
   ( ,.--'`   ',__ /./;   ;, '.__.'`    __
   _`) )  .---.__.' / |   |\   \__..--""  """--.,_
  `---' .'.''-._.-'`_./  /\ '.  \ _.-~~~````~~~-._`-.__.'
        | |  .' _.-' |  |  \  \  '.               `~---`
         \ \/ .'     \  \   '. '-._)
          \/ /        \  \    `=.__`~-.
     jgs  / /\         `) )    / / `"".`\
    , _.-'.'\ \        / /    ( (     / /
     `--~`   ) )    .-'.'      '.'.  | (
            (/`    ( (`          ) )  '-;
             `      '-;         (-'
2011-03-24 23:54:23 +01:00

814 lines
20 KiB
C++

/**
* @file llxmltree.cpp
* @brief LLXmlTree implementation
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/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();
}
}