00001
00032 #include "linden_common.h"
00033
00034 #include "llxmltree.h"
00035 #include "v3color.h"
00036 #include "v4color.h"
00037 #include "v4coloru.h"
00038 #include "v3math.h"
00039 #include "v3dmath.h"
00040 #include "v4math.h"
00041 #include "llquaternion.h"
00042 #include "lluuid.h"
00043
00045
00046
00047
00048 LLStdStringTable LLXmlTree::sAttributeKeys(1024);
00049
00050 LLXmlTree::LLXmlTree()
00051 : mRoot( NULL ),
00052 mNodeNames(512)
00053 {
00054 }
00055
00056 LLXmlTree::~LLXmlTree()
00057 {
00058 cleanup();
00059 }
00060
00061 void LLXmlTree::cleanup()
00062 {
00063 delete mRoot;
00064 mRoot = NULL;
00065 mNodeNames.cleanup();
00066 }
00067
00068
00069 BOOL LLXmlTree::parseFile(const std::string &path, BOOL keep_contents)
00070 {
00071 delete mRoot;
00072 mRoot = NULL;
00073
00074 LLXmlTreeParser parser(this);
00075 BOOL success = parser.parseFile( path, &mRoot, keep_contents );
00076 if( !success )
00077 {
00078 S32 line_number = parser.getCurrentLineNumber();
00079 const char* error = parser.getErrorString();
00080 llwarns << "LLXmlTree parse failed. Line " << line_number << ": " << error << llendl;
00081 }
00082 return success;
00083 }
00084
00085 void LLXmlTree::dump()
00086 {
00087 if( mRoot )
00088 {
00089 dumpNode( mRoot, " " );
00090 }
00091 }
00092
00093 void LLXmlTree::dumpNode( LLXmlTreeNode* node, const LLString& prefix )
00094 {
00095 node->dump( prefix );
00096
00097 LLString new_prefix = prefix + " ";
00098 for( LLXmlTreeNode* child = node->getFirstChild(); child; child = node->getNextChild() )
00099 {
00100 dumpNode( child, new_prefix );
00101 }
00102 }
00103
00105
00106
00107 LLXmlTreeNode::LLXmlTreeNode( const std::string& name, LLXmlTreeNode* parent, LLXmlTree* tree )
00108 : mName(name),
00109 mParent(parent),
00110 mTree(tree)
00111 {
00112 }
00113
00114 LLXmlTreeNode::~LLXmlTreeNode()
00115 {
00116 attribute_map_t::iterator iter;
00117 for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
00118 delete iter->second;
00119 child_list_t::iterator child_iter;
00120 for (child_iter=mChildList.begin(); child_iter != mChildList.end(); child_iter++)
00121 delete *child_iter;
00122 }
00123
00124 void LLXmlTreeNode::dump( const LLString& prefix )
00125 {
00126 llinfos << prefix << mName ;
00127 if( !mContents.empty() )
00128 {
00129 llcont << " contents = \"" << mContents << "\"";
00130 }
00131 attribute_map_t::iterator iter;
00132 for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
00133 {
00134 LLStdStringHandle key = iter->first;
00135 const LLString* value = iter->second;
00136 llcont << prefix << " " << key << "=" << (value->empty() ? "NULL" : *value);
00137 }
00138 llcont << llendl;
00139 }
00140
00141 BOOL LLXmlTreeNode::hasAttribute(const std::string& name)
00142 {
00143 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00144 attribute_map_t::iterator iter = mAttributes.find(canonical_name);
00145 return (iter == mAttributes.end()) ? false : true;
00146 }
00147
00148 void LLXmlTreeNode::addAttribute(const std::string& name, const std::string& value)
00149 {
00150 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00151 const LLString *newstr = new LLString(value);
00152 mAttributes[canonical_name] = newstr;
00153 }
00154
00155 LLXmlTreeNode* LLXmlTreeNode::getFirstChild()
00156 {
00157 mChildListIter = mChildList.begin();
00158 return getNextChild();
00159 }
00160 LLXmlTreeNode* LLXmlTreeNode::getNextChild()
00161 {
00162 if (mChildListIter == mChildList.end())
00163 return 0;
00164 else
00165 return *mChildListIter++;
00166 }
00167
00168 LLXmlTreeNode* LLXmlTreeNode::getChildByName(const std::string& name)
00169 {
00170 LLStdStringHandle tableptr = mTree->mNodeNames.checkString(name);
00171 mChildMapIter = mChildMap.lower_bound(tableptr);
00172 mChildMapEndIter = mChildMap.upper_bound(tableptr);
00173 return getNextNamedChild();
00174 }
00175
00176 LLXmlTreeNode* LLXmlTreeNode::getNextNamedChild()
00177 {
00178 if (mChildMapIter == mChildMapEndIter)
00179 return NULL;
00180 else
00181 return (mChildMapIter++)->second;
00182 }
00183
00184 void LLXmlTreeNode::appendContents(const std::string& str)
00185 {
00186 mContents.append( str );
00187 }
00188
00189 void LLXmlTreeNode::addChild(LLXmlTreeNode* child)
00190 {
00191 llassert( child );
00192 mChildList.push_back( child );
00193
00194
00195 LLStdStringHandle tableptr = mTree->mNodeNames.insert(child->mName);
00196 mChildMap.insert( child_map_t::value_type(tableptr, child));
00197
00198 child->mParent = this;
00199 }
00200
00202
00203
00204
00205 BOOL LLXmlTreeNode::getFastAttributeBOOL(LLStdStringHandle canonical_name, BOOL& value)
00206 {
00207 const LLString *s = getAttribute( canonical_name );
00208 return s && LLString::convertToBOOL( *s, value );
00209 }
00210
00211 BOOL LLXmlTreeNode::getFastAttributeU8(LLStdStringHandle canonical_name, U8& value)
00212 {
00213 const LLString *s = getAttribute( canonical_name );
00214 return s && LLString::convertToU8( *s, value );
00215 }
00216
00217 BOOL LLXmlTreeNode::getFastAttributeS8(LLStdStringHandle canonical_name, S8& value)
00218 {
00219 const LLString *s = getAttribute( canonical_name );
00220 return s && LLString::convertToS8( *s, value );
00221 }
00222
00223 BOOL LLXmlTreeNode::getFastAttributeS16(LLStdStringHandle canonical_name, S16& value)
00224 {
00225 const LLString *s = getAttribute( canonical_name );
00226 return s && LLString::convertToS16( *s, value );
00227 }
00228
00229 BOOL LLXmlTreeNode::getFastAttributeU16(LLStdStringHandle canonical_name, U16& value)
00230 {
00231 const LLString *s = getAttribute( canonical_name );
00232 return s && LLString::convertToU16( *s, value );
00233 }
00234
00235 BOOL LLXmlTreeNode::getFastAttributeU32(LLStdStringHandle canonical_name, U32& value)
00236 {
00237 const LLString *s = getAttribute( canonical_name );
00238 return s && LLString::convertToU32( *s, value );
00239 }
00240
00241 BOOL LLXmlTreeNode::getFastAttributeS32(LLStdStringHandle canonical_name, S32& value)
00242 {
00243 const LLString *s = getAttribute( canonical_name );
00244 return s && LLString::convertToS32( *s, value );
00245 }
00246
00247 BOOL LLXmlTreeNode::getFastAttributeF32(LLStdStringHandle canonical_name, F32& value)
00248 {
00249 const LLString *s = getAttribute( canonical_name );
00250 return s && LLString::convertToF32( *s, value );
00251 }
00252
00253 BOOL LLXmlTreeNode::getFastAttributeF64(LLStdStringHandle canonical_name, F64& value)
00254 {
00255 const LLString *s = getAttribute( canonical_name );
00256 return s && LLString::convertToF64( *s, value );
00257 }
00258
00259 BOOL LLXmlTreeNode::getFastAttributeColor(LLStdStringHandle canonical_name, LLColor4& value)
00260 {
00261 const LLString *s = getAttribute( canonical_name );
00262 return s ? LLColor4::parseColor(s->c_str(), &value) : FALSE;
00263 }
00264
00265 BOOL LLXmlTreeNode::getFastAttributeColor4(LLStdStringHandle canonical_name, LLColor4& value)
00266 {
00267 const LLString *s = getAttribute( canonical_name );
00268 return s ? LLColor4::parseColor4(s->c_str(), &value) : FALSE;
00269 }
00270
00271 BOOL LLXmlTreeNode::getFastAttributeColor4U(LLStdStringHandle canonical_name, LLColor4U& value)
00272 {
00273 const LLString *s = getAttribute( canonical_name );
00274 return s ? LLColor4U::parseColor4U(s->c_str(), &value ) : FALSE;
00275 }
00276
00277 BOOL LLXmlTreeNode::getFastAttributeVector3(LLStdStringHandle canonical_name, LLVector3& value)
00278 {
00279 const LLString *s = getAttribute( canonical_name );
00280 return s ? LLVector3::parseVector3(s->c_str(), &value ) : FALSE;
00281 }
00282
00283 BOOL LLXmlTreeNode::getFastAttributeVector3d(LLStdStringHandle canonical_name, LLVector3d& value)
00284 {
00285 const LLString *s = getAttribute( canonical_name );
00286 return s ? LLVector3d::parseVector3d(s->c_str(), &value ) : FALSE;
00287 }
00288
00289 BOOL LLXmlTreeNode::getFastAttributeQuat(LLStdStringHandle canonical_name, LLQuaternion& value)
00290 {
00291 const LLString *s = getAttribute( canonical_name );
00292 return s ? LLQuaternion::parseQuat(s->c_str(), &value ) : FALSE;
00293 }
00294
00295 BOOL LLXmlTreeNode::getFastAttributeUUID(LLStdStringHandle canonical_name, LLUUID& value)
00296 {
00297 const LLString *s = getAttribute( canonical_name );
00298 return s ? LLUUID::parseUUID(s->c_str(), &value ) : FALSE;
00299 }
00300
00301 BOOL LLXmlTreeNode::getFastAttributeString(LLStdStringHandle canonical_name, LLString& value)
00302 {
00303 const LLString *s = getAttribute( canonical_name );
00304 if( !s )
00305 {
00306 return FALSE;
00307 }
00308
00309 value = *s;
00310 return TRUE;
00311 }
00312
00313
00315
00316 BOOL LLXmlTreeNode::getAttributeBOOL(const std::string& name, BOOL& value)
00317 {
00318 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00319 return getFastAttributeBOOL(canonical_name, value);
00320 }
00321
00322 BOOL LLXmlTreeNode::getAttributeU8(const std::string& name, U8& value)
00323 {
00324 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00325 return getFastAttributeU8(canonical_name, value);
00326 }
00327
00328 BOOL LLXmlTreeNode::getAttributeS8(const std::string& name, S8& value)
00329 {
00330 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00331 return getFastAttributeS8(canonical_name, value);
00332 }
00333
00334 BOOL LLXmlTreeNode::getAttributeS16(const std::string& name, S16& value)
00335 {
00336 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00337 return getFastAttributeS16(canonical_name, value);
00338 }
00339
00340 BOOL LLXmlTreeNode::getAttributeU16(const std::string& name, U16& value)
00341 {
00342 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00343 return getFastAttributeU16(canonical_name, value);
00344 }
00345
00346 BOOL LLXmlTreeNode::getAttributeU32(const std::string& name, U32& value)
00347 {
00348 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00349 return getFastAttributeU32(canonical_name, value);
00350 }
00351
00352 BOOL LLXmlTreeNode::getAttributeS32(const std::string& name, S32& value)
00353 {
00354 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00355 return getFastAttributeS32(canonical_name, value);
00356 }
00357
00358 BOOL LLXmlTreeNode::getAttributeF32(const std::string& name, F32& value)
00359 {
00360 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00361 return getFastAttributeF32(canonical_name, value);
00362 }
00363
00364 BOOL LLXmlTreeNode::getAttributeF64(const std::string& name, F64& value)
00365 {
00366 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00367 return getFastAttributeF64(canonical_name, value);
00368 }
00369
00370 BOOL LLXmlTreeNode::getAttributeColor(const std::string& name, LLColor4& value)
00371 {
00372 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00373 return getFastAttributeColor(canonical_name, value);
00374 }
00375
00376 BOOL LLXmlTreeNode::getAttributeColor4(const std::string& name, LLColor4& value)
00377 {
00378 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00379 return getFastAttributeColor4(canonical_name, value);
00380 }
00381
00382 BOOL LLXmlTreeNode::getAttributeColor4U(const std::string& name, LLColor4U& value)
00383 {
00384 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00385 return getFastAttributeColor4U(canonical_name, value);
00386 }
00387
00388 BOOL LLXmlTreeNode::getAttributeVector3(const std::string& name, LLVector3& value)
00389 {
00390 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00391 return getFastAttributeVector3(canonical_name, value);
00392 }
00393
00394 BOOL LLXmlTreeNode::getAttributeVector3d(const std::string& name, LLVector3d& value)
00395 {
00396 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00397 return getFastAttributeVector3d(canonical_name, value);
00398 }
00399
00400 BOOL LLXmlTreeNode::getAttributeQuat(const std::string& name, LLQuaternion& value)
00401 {
00402 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00403 return getFastAttributeQuat(canonical_name, value);
00404 }
00405
00406 BOOL LLXmlTreeNode::getAttributeUUID(const std::string& name, LLUUID& value)
00407 {
00408 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00409 return getFastAttributeUUID(canonical_name, value);
00410 }
00411
00412 BOOL LLXmlTreeNode::getAttributeString(const std::string& name, LLString& value)
00413 {
00414 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00415 return getFastAttributeString(canonical_name, value);
00416 }
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440 LLString LLXmlTreeNode::getTextContents()
00441 {
00442 std::string msg;
00443 LLXmlTreeNode* p = getChildByName("p");
00444 if (p)
00445 {
00446
00447 while (p)
00448 {
00449 msg += p->getContents() + "\n";
00450 p = getNextNamedChild();
00451 }
00452 }
00453 else
00454 {
00455 std::string::size_type n = mContents.find_first_not_of(" \t\n");
00456 if (n != std::string::npos && mContents[n] == '\"')
00457 {
00458
00459 S32 num_lines = 0;
00460 while(1)
00461 {
00462
00463 ++n;
00464 std::string::size_type t = n;
00465 std::string::size_type m = 0;
00466
00467 while(1)
00468 {
00469 m = mContents.find_first_of("\\\"", t);
00470 if ((m == std::string::npos) || (mContents[m] == '\"'))
00471 {
00472 break;
00473 }
00474 mContents.erase(m,1);
00475 t = m+1;
00476 }
00477 if (m == std::string::npos)
00478 {
00479 break;
00480 }
00481
00482 num_lines++;
00483 msg += mContents.substr(n,m-n) + "\n";
00484 n = mContents.find_first_of("\"", m+1);
00485 if (n == std::string::npos)
00486 {
00487 if (num_lines == 1)
00488 {
00489 msg.erase(msg.size()-1);
00490 }
00491 break;
00492 }
00493 }
00494 }
00495 else
00496 {
00497
00498 msg = mContents;
00499 }
00500 }
00501 return msg;
00502 }
00503
00504
00506
00507
00508 LLXmlTreeParser::LLXmlTreeParser(LLXmlTree* tree)
00509 : mTree(tree),
00510 mRoot( NULL ),
00511 mCurrent( NULL ),
00512 mDump( FALSE )
00513 {
00514 }
00515
00516 LLXmlTreeParser::~LLXmlTreeParser()
00517 {
00518 }
00519
00520 BOOL LLXmlTreeParser::parseFile(const std::string &path, LLXmlTreeNode** root, BOOL keep_contents)
00521 {
00522 llassert( !mRoot );
00523 llassert( !mCurrent );
00524
00525 mKeepContents = keep_contents;
00526
00527 BOOL success = LLXmlParser::parseFile(path);
00528
00529 *root = mRoot;
00530 mRoot = NULL;
00531
00532 if( success )
00533 {
00534 llassert( !mCurrent );
00535 }
00536 mCurrent = NULL;
00537
00538 return success;
00539 }
00540
00541
00542 const std::string& LLXmlTreeParser::tabs()
00543 {
00544 static LLString s;
00545 s = "";
00546 S32 num_tabs = getDepth() - 1;
00547 for( S32 i = 0; i < num_tabs; i++)
00548 {
00549 s += " ";
00550 }
00551 return s;
00552 }
00553
00554 void LLXmlTreeParser::startElement(const char* name, const char **atts)
00555 {
00556 if( mDump )
00557 {
00558 llinfos << tabs() << "startElement " << name << llendl;
00559
00560 S32 i = 0;
00561 while( atts[i] && atts[i+1] )
00562 {
00563 llinfos << tabs() << "attribute: " << atts[i] << "=" << atts[i+1] << llendl;
00564 i += 2;
00565 }
00566 }
00567
00568 LLXmlTreeNode* child = CreateXmlTreeNode( std::string(name), mCurrent );
00569
00570 S32 i = 0;
00571 while( atts[i] && atts[i+1] )
00572 {
00573 child->addAttribute( atts[i], atts[i+1] );
00574 i += 2;
00575 }
00576
00577 if( mCurrent )
00578 {
00579 mCurrent->addChild( child );
00580
00581 }
00582 else
00583 {
00584 llassert( !mRoot );
00585 mRoot = child;
00586 }
00587 mCurrent = child;
00588 }
00589
00590 LLXmlTreeNode* LLXmlTreeParser::CreateXmlTreeNode(const std::string& name, LLXmlTreeNode* parent)
00591 {
00592 return new LLXmlTreeNode(name, parent, mTree);
00593 }
00594
00595
00596 void LLXmlTreeParser::endElement(const char* name)
00597 {
00598 if( mDump )
00599 {
00600 llinfos << tabs() << "endElement " << name << llendl;
00601 }
00602
00603 if( !mCurrent->mContents.empty() )
00604 {
00605 LLString::trim(mCurrent->mContents);
00606 LLString::removeCRLF(mCurrent->mContents);
00607 }
00608
00609 mCurrent = mCurrent->getParent();
00610 }
00611
00612 void LLXmlTreeParser::characterData(const char *s, int len)
00613 {
00614 LLString str(s, len);
00615 if( mDump )
00616 {
00617 llinfos << tabs() << "CharacterData " << str << llendl;
00618 }
00619
00620 if (mKeepContents)
00621 {
00622 mCurrent->appendContents( str );
00623 }
00624 }
00625
00626 void LLXmlTreeParser::processingInstruction(const char *target, const char *data)
00627 {
00628 if( mDump )
00629 {
00630 llinfos << tabs() << "processingInstruction " << data << llendl;
00631 }
00632 }
00633
00634 void LLXmlTreeParser::comment(const char *data)
00635 {
00636 if( mDump )
00637 {
00638 llinfos << tabs() << "comment " << data << llendl;
00639 }
00640 }
00641
00642 void LLXmlTreeParser::startCdataSection()
00643 {
00644 if( mDump )
00645 {
00646 llinfos << tabs() << "startCdataSection" << llendl;
00647 }
00648 }
00649
00650 void LLXmlTreeParser::endCdataSection()
00651 {
00652 if( mDump )
00653 {
00654 llinfos << tabs() << "endCdataSection" << llendl;
00655 }
00656 }
00657
00658 void LLXmlTreeParser::defaultData(const char *s, int len)
00659 {
00660 if( mDump )
00661 {
00662 LLString str(s, len);
00663 llinfos << tabs() << "defaultData " << str << llendl;
00664 }
00665 }
00666
00667 void LLXmlTreeParser::unparsedEntityDecl(
00668 const char* entity_name,
00669 const char* base,
00670 const char* system_id,
00671 const char* public_id,
00672 const char* notation_name)
00673 {
00674 if( mDump )
00675 {
00676 llinfos << tabs() << "unparsed entity:" << llendl;
00677 llinfos << tabs() << " entityName " << entity_name << llendl;
00678 llinfos << tabs() << " base " << base << llendl;
00679 llinfos << tabs() << " systemId " << system_id << llendl;
00680 llinfos << tabs() << " publicId " << public_id << llendl;
00681 llinfos << tabs() << " notationName " << notation_name<< llendl;
00682 }
00683 }
00684
00685 void test_llxmltree()
00686 {
00687 LLXmlTree tree;
00688 BOOL success = tree.parseFile( "test.xml" );
00689 if( success )
00690 {
00691 tree.dump();
00692 }
00693 }
00694