diff options
Diffstat (limited to 'indra/llxml/llxmltree.cpp')
-rw-r--r-- | indra/llxml/llxmltree.cpp | 671 |
1 files changed, 671 insertions, 0 deletions
diff --git a/indra/llxml/llxmltree.cpp b/indra/llxml/llxmltree.cpp new file mode 100644 index 0000000000..3d0d1ba379 --- /dev/null +++ b/indra/llxml/llxmltree.cpp @@ -0,0 +1,671 @@ +/** + * @file llxmltree.cpp + * @brief LLXmlTree implementation + * + * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#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 ), + 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; +} + +void LLXmlTree::dump() +{ + if( mRoot ) + { + dumpNode( mRoot, " " ); + } +} + +void LLXmlTree::dumpNode( LLXmlTreeNode* node, const LLString& prefix ) +{ + node->dump( prefix ); + + LLString new_prefix = prefix + " "; + for( LLXmlTreeNode* child = node->getFirstChild(); child; child = node->getNextChild() ) + { + dumpNode( child, new_prefix ); + } +} + +////////////////////////////////////////////////////////////// +// 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 LLString& 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 LLString* value = iter->second; + llcont << prefix << " " << key << "=" << (value->empty() ? "NULL" : *value); + } + llcont << llendl; +} + +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 LLString *newstr = new LLString(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 LLString *s = getAttribute( canonical_name ); + return s && LLString::convertToBOOL( *s, value ); +} + +BOOL LLXmlTreeNode::getFastAttributeU8(LLStdStringHandle canonical_name, U8& value) +{ + const LLString *s = getAttribute( canonical_name ); + return s && LLString::convertToU8( *s, value ); +} + +BOOL LLXmlTreeNode::getFastAttributeS8(LLStdStringHandle canonical_name, S8& value) +{ + const LLString *s = getAttribute( canonical_name ); + return s && LLString::convertToS8( *s, value ); +} + +BOOL LLXmlTreeNode::getFastAttributeS16(LLStdStringHandle canonical_name, S16& value) +{ + const LLString *s = getAttribute( canonical_name ); + return s && LLString::convertToS16( *s, value ); +} + +BOOL LLXmlTreeNode::getFastAttributeU16(LLStdStringHandle canonical_name, U16& value) +{ + const LLString *s = getAttribute( canonical_name ); + return s && LLString::convertToU16( *s, value ); +} + +BOOL LLXmlTreeNode::getFastAttributeU32(LLStdStringHandle canonical_name, U32& value) +{ + const LLString *s = getAttribute( canonical_name ); + return s && LLString::convertToU32( *s, value ); +} + +BOOL LLXmlTreeNode::getFastAttributeS32(LLStdStringHandle canonical_name, S32& value) +{ + const LLString *s = getAttribute( canonical_name ); + return s && LLString::convertToS32( *s, value ); +} + +BOOL LLXmlTreeNode::getFastAttributeF32(LLStdStringHandle canonical_name, F32& value) +{ + const LLString *s = getAttribute( canonical_name ); + return s && LLString::convertToF32( *s, value ); +} + +BOOL LLXmlTreeNode::getFastAttributeF64(LLStdStringHandle canonical_name, F64& value) +{ + const LLString *s = getAttribute( canonical_name ); + return s && LLString::convertToF64( *s, value ); +} + +BOOL LLXmlTreeNode::getFastAttributeColor(LLStdStringHandle canonical_name, LLColor4& value) +{ + const LLString *s = getAttribute( canonical_name ); + return s ? LLColor4::parseColor(s->c_str(), &value) : FALSE; +} + +BOOL LLXmlTreeNode::getFastAttributeColor4(LLStdStringHandle canonical_name, LLColor4& value) +{ + const LLString *s = getAttribute( canonical_name ); + return s ? LLColor4::parseColor4(s->c_str(), &value) : FALSE; +} + +BOOL LLXmlTreeNode::getFastAttributeColor4U(LLStdStringHandle canonical_name, LLColor4U& value) +{ + const LLString *s = getAttribute( canonical_name ); + return s ? LLColor4U::parseColor4U(s->c_str(), &value ) : FALSE; +} + +BOOL LLXmlTreeNode::getFastAttributeVector3(LLStdStringHandle canonical_name, LLVector3& value) +{ + const LLString *s = getAttribute( canonical_name ); + return s ? LLVector3::parseVector3(s->c_str(), &value ) : FALSE; +} + +BOOL LLXmlTreeNode::getFastAttributeVector3d(LLStdStringHandle canonical_name, LLVector3d& value) +{ + const LLString *s = getAttribute( canonical_name ); + return s ? LLVector3d::parseVector3d(s->c_str(), &value ) : FALSE; +} + +BOOL LLXmlTreeNode::getFastAttributeQuat(LLStdStringHandle canonical_name, LLQuaternion& value) +{ + const LLString *s = getAttribute( canonical_name ); + return s ? LLQuaternion::parseQuat(s->c_str(), &value ) : FALSE; +} + +BOOL LLXmlTreeNode::getFastAttributeUUID(LLStdStringHandle canonical_name, LLUUID& value) +{ + const LLString *s = getAttribute( canonical_name ); + return s ? LLUUID::parseUUID(s->c_str(), &value ) : FALSE; +} + +BOOL LLXmlTreeNode::getFastAttributeString(LLStdStringHandle canonical_name, LLString& value) +{ + const LLString *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, LLString& 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> + +*/ + +LLString 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 ) +{ +} + +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); + + *root = mRoot; + mRoot = NULL; + + if( success ) + { + llassert( !mCurrent ); + } + mCurrent = NULL; + + return success; +} + + +const std::string& LLXmlTreeParser::tabs() +{ + static LLString 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() ) + { + LLString::trim(mCurrent->mContents); + LLString::removeCRLF(mCurrent->mContents); + } + + mCurrent = mCurrent->getParent(); +} + +void LLXmlTreeParser::characterData(const char *s, int len) +{ + LLString str(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 ) + { + LLString str(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(); + } +} + |