00001
00033 #include "linden_common.h"
00034
00035 #include <iostream>
00036 #include <map>
00037
00038 #include "llxmlnode.h"
00039
00040 #include "v3color.h"
00041 #include "v4color.h"
00042 #include "v4coloru.h"
00043 #include "v3math.h"
00044 #include "v3dmath.h"
00045 #include "v4math.h"
00046 #include "llquaternion.h"
00047 #include "llstring.h"
00048 #include "lluuid.h"
00049
00050 const S32 MAX_COLUMN_WIDTH = 80;
00051
00052
00053 BOOL LLXMLNode::sStripEscapedStrings = TRUE;
00054 BOOL LLXMLNode::sStripWhitespaceValues = FALSE;
00055
00056 LLXMLNode::LLXMLNode() :
00057 mID(""),
00058 mIsAttribute(FALSE),
00059 mVersionMajor(0),
00060 mVersionMinor(0),
00061 mLength(0),
00062 mPrecision(64),
00063 mType(TYPE_CONTAINER),
00064 mEncoding(ENCODING_DEFAULT),
00065 mParent(NULL),
00066 mChildren(NULL),
00067 mName(NULL),
00068 mValue(""),
00069 mDefault(NULL)
00070 {
00071 }
00072
00073 LLXMLNode::LLXMLNode(const LLString& name, BOOL is_attribute) :
00074 mID(""),
00075 mIsAttribute(is_attribute),
00076 mVersionMajor(0),
00077 mVersionMinor(0),
00078 mLength(0),
00079 mPrecision(64),
00080 mType(TYPE_CONTAINER),
00081 mEncoding(ENCODING_DEFAULT),
00082 mParent(NULL),
00083 mChildren(NULL),
00084 mValue(""),
00085 mDefault(NULL)
00086 {
00087 mName = gStringTable.addStringEntry(name);
00088 }
00089
00090 LLXMLNode::LLXMLNode(LLStringTableEntry* name, BOOL is_attribute) :
00091 mID(""),
00092 mIsAttribute(is_attribute),
00093 mVersionMajor(0),
00094 mVersionMinor(0),
00095 mLength(0),
00096 mPrecision(64),
00097 mType(TYPE_CONTAINER),
00098 mEncoding(ENCODING_DEFAULT),
00099 mParent(NULL),
00100 mChildren(NULL),
00101 mName(name),
00102 mValue(""),
00103 mDefault(NULL)
00104 {
00105 }
00106
00107
00108 LLXMLNode::~LLXMLNode()
00109 {
00110
00111 if (mChildren)
00112 {
00113 for (LLXMLChildList::iterator iter = mChildren->map.begin();
00114 iter != mChildren->map.end(); ++iter)
00115 {
00116 LLXMLNodePtr child = iter->second;
00117 child->mParent = NULL;
00118 child->mNext = NULL;
00119 child->mPrev = NULL;
00120 }
00121 mChildren->map.clear();
00122 mChildren->head = NULL;
00123 mChildren->tail = NULL;
00124 delete mChildren;
00125 }
00126 for (LLXMLAttribList::iterator iter = mAttributes.begin();
00127 iter != mAttributes.end(); ++iter)
00128 {
00129 LLXMLNodePtr attr = iter->second;
00130 attr->mParent = NULL;
00131 attr->mNext = NULL;
00132 attr->mPrev = NULL;
00133 }
00134 llassert(mParent == NULL);
00135 mDefault = NULL;
00136 }
00137
00138 BOOL LLXMLNode::isNull()
00139 {
00140 return (mName == NULL);
00141 }
00142
00143
00144 BOOL LLXMLNode::removeChild(LLXMLNode *target_child)
00145 {
00146 if (!target_child)
00147 {
00148 return FALSE;
00149 }
00150 if (target_child->mIsAttribute)
00151 {
00152 LLXMLAttribList::iterator children_itr = mAttributes.find(target_child->mName);
00153 if (children_itr != mAttributes.end())
00154 {
00155 target_child->mParent = NULL;
00156 mAttributes.erase(children_itr);
00157 return TRUE;
00158 }
00159 }
00160 else if (mChildren)
00161 {
00162 LLXMLChildList::iterator children_itr = mChildren->map.find(target_child->mName);
00163 while (children_itr != mChildren->map.end())
00164 {
00165 if (target_child == children_itr->second)
00166 {
00167 if (target_child == mChildren->head)
00168 {
00169 mChildren->head = target_child->mNext;
00170 }
00171
00172 LLXMLNodePtr prev = target_child->mPrev;
00173 LLXMLNodePtr next = target_child->mNext;
00174 if (prev.notNull()) prev->mNext = next;
00175 if (next.notNull()) next->mPrev = prev;
00176
00177 target_child->mPrev = NULL;
00178 target_child->mNext = NULL;
00179 target_child->mParent = NULL;
00180 mChildren->map.erase(children_itr);
00181 if (mChildren->map.empty())
00182 {
00183 delete mChildren;
00184 mChildren = NULL;
00185 }
00186 return TRUE;
00187 }
00188 else if (children_itr->first != target_child->mName)
00189 {
00190 break;
00191 }
00192 else
00193 {
00194 ++children_itr;
00195 }
00196 }
00197 }
00198 return FALSE;
00199 }
00200
00201 void LLXMLNode::addChild(LLXMLNodePtr new_child)
00202 {
00203 if (new_child->mParent != NULL)
00204 {
00205 if (new_child->mParent == this)
00206 {
00207 return;
00208 }
00209 new_child->mParent->removeChild(new_child);
00210 }
00211
00212 new_child->mParent = this;
00213 if (new_child->mIsAttribute)
00214 {
00215 mAttributes.insert(std::pair<LLStringTableEntry*, LLXMLNodePtr>(new_child->mName, new_child));
00216 }
00217 else
00218 {
00219 if (!mChildren)
00220 {
00221 mChildren = new LLXMLChildren();
00222 mChildren->head = new_child;
00223 mChildren->tail = new_child;
00224 }
00225 mChildren->map.insert(std::pair<LLStringTableEntry*, LLXMLNodePtr>(new_child->mName, new_child));
00226
00227 if (mChildren->tail != new_child)
00228 {
00229 mChildren->tail->mNext = new_child;
00230 new_child->mPrev = mChildren->tail;
00231 mChildren->tail = new_child;
00232 }
00233 }
00234
00235 new_child->updateDefault();
00236 }
00237
00238
00239 LLXMLNodePtr LLXMLNode::createChild(const LLString& name, BOOL is_attribute)
00240 {
00241 return createChild(gStringTable.addStringEntry(name), is_attribute);
00242 }
00243
00244
00245 LLXMLNodePtr LLXMLNode::createChild(LLStringTableEntry* name, BOOL is_attribute)
00246 {
00247 LLXMLNode* ret = new LLXMLNode(name, is_attribute);
00248 ret->mID = "";
00249 addChild(ret);
00250 return ret;
00251 }
00252
00253 BOOL LLXMLNode::deleteChild(LLXMLNode *child)
00254 {
00255 if (removeChild(child))
00256 {
00257 return TRUE;
00258 }
00259 return FALSE;
00260 }
00261
00262 void LLXMLNode::setParent(LLXMLNodePtr new_parent)
00263 {
00264 if (new_parent.notNull())
00265 {
00266 new_parent->addChild(this);
00267 }
00268 else
00269 {
00270 if (mParent != NULL)
00271 {
00272 LLXMLNodePtr old_parent = mParent;
00273 mParent = NULL;
00274 old_parent->removeChild(this);
00275 }
00276 }
00277 }
00278
00279
00280 void LLXMLNode::updateDefault()
00281 {
00282 if (mParent != NULL && !mParent->mDefault.isNull())
00283 {
00284 mDefault = NULL;
00285
00286
00287 if (!mParent->mDefault.isNull())
00288 {
00289 findDefault(mParent->mDefault);
00290 }
00291 }
00292
00293 if (mChildren)
00294 {
00295 LLXMLChildList::const_iterator children_itr;
00296 LLXMLChildList::const_iterator children_end = mChildren->map.end();
00297 for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
00298 {
00299 LLXMLNodePtr child = (*children_itr).second;
00300 child->updateDefault();
00301 }
00302 }
00303 }
00304
00305 void XMLCALL StartXMLNode(void *userData,
00306 const XML_Char *name,
00307 const XML_Char **atts)
00308 {
00309
00310 LLXMLNode *new_node_ptr = new LLXMLNode(name, FALSE);
00311 LLXMLNodePtr new_node = new_node_ptr;
00312 new_node->mID = "";
00313 LLXMLNodePtr ptr_new_node = new_node;
00314
00315
00316 LLXMLNode* parent = (LLXMLNode *)userData;
00317
00318 if (NULL == parent)
00319 {
00320 llwarns << "parent (userData) is NULL; aborting function" << llendl;
00321 return;
00322 }
00323
00324 new_node_ptr->mParser = parent->mParser;
00325
00326
00327 XML_Parser *parser = parent->mParser;
00328 XML_SetUserData(*parser, (void *)new_node_ptr);
00329
00330
00331 U32 pos = 0;
00332 while (atts[pos] != NULL)
00333 {
00334 LLString attr_name = atts[pos];
00335 LLString attr_value = atts[pos+1];
00336
00337
00338 if ('i' == attr_name[0] && "id" == attr_name)
00339 {
00340 new_node->mID = attr_value;
00341 }
00342 else if ('v' == attr_name[0] && "version" == attr_name)
00343 {
00344 U32 version_major = 0;
00345 U32 version_minor = 0;
00346 if (sscanf(attr_value.c_str(), "%d.%d", &version_major, &version_minor) > 0)
00347 {
00348 new_node->mVersionMajor = version_major;
00349 new_node->mVersionMinor = version_minor;
00350 }
00351 }
00352 else if (('s' == attr_name[0] && "size" == attr_name) || ('l' == attr_name[0] && "length" == attr_name))
00353 {
00354 U32 length;
00355 if (sscanf(attr_value.c_str(), "%d", &length) > 0)
00356 {
00357 new_node->mLength = length;
00358 }
00359 }
00360 else if ('p' == attr_name[0] && "precision" == attr_name)
00361 {
00362 U32 precision;
00363 if (sscanf(attr_value.c_str(), "%d", &precision) > 0)
00364 {
00365 new_node->mPrecision = precision;
00366 }
00367 }
00368 else if ('t' == attr_name[0] && "type" == attr_name)
00369 {
00370 if ("boolean" == attr_value)
00371 {
00372 new_node->mType = LLXMLNode::TYPE_BOOLEAN;
00373 }
00374 else if ("integer" == attr_value)
00375 {
00376 new_node->mType = LLXMLNode::TYPE_INTEGER;
00377 }
00378 else if ("float" == attr_value)
00379 {
00380 new_node->mType = LLXMLNode::TYPE_FLOAT;
00381 }
00382 else if ("string" == attr_value)
00383 {
00384 new_node->mType = LLXMLNode::TYPE_STRING;
00385 }
00386 else if ("uuid" == attr_value)
00387 {
00388 new_node->mType = LLXMLNode::TYPE_UUID;
00389 }
00390 else if ("noderef" == attr_value)
00391 {
00392 new_node->mType = LLXMLNode::TYPE_NODEREF;
00393 }
00394 }
00395 else if ('e' == attr_name[0] && "encoding" == attr_name)
00396 {
00397 if ("decimal" == attr_value)
00398 {
00399 new_node->mEncoding = LLXMLNode::ENCODING_DECIMAL;
00400 }
00401 else if ("hex" == attr_value)
00402 {
00403 new_node->mEncoding = LLXMLNode::ENCODING_HEX;
00404 }
00405
00406
00407
00408
00409 }
00410
00411
00412 LLXMLNodePtr attr_node;
00413 if (!new_node->getAttribute(attr_name, attr_node, FALSE))
00414 {
00415 attr_node = new LLXMLNode(attr_name, TRUE);
00416 }
00417 attr_node->setValue(attr_value);
00418 new_node->addChild(attr_node);
00419
00420 pos += 2;
00421 }
00422
00423 if (parent)
00424 {
00425 parent->addChild(new_node);
00426 }
00427 }
00428
00429 void XMLCALL EndXMLNode(void *userData,
00430 const XML_Char *name)
00431 {
00432
00433 LLXMLNode *node = (LLXMLNode *)userData;
00434 XML_Parser *parser = node->mParser;
00435 XML_SetUserData(*parser, (void *)node->mParent);
00436
00437 if (LLXMLNode::sStripWhitespaceValues)
00438 {
00439 LLString value = node->getValue();
00440 BOOL is_empty = TRUE;
00441 for (std::string::size_type s = 0; s < value.length(); s++)
00442 {
00443 char c = value[s];
00444 if (c != ' ' && c != '\t' && c != '\n')
00445 {
00446 is_empty = FALSE;
00447 break;
00448 }
00449 }
00450 if (is_empty)
00451 {
00452 value.clear();
00453 node->setValue(value);
00454 }
00455 }
00456 }
00457
00458 void XMLCALL XMLData(void *userData,
00459 const XML_Char *s,
00460 int len)
00461 {
00462 LLXMLNode* current_node = (LLXMLNode *)userData;
00463 LLString value = current_node->getValue();
00464 if (LLXMLNode::sStripEscapedStrings)
00465 {
00466 if (s[0] == '\"' && s[len-1] == '\"')
00467 {
00468
00469 LLString unescaped_string;
00470 for (S32 pos=1; pos<len-1; ++pos)
00471 {
00472 if (s[pos] == '\\' && s[pos+1] == '\\')
00473 {
00474 unescaped_string.append("\\");
00475 ++pos;
00476 }
00477 else if (s[pos] == '\\' && s[pos+1] == '\"')
00478 {
00479 unescaped_string.append("\"");
00480 ++pos;
00481 }
00482 else
00483 {
00484 unescaped_string.append(&s[pos], 1);
00485 }
00486 }
00487 value.append(unescaped_string);
00488 current_node->setValue(value);
00489 return;
00490 }
00491 }
00492 value.append(LLString(s, 0, len));
00493 current_node->setValue(value);
00494 }
00495
00496
00497
00498
00499 bool LLXMLNode::updateNode(
00500 LLXMLNodePtr& node,
00501 LLXMLNodePtr& update_node)
00502 {
00503
00504 if (!node || !update_node)
00505 {
00506 llwarns << "Node invalid" << llendl;
00507 return FALSE;
00508 }
00509
00510
00511 node->mValue = update_node->mValue;
00512
00513
00514 LLXMLAttribList::const_iterator itor;
00515
00516 for(itor = update_node->mAttributes.begin(); itor != update_node->mAttributes.end(); ++itor)
00517 {
00518 const LLStringTableEntry* attribNameEntry = (*itor).first;
00519 LLXMLNodePtr updateAttribNode = (*itor).second;
00520
00521 LLXMLNodePtr attribNode;
00522
00523 node->getAttribute(attribNameEntry, attribNode, 0);
00524
00525 if (attribNode)
00526 {
00527 attribNode->mValue = updateAttribNode->mValue;
00528 }
00529 }
00530
00531
00532 LLXMLNodePtr child;
00533 LLXMLNodePtr updateChild;
00534
00535 for (updateChild = update_node->getFirstChild(); updateChild.notNull();
00536 updateChild = updateChild->getNextSibling())
00537 {
00538 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
00539 {
00540 LLString nodeName;
00541 LLString updateName;
00542
00543 updateChild->getAttributeString("name", updateName);
00544 child->getAttributeString("name", nodeName);
00545
00546
00547
00548 if (updateName.empty())
00549 {
00550 updateChild->getAttributeString("value", updateName);
00551 child->getAttributeString("value", nodeName);
00552 }
00553
00554 if ((nodeName != "") && (updateName == nodeName))
00555 {
00556 updateNode(child, updateChild);
00557 break;
00558 }
00559 }
00560 }
00561
00562 return TRUE;
00563 }
00564
00565
00566
00567
00568
00569 bool LLXMLNode::parseFile(
00570 LLString filename,
00571 LLXMLNodePtr& node,
00572 LLXMLNode* defaults_tree)
00573 {
00574
00575 FILE* fp = LLFile::fopen(filename.c_str(), "rb");
00576 if (fp == NULL)
00577 {
00578 node = new LLXMLNode();
00579 return false;
00580 }
00581 fseek(fp, 0, SEEK_END);
00582 U32 length = ftell(fp);
00583 fseek(fp, 0, SEEK_SET);
00584
00585 U8* buffer = new U8[length+1];
00586 size_t nread = fread(buffer, 1, length, fp);
00587 buffer[nread] = 0;
00588 fclose(fp);
00589
00590 bool rv = parseBuffer(buffer, nread, node, defaults_tree);
00591 delete [] buffer;
00592 return rv;
00593 }
00594
00595
00596 bool LLXMLNode::parseBuffer(
00597 U8* buffer,
00598 U32 length,
00599 LLXMLNodePtr& node,
00600 LLXMLNode* defaults)
00601 {
00602
00603 XML_Parser my_parser = XML_ParserCreate(NULL);
00604 XML_SetElementHandler(my_parser, StartXMLNode, EndXMLNode);
00605 XML_SetCharacterDataHandler(my_parser, XMLData);
00606
00607
00608 LLXMLNode *file_node_ptr = new LLXMLNode("XML", FALSE);
00609 LLXMLNodePtr file_node = file_node_ptr;
00610
00611 file_node->mParser = &my_parser;
00612
00613 XML_SetUserData(my_parser, (void *)file_node_ptr);
00614
00615
00616 if (XML_Parse(my_parser, (const char *)buffer, length, TRUE) != XML_STATUS_OK)
00617 {
00618 llwarns << "Error parsing xml error code: "
00619 << XML_ErrorString(XML_GetErrorCode(my_parser))
00620 << " on lne " << XML_GetCurrentLineNumber(my_parser)
00621 << llendl;
00622 }
00623
00624
00625 XML_ParserFree(my_parser);
00626
00627 if (!file_node->mChildren || file_node->mChildren->map.size() != 1)
00628 {
00629 llwarns << "Parse failure - wrong number of top-level nodes xml."
00630 << llendl;
00631 node = new LLXMLNode();
00632 return false;
00633 }
00634
00635 LLXMLNode *return_node = file_node->mChildren->map.begin()->second;
00636
00637 return_node->setDefault(defaults);
00638 return_node->updateDefault();
00639
00640 node = return_node;
00641 return true;
00642 }
00643
00644
00645 bool LLXMLNode::parseStream(
00646 std::istream& str,
00647 LLXMLNodePtr& node,
00648 LLXMLNode* defaults)
00649 {
00650
00651 XML_Parser my_parser = XML_ParserCreate(NULL);
00652 XML_SetElementHandler(my_parser, StartXMLNode, EndXMLNode);
00653 XML_SetCharacterDataHandler(my_parser, XMLData);
00654
00655
00656 LLXMLNode *file_node_ptr = new LLXMLNode("XML", FALSE);
00657 LLXMLNodePtr file_node = file_node_ptr;
00658
00659 file_node->mParser = &my_parser;
00660
00661 XML_SetUserData(my_parser, (void *)file_node_ptr);
00662
00663 const int BUFSIZE = 1024;
00664 U8* buffer = new U8[BUFSIZE];
00665
00666 while(str.good())
00667 {
00668 str.read((char*)buffer, BUFSIZE);
00669 int count = str.gcount();
00670
00671 if (XML_Parse(my_parser, (const char *)buffer, count, !str.good()) != XML_STATUS_OK)
00672 {
00673 llwarns << "Error parsing xml error code: "
00674 << XML_ErrorString(XML_GetErrorCode(my_parser))
00675 << " on lne " << XML_GetCurrentLineNumber(my_parser)
00676 << llendl;
00677 break;
00678 }
00679 }
00680
00681 delete [] buffer;
00682
00683
00684 XML_ParserFree(my_parser);
00685
00686 if (!file_node->mChildren || file_node->mChildren->map.size() != 1)
00687 {
00688 llwarns << "Parse failure - wrong number of top-level nodes xml."
00689 << llendl;
00690 node = new LLXMLNode();
00691 return false;
00692 }
00693
00694 LLXMLNode *return_node = file_node->mChildren->map.begin()->second;
00695
00696 return_node->setDefault(defaults);
00697 return_node->updateDefault();
00698
00699 node = return_node;
00700 return true;
00701 }
00702
00703
00704 BOOL LLXMLNode::isFullyDefault()
00705 {
00706 if (mDefault.isNull())
00707 {
00708 return FALSE;
00709 }
00710 BOOL has_default_value = (mValue == mDefault->mValue);
00711 BOOL has_default_attribute = (mIsAttribute == mDefault->mIsAttribute);
00712 BOOL has_default_type = mIsAttribute || (mType == mDefault->mType);
00713 BOOL has_default_encoding = mIsAttribute || (mEncoding == mDefault->mEncoding);
00714 BOOL has_default_precision = mIsAttribute || (mPrecision == mDefault->mPrecision);
00715 BOOL has_default_length = mIsAttribute || (mLength == mDefault->mLength);
00716
00717 if (has_default_value
00718 && has_default_type
00719 && has_default_encoding
00720 && has_default_precision
00721 && has_default_length
00722 && has_default_attribute)
00723 {
00724 if (mChildren)
00725 {
00726 LLXMLChildList::const_iterator children_itr;
00727 LLXMLChildList::const_iterator children_end = mChildren->map.end();
00728 for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
00729 {
00730 LLXMLNodePtr child = (*children_itr).second;
00731 if (!child->isFullyDefault())
00732 {
00733 return FALSE;
00734 }
00735 }
00736 }
00737 return TRUE;
00738 }
00739
00740 return FALSE;
00741 }
00742
00743
00744 void LLXMLNode::writeHeaderToFile(FILE *fOut)
00745 {
00746 fprintf(fOut, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n");
00747 }
00748
00749 void LLXMLNode::writeToFile(FILE *fOut, LLString indent)
00750 {
00751 if (isFullyDefault())
00752 {
00753
00754 return;
00755 }
00756
00757 std::ostringstream ostream;
00758 writeToOstream(ostream, indent);
00759 LLString outstring = ostream.str();
00760 if (fwrite(outstring.c_str(), 1, outstring.length(), fOut) != outstring.length())
00761 {
00762 llwarns << "Short write" << llendl;
00763 }
00764 }
00765
00766 void LLXMLNode::writeToOstream(std::ostream& output_stream, const LLString& indent)
00767 {
00768 if (isFullyDefault())
00769 {
00770
00771 return;
00772 }
00773
00774 BOOL has_default_type = mDefault.isNull()?FALSE:(mType == mDefault->mType);
00775 BOOL has_default_encoding = mDefault.isNull()?FALSE:(mEncoding == mDefault->mEncoding);
00776 BOOL has_default_precision = mDefault.isNull()?FALSE:(mPrecision == mDefault->mPrecision);
00777 BOOL has_default_length = mDefault.isNull()?FALSE:(mLength == mDefault->mLength);
00778
00779
00780 output_stream << indent.c_str() << "<" << mName->mString;
00781
00782
00783 if (mID != "")
00784 {
00785 output_stream << " id=\"" << mID.c_str() << "\"";
00786 }
00787
00788
00789 if (!has_default_type)
00790 {
00791 switch (mType)
00792 {
00793 case TYPE_BOOLEAN:
00794 output_stream << " type=\"boolean\"";
00795 break;
00796 case TYPE_INTEGER:
00797 output_stream << " type=\"integer\"";
00798 break;
00799 case TYPE_FLOAT:
00800 output_stream << " type=\"float\"";
00801 break;
00802 case TYPE_STRING:
00803 output_stream << " type=\"string\"";
00804 break;
00805 case TYPE_UUID:
00806 output_stream << " type=\"uuid\"";
00807 break;
00808 case TYPE_NODEREF:
00809 output_stream << " type=\"noderef\"";
00810 break;
00811 default:
00812
00813 break;
00814 };
00815 }
00816
00817
00818 if (!has_default_encoding)
00819 {
00820 switch (mEncoding)
00821 {
00822 case ENCODING_DECIMAL:
00823 output_stream << " encoding=\"decimal\"";
00824 break;
00825 case ENCODING_HEX:
00826 output_stream << " encoding=\"hex\"";
00827 break;
00828
00829
00830
00831 default:
00832
00833 break;
00834 };
00835 }
00836
00837
00838 if (!has_default_precision && (mType == TYPE_INTEGER || mType == TYPE_FLOAT))
00839 {
00840 output_stream << " precision=\"" << mPrecision << "\"";
00841 }
00842
00843
00844 if (mVersionMajor > 0 || mVersionMinor > 0)
00845 {
00846 output_stream << " version=\"" << mVersionMajor << "." << mVersionMinor << "\"";
00847 }
00848
00849
00850 if (!has_default_length && mLength > 0)
00851 {
00852 output_stream << " length=\"" << mLength << "\"";
00853 }
00854
00855 {
00856
00857 S32 col_pos = 0;
00858 LLXMLAttribList::const_iterator attr_itr;
00859 LLXMLAttribList::const_iterator attr_end = mAttributes.end();
00860 for (attr_itr = mAttributes.begin(); attr_itr != attr_end; ++attr_itr)
00861 {
00862 LLXMLNodePtr child = (*attr_itr).second;
00863 if (child->mDefault.isNull() || child->mDefault->mValue != child->mValue)
00864 {
00865 LLString attr = child->mName->mString;
00866 if (attr == "id" ||
00867 attr == "type" ||
00868 attr == "encoding" ||
00869 attr == "precision" ||
00870 attr == "version" ||
00871 attr == "length")
00872 {
00873 continue;
00874 }
00875
00876 LLString attr_str = llformat(" %s=\"%s\"",
00877 attr.c_str(),
00878 escapeXML(child->mValue).c_str());
00879 if (col_pos + (S32)attr_str.length() > MAX_COLUMN_WIDTH)
00880 {
00881 output_stream << "\n" << indent << " ";
00882 col_pos = 4;
00883 }
00884 col_pos += attr_str.length();
00885 output_stream << attr_str;
00886 }
00887 }
00888 }
00889
00890 if (!mChildren && mValue == "")
00891 {
00892 output_stream << " />\n";
00893 return;
00894 }
00895 else
00896 {
00897 output_stream << ">\n";
00898 if (mChildren)
00899 {
00900
00901 LLString next_indent = indent + "\t";
00902 for (LLXMLNode* child = getFirstChild(); child; child = child->getNextSibling())
00903 {
00904 child->writeToOstream(output_stream, next_indent);
00905 }
00906 }
00907 if (!mValue.empty())
00908 {
00909 LLString contents = getTextContents();
00910 output_stream << indent.c_str() << "\t" << escapeXML(contents) << "\n";
00911 }
00912 output_stream << indent.c_str() << "</" << mName->mString << ">\n";
00913 }
00914 }
00915
00916 void LLXMLNode::findName(const LLString& name, LLXMLNodeList &results)
00917 {
00918 LLStringTableEntry* name_entry = gStringTable.checkStringEntry(name);
00919 if (name_entry == mName)
00920 {
00921 results.insert(std::pair<LLString, LLXMLNode*>(this->mName->mString, this));
00922 return;
00923 }
00924 if (mChildren)
00925 {
00926 LLXMLChildList::const_iterator children_itr;
00927 LLXMLChildList::const_iterator children_end = mChildren->map.end();
00928 for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
00929 {
00930 LLXMLNodePtr child = (*children_itr).second;
00931 child->findName(name_entry, results);
00932 }
00933 }
00934 }
00935
00936 void LLXMLNode::findName(LLStringTableEntry* name, LLXMLNodeList &results)
00937 {
00938 if (name == mName)
00939 {
00940 results.insert(std::pair<LLString, LLXMLNode*>(this->mName->mString, this));
00941 return;
00942 }
00943 if (mChildren)
00944 {
00945 LLXMLChildList::const_iterator children_itr;
00946 LLXMLChildList::const_iterator children_end = mChildren->map.end();
00947 for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
00948 {
00949 LLXMLNodePtr child = (*children_itr).second;
00950 child->findName(name, results);
00951 }
00952 }
00953 }
00954
00955 void LLXMLNode::findID(const LLString& id, LLXMLNodeList &results)
00956 {
00957 if (id == mID)
00958 {
00959 results.insert(std::pair<LLString, LLXMLNode*>(this->mName->mString, this));
00960 return;
00961 }
00962 if (mChildren)
00963 {
00964 LLXMLChildList::const_iterator children_itr;
00965 LLXMLChildList::const_iterator children_end = mChildren->map.end();
00966 for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
00967 {
00968 LLXMLNodePtr child = (*children_itr).second;
00969 child->findID(id, results);
00970 }
00971 }
00972 }
00973
00974 void LLXMLNode::scrubToTree(LLXMLNode *tree)
00975 {
00976 if (!tree || !tree->mChildren)
00977 {
00978 return;
00979 }
00980 if (mChildren)
00981 {
00982 std::vector<LLXMLNodePtr> to_delete_list;
00983 LLXMLChildList::iterator itor = mChildren->map.begin();
00984 while (itor != mChildren->map.end())
00985 {
00986 LLXMLNodePtr child = itor->second;
00987 LLXMLNodePtr child_tree = NULL;
00988
00989 bool found = false;
00990 LLXMLChildList::iterator itor2 = tree->mChildren->map.begin();
00991 while (itor2 != tree->mChildren->map.end())
00992 {
00993 if (child->mName == itor2->second->mName)
00994 {
00995 child_tree = itor2->second;
00996 found = true;
00997 }
00998 ++itor2;
00999 }
01000 if (!found)
01001 {
01002 to_delete_list.push_back(child);
01003 }
01004 else
01005 {
01006 child->scrubToTree(child_tree);
01007 }
01008 ++itor;
01009 }
01010 std::vector<LLXMLNodePtr>::iterator itor3;
01011 for (itor3=to_delete_list.begin(); itor3!=to_delete_list.end(); ++itor3)
01012 {
01013 (*itor3)->setParent(NULL);
01014 }
01015 }
01016 }
01017
01018 bool LLXMLNode::getChild(const LLString& name, LLXMLNodePtr& node, BOOL use_default_if_missing)
01019 {
01020 return getChild(gStringTable.checkStringEntry(name), node, use_default_if_missing);
01021 }
01022
01023 bool LLXMLNode::getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing)
01024 {
01025 if (mChildren)
01026 {
01027 LLXMLChildList::const_iterator child_itr = mChildren->map.find(name);
01028 if (child_itr != mChildren->map.end())
01029 {
01030 node = (*child_itr).second;
01031 return true;
01032 }
01033 }
01034 if (use_default_if_missing && !mDefault.isNull())
01035 {
01036 return mDefault->getChild(name, node, FALSE);
01037 }
01038 node = new LLXMLNode();
01039 return false;
01040 }
01041
01042 void LLXMLNode::getChildren(const LLString& name, LLXMLNodeList &children, BOOL use_default_if_missing) const
01043 {
01044 getChildren(gStringTable.checkStringEntry(name), children, use_default_if_missing);
01045 }
01046
01047 void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, BOOL use_default_if_missing) const
01048 {
01049 if (mChildren)
01050 {
01051 LLXMLChildList::const_iterator child_itr = mChildren->map.find(name);
01052 if (child_itr != mChildren->map.end())
01053 {
01054 LLXMLChildList::const_iterator children_end = mChildren->map.end();
01055 while (child_itr != children_end)
01056 {
01057 LLXMLNodePtr child = (*child_itr).second;
01058 if (name != child->mName)
01059 {
01060 break;
01061 }
01062 children.insert(std::pair<LLString, LLXMLNodePtr>(child->mName->mString, child));
01063 child_itr++;
01064 }
01065 }
01066 }
01067 if (children.size() == 0 && use_default_if_missing && !mDefault.isNull())
01068 {
01069 mDefault->getChildren(name, children, FALSE);
01070 }
01071 }
01072
01073 bool LLXMLNode::getAttribute(const LLString& name, LLXMLNodePtr& node, BOOL use_default_if_missing)
01074 {
01075 return getAttribute(gStringTable.checkStringEntry(name), node, use_default_if_missing);
01076 }
01077
01078 bool LLXMLNode::getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing)
01079 {
01080 LLXMLAttribList::const_iterator child_itr = mAttributes.find(name);
01081 if (child_itr != mAttributes.end())
01082 {
01083 node = (*child_itr).second;
01084 return true;
01085 }
01086 if (use_default_if_missing && !mDefault.isNull())
01087 {
01088 return mDefault->getAttribute(name, node, FALSE);
01089 }
01090 node = new LLXMLNode();
01091 return false;
01092 }
01093
01094 bool LLXMLNode::setAttributeString(const LLString& attr, const LLString& value)
01095 {
01096 LLStringTableEntry* name = gStringTable.checkStringEntry(attr);
01097 LLXMLAttribList::const_iterator child_itr = mAttributes.find(name);
01098 if (child_itr != mAttributes.end())
01099 {
01100 LLXMLNodePtr node = (*child_itr).second;
01101 node->setValue(value);
01102 return true;
01103 }
01104 return false;
01105 }
01106
01107 BOOL LLXMLNode::hasAttribute(const LLString& name )
01108 {
01109 LLXMLNodePtr node;
01110 return getAttribute(name, node);
01111 }
01112
01113 BOOL LLXMLNode::getAttributeBOOL(const LLString& name, BOOL& value )
01114 {
01115 LLXMLNodePtr node;
01116 return (getAttribute(name, node) && node->getBoolValue(1, &value));
01117 }
01118
01119 BOOL LLXMLNode::getAttributeU8(const LLString& name, U8& value )
01120 {
01121 LLXMLNodePtr node;
01122 return (getAttribute(name, node) && node->getByteValue(1, &value));
01123 }
01124
01125 BOOL LLXMLNode::getAttributeS8(const LLString& name, S8& value )
01126 {
01127 LLXMLNodePtr node;
01128 S32 val;
01129 if (!(getAttribute(name, node) && node->getIntValue(1, &val)))
01130 {
01131 return false;
01132 }
01133 value = val;
01134 return true;
01135 }
01136
01137 BOOL LLXMLNode::getAttributeU16(const LLString& name, U16& value )
01138 {
01139 LLXMLNodePtr node;
01140 U32 val;
01141 if (!(getAttribute(name, node) && node->getUnsignedValue(1, &val)))
01142 {
01143 return false;
01144 }
01145 value = val;
01146 return true;
01147 }
01148
01149 BOOL LLXMLNode::getAttributeS16(const LLString& name, S16& value )
01150 {
01151 LLXMLNodePtr node;
01152 S32 val;
01153 if (!(getAttribute(name, node) && node->getIntValue(1, &val)))
01154 {
01155 return false;
01156 }
01157 value = val;
01158 return true;
01159 }
01160
01161 BOOL LLXMLNode::getAttributeU32(const LLString& name, U32& value )
01162 {
01163 LLXMLNodePtr node;
01164 return (getAttribute(name, node) && node->getUnsignedValue(1, &value));
01165 }
01166
01167 BOOL LLXMLNode::getAttributeS32(const LLString& name, S32& value )
01168 {
01169 LLXMLNodePtr node;
01170 return (getAttribute(name, node) && node->getIntValue(1, &value));
01171 }
01172
01173 BOOL LLXMLNode::getAttributeF32(const LLString& name, F32& value )
01174 {
01175 LLXMLNodePtr node;
01176 return (getAttribute(name, node) && node->getFloatValue(1, &value));
01177 }
01178
01179 BOOL LLXMLNode::getAttributeF64(const LLString& name, F64& value )
01180 {
01181 LLXMLNodePtr node;
01182 return (getAttribute(name, node) && node->getDoubleValue(1, &value));
01183 }
01184
01185 BOOL LLXMLNode::getAttributeColor(const LLString& name, LLColor4& value )
01186 {
01187 LLXMLNodePtr node;
01188 return (getAttribute(name, node) && node->getFloatValue(4, value.mV));
01189 }
01190
01191 BOOL LLXMLNode::getAttributeColor4(const LLString& name, LLColor4& value )
01192 {
01193 LLXMLNodePtr node;
01194 return (getAttribute(name, node) && node->getFloatValue(4, value.mV));
01195 }
01196
01197 BOOL LLXMLNode::getAttributeColor4U(const LLString& name, LLColor4U& value )
01198 {
01199 LLXMLNodePtr node;
01200 return (getAttribute(name, node) && node->getByteValue(4, value.mV));
01201 }
01202
01203 BOOL LLXMLNode::getAttributeVector3(const LLString& name, LLVector3& value )
01204 {
01205 LLXMLNodePtr node;
01206 return (getAttribute(name, node) && node->getFloatValue(3, value.mV));
01207 }
01208
01209 BOOL LLXMLNode::getAttributeVector3d(const LLString& name, LLVector3d& value )
01210 {
01211 LLXMLNodePtr node;
01212 return (getAttribute(name, node) && node->getDoubleValue(3, value.mdV));
01213 }
01214
01215 BOOL LLXMLNode::getAttributeQuat(const LLString& name, LLQuaternion& value )
01216 {
01217 LLXMLNodePtr node;
01218 return (getAttribute(name, node) && node->getFloatValue(4, value.mQ));
01219 }
01220
01221 BOOL LLXMLNode::getAttributeUUID(const LLString& name, LLUUID& value )
01222 {
01223 LLXMLNodePtr node;
01224 return (getAttribute(name, node) && node->getUUIDValue(1, &value));
01225 }
01226
01227 BOOL LLXMLNode::getAttributeString(const LLString& name, LLString& value )
01228 {
01229 LLXMLNodePtr node;
01230 if (!getAttribute(name, node))
01231 {
01232 return false;
01233 }
01234 value = node->getValue();
01235 return true;
01236 }
01237
01238 LLXMLNodePtr LLXMLNode::getRoot()
01239 {
01240 if (mParent == NULL)
01241 {
01242 return this;
01243 }
01244 return mParent->getRoot();
01245 }
01246
01247
01248 const char *LLXMLNode::skipWhitespace(const char *str)
01249 {
01250
01251 while (str[0] == ' ' || str[0] == '\t' || str[0] == '\n') ++str;
01252 return str;
01253 }
01254
01255
01256 const char *LLXMLNode::skipNonWhitespace(const char *str)
01257 {
01258
01259 while (str[0] != ' ' && str[0] != '\t' && str[0] != '\n' && str[0] != 0) ++str;
01260 return str;
01261 }
01262
01263
01264 const char *LLXMLNode::parseInteger(const char *str, U64 *dest, BOOL *is_negative, U32 precision, Encoding encoding)
01265 {
01266 *dest = 0;
01267 *is_negative = FALSE;
01268
01269 str = skipWhitespace(str);
01270
01271 if (str[0] == 0) return NULL;
01272
01273 if (encoding == ENCODING_DECIMAL || encoding == ENCODING_DEFAULT)
01274 {
01275 if (str[0] == '+')
01276 {
01277 ++str;
01278 }
01279 if (str[0] == '-')
01280 {
01281 *is_negative = TRUE;
01282 ++str;
01283 }
01284
01285 str = skipWhitespace(str);
01286
01287 U64 ret = 0;
01288 while (str[0] >= '0' && str[0] <= '9')
01289 {
01290 ret *= 10;
01291 ret += str[0] - '0';
01292 ++str;
01293 }
01294
01295 if (str[0] == '.')
01296 {
01297
01298 str = skipNonWhitespace(str);
01299 }
01300
01301 *dest = ret;
01302 return str;
01303 }
01304 if (encoding == ENCODING_HEX)
01305 {
01306 U64 ret = 0;
01307 str = skipWhitespace(str);
01308 for (U32 pos=0; pos<(precision/4); ++pos)
01309 {
01310 ret <<= 4;
01311 str = skipWhitespace(str);
01312 if (str[0] >= '0' && str[0] <= '9')
01313 {
01314 ret += str[0] - '0';
01315 }
01316 else if (str[0] >= 'a' && str[0] <= 'f')
01317 {
01318 ret += str[0] - 'a' + 10;
01319 }
01320 else if (str[0] >= 'A' && str[0] <= 'F')
01321 {
01322 ret += str[0] - 'A' + 10;
01323 }
01324 else
01325 {
01326 return NULL;
01327 }
01328 ++str;
01329 }
01330
01331 *dest = ret;
01332 return str;
01333 }
01334 return NULL;
01335 }
01336
01337
01338 const U64 float_coeff_table[] =
01339 { 5, 25, 125, 625, 3125,
01340 15625, 78125, 390625, 1953125, 9765625,
01341 48828125, 244140625, 1220703125, 6103515625LL, 30517578125LL,
01342 152587890625LL, 762939453125LL, 3814697265625LL, 19073486328125LL, 95367431640625LL,
01343 476837158203125LL, 2384185791015625LL, 11920928955078125LL, 59604644775390625LL, 298023223876953125LL };
01344
01345
01346 const U64 float_coeff_table_2[] =
01347 { 149011611938476562LL,74505805969238281LL,
01348 37252902984619140LL, 18626451492309570LL, 9313225746154785LL, 4656612873077392LL,
01349 2328306436538696LL, 1164153218269348LL, 582076609134674LL, 291038304567337LL,
01350 145519152283668LL, 72759576141834LL, 36379788070917LL, 18189894035458LL,
01351 9094947017729LL, 4547473508864LL, 2273736754432LL, 1136868377216LL,
01352 568434188608LL, 284217094304LL, 142108547152LL, 71054273576LL,
01353 35527136788LL, 17763568394LL, 8881784197LL, 4440892098LL,
01354 2220446049LL, 1110223024LL, 555111512LL, 277555756LL,
01355 138777878, 69388939, 34694469, 17347234,
01356 8673617, 4336808, 2168404, 1084202,
01357 542101, 271050, 135525, 67762,
01358 };
01359
01360
01361 const char *LLXMLNode::parseFloat(const char *str, F64 *dest, U32 precision, Encoding encoding)
01362 {
01363 str = skipWhitespace(str);
01364
01365 if (str[0] == 0) return NULL;
01366
01367 if (encoding == ENCODING_DECIMAL || encoding == ENCODING_DEFAULT)
01368 {
01369 str = skipWhitespace(str);
01370
01371 if (memcmp(str, "inf", 3) == 0)
01372 {
01373 *(U64 *)dest = 0x7FF0000000000000ll;
01374 return str + 3;
01375 }
01376 if (memcmp(str, "-inf", 4) == 0)
01377 {
01378 *(U64 *)dest = 0xFFF0000000000000ll;
01379 return str + 4;
01380 }
01381 if (memcmp(str, "1.#INF", 6) == 0)
01382 {
01383 *(U64 *)dest = 0x7FF0000000000000ll;
01384 return str + 6;
01385 }
01386 if (memcmp(str, "-1.#INF", 7) == 0)
01387 {
01388 *(U64 *)dest = 0xFFF0000000000000ll;
01389 return str + 7;
01390 }
01391
01392 F64 negative = 1.0f;
01393 if (str[0] == '+')
01394 {
01395 ++str;
01396 }
01397 if (str[0] == '-')
01398 {
01399 negative = -1.0f;
01400 ++str;
01401 }
01402
01403 const char* base_str = str;
01404 str = skipWhitespace(str);
01405
01406
01407 U64 int_part = 0;
01408 while (str[0] >= '0' && str[0] <= '9')
01409 {
01410 int_part *= 10;
01411 int_part += U64(str[0] - '0');
01412 ++str;
01413 }
01414
01415 U64 f_part = 0;
01416 if (str[0] == '.')
01417 {
01418 ++str;
01419 U64 remainder = 0;
01420 U32 pos = 0;
01421
01422 while (str[0] >= '0' && str[0] <= '9' && pos < 25)
01423 {
01424 remainder = (remainder*10) + U64(str[0] - '0');
01425 f_part <<= 1;
01426
01427
01428 if (remainder >= float_coeff_table[pos])
01429 {
01430 remainder -= float_coeff_table[pos];
01431 f_part |= 1;
01432 }
01433 ++pos;
01434 ++str;
01435 }
01436 if (pos == 25)
01437 {
01438
01439 while (str[0] >= '0' && str[0] <= '9')
01440 {
01441 ++str;
01442 }
01443 }
01444 else
01445 {
01446 while (pos < 25)
01447 {
01448 remainder *= 10;
01449 f_part <<= 1;
01450
01451
01452 if (remainder >= float_coeff_table[pos])
01453 {
01454 remainder -= float_coeff_table[pos];
01455 f_part |= 1;
01456 }
01457 ++pos;
01458 }
01459 }
01460 pos = 0;
01461 while (pos < 36)
01462 {
01463 f_part <<= 1;
01464
01465 if (remainder >= float_coeff_table_2[pos])
01466 {
01467 remainder -= float_coeff_table_2[pos];
01468 f_part |= 1;
01469 }
01470 ++pos;
01471 }
01472 }
01473
01474 F64 ret = F64(int_part) + (F64(f_part)/F64(1LL<<61));
01475
01476 F64 exponent = 1.f;
01477 if (str[0] == 'e')
01478 {
01479
01480 ++str;
01481 U64 exp;
01482 BOOL is_negative;
01483 str = parseInteger(str, &exp, &is_negative, 64, ENCODING_DECIMAL);
01484 if (str == NULL)
01485 {
01486 exp = 1;
01487 }
01488 F64 exp_d = F64(exp) * (is_negative?-1:1);
01489 exponent = pow(10.0, exp_d);
01490 }
01491
01492 if (str == base_str)
01493 {
01494
01495 return NULL;
01496 }
01497 else
01498 {
01499 *dest = ret*negative*exponent;
01500 return str;
01501 }
01502 }
01503 if (encoding == ENCODING_HEX)
01504 {
01505 U64 bytes_dest;
01506 BOOL is_negative;
01507 str = parseInteger(str, (U64 *)&bytes_dest, &is_negative, precision, ENCODING_HEX);
01508
01509 switch (precision)
01510 {
01511 case 32:
01512 {
01513 U32 short_dest = (U32)bytes_dest;
01514 F32 ret_val = *(F32 *)&short_dest;
01515 *dest = ret_val;
01516 }
01517 break;
01518 case 64:
01519 *dest = *(F64 *)&bytes_dest;
01520 break;
01521 default:
01522 return NULL;
01523 }
01524 return str;
01525 }
01526 return NULL;
01527 }
01528
01529 U32 LLXMLNode::getBoolValue(U32 expected_length, BOOL *array)
01530 {
01531 llassert(array);
01532
01533
01534 if (mType != TYPE_BOOLEAN && mType != TYPE_STRING && mType != TYPE_UNKNOWN)
01535 {
01536 return 0;
01537 }
01538
01539 LLString *str_array = new LLString[expected_length];
01540
01541 U32 length = getStringValue(expected_length, str_array);
01542
01543 U32 ret_length = 0;
01544 for (U32 i=0; i<length; ++i)
01545 {
01546 LLString::toLower(str_array[i]);
01547 if (str_array[i] == "false")
01548 {
01549 array[ret_length++] = FALSE;
01550 }
01551 else if (str_array[i] == "true")
01552 {
01553 array[ret_length++] = TRUE;
01554 }
01555 }
01556
01557 delete[] str_array;
01558
01559 #if LL_DEBUG
01560 if (ret_length != expected_length)
01561 {
01562 lldebugs << "LLXMLNode::getBoolValue() failed for node named '"
01563 << mName->mString << "' -- expected " << expected_length << " but "
01564 << "only found " << ret_length << llendl;
01565 }
01566 #endif
01567 return ret_length;
01568 }
01569
01570 U32 LLXMLNode::getByteValue(U32 expected_length, U8 *array, Encoding encoding)
01571 {
01572 llassert(array);
01573
01574
01575 if (mType != TYPE_INTEGER
01576 && mType != TYPE_UNKNOWN)
01577 {
01578 return 0;
01579 }
01580
01581 if (mLength > 0 && mLength != expected_length)
01582 {
01583 llwarns << "XMLNode::getByteValue asked for " << expected_length
01584 << " elements, while node has " << mLength << llendl;
01585 return 0;
01586 }
01587
01588 if (encoding == ENCODING_DEFAULT)
01589 {
01590 encoding = mEncoding;
01591 }
01592
01593 const char *value_string = mValue.c_str();
01594
01595 U32 i;
01596 for (i=0; i<expected_length; ++i)
01597 {
01598 U64 value;
01599 BOOL is_negative;
01600 value_string = parseInteger(value_string, &value, &is_negative, 8, encoding);
01601 if (value_string == NULL)
01602 {
01603 break;
01604 }
01605 if (value > 255 || is_negative)
01606 {
01607 llwarns << "getByteValue: Value outside of valid range." << llendl;
01608 break;
01609 }
01610 array[i] = U8(value);
01611 }
01612 #if LL_DEBUG
01613 if (i != expected_length)
01614 {
01615 lldebugs << "LLXMLNode::getByteValue() failed for node named '"
01616 << mName->mString << "' -- expected " << expected_length << " but "
01617 << "only found " << i << llendl;
01618 }
01619 #endif
01620 return i;
01621 }
01622
01623 U32 LLXMLNode::getIntValue(U32 expected_length, S32 *array, Encoding encoding)
01624 {
01625 llassert(array);
01626
01627
01628 if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN)
01629 {
01630 return 0;
01631 }
01632
01633 if (mLength > 0 && mLength != expected_length)
01634 {
01635 llwarns << "XMLNode::getIntValue asked for " << expected_length
01636 << " elements, while node has " << mLength << llendl;
01637 return 0;
01638 }
01639
01640 if (encoding == ENCODING_DEFAULT)
01641 {
01642 encoding = mEncoding;
01643 }
01644
01645 const char *value_string = mValue.c_str();
01646
01647 U32 i = 0;
01648 for (i=0; i<expected_length; ++i)
01649 {
01650 U64 value;
01651 BOOL is_negative;
01652 value_string = parseInteger(value_string, &value, &is_negative, 32, encoding);
01653 if (value_string == NULL)
01654 {
01655 break;
01656 }
01657 if (value > 0x7fffffff)
01658 {
01659 llwarns << "getIntValue: Value outside of valid range." << llendl;
01660 break;
01661 }
01662 array[i] = S32(value) * (is_negative?-1:1);
01663 }
01664
01665 #if LL_DEBUG
01666 if (i != expected_length)
01667 {
01668 lldebugs << "LLXMLNode::getIntValue() failed for node named '"
01669 << mName->mString << "' -- expected " << expected_length << " but "
01670 << "only found " << i << llendl;
01671 }
01672 #endif
01673 return i;
01674 }
01675
01676 U32 LLXMLNode::getUnsignedValue(U32 expected_length, U32 *array, Encoding encoding)
01677 {
01678 llassert(array);
01679
01680
01681 if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN)
01682 {
01683 return 0;
01684 }
01685
01686 if (mLength > 0 && mLength != expected_length)
01687 {
01688 llwarns << "XMLNode::getUnsignedValue asked for " << expected_length
01689 << " elements, while node has " << mLength << llendl;
01690 return 0;
01691 }
01692
01693 if (encoding == ENCODING_DEFAULT)
01694 {
01695 encoding = mEncoding;
01696 }
01697
01698 const char *value_string = mValue.c_str();
01699
01700 U32 i = 0;
01701
01702 for (i=0; i<expected_length; ++i)
01703 {
01704 U64 value;
01705 BOOL is_negative;
01706 value_string = parseInteger(value_string, &value, &is_negative, 32, encoding);
01707 if (value_string == NULL)
01708 {
01709 break;
01710 }
01711 if (is_negative || value > 0xffffffff)
01712 {
01713 llwarns << "getUnsignedValue: Value outside of valid range." << llendl;
01714 break;
01715 }
01716 array[i] = U32(value);
01717 }
01718
01719 #if LL_DEBUG
01720 if (i != expected_length)
01721 {
01722 lldebugs << "LLXMLNode::getUnsignedValue() failed for node named '"
01723 << mName->mString << "' -- expected " << expected_length << " but "
01724 << "only found " << i << llendl;
01725 }
01726 #endif
01727
01728 return i;
01729 }
01730
01731 U32 LLXMLNode::getLongValue(U32 expected_length, U64 *array, Encoding encoding)
01732 {
01733 llassert(array);
01734
01735
01736 if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN)
01737 {
01738 return 0;
01739 }
01740
01741 if (mLength > 0 && mLength != expected_length)
01742 {
01743 llwarns << "XMLNode::getLongValue asked for " << expected_length << " elements, while node has " << mLength << llendl;
01744 return 0;
01745 }
01746
01747 if (encoding == ENCODING_DEFAULT)
01748 {
01749 encoding = mEncoding;
01750 }
01751
01752 const char *value_string = mValue.c_str();
01753
01754 U32 i = 0;
01755
01756 for (i=0; i<expected_length; ++i)
01757 {
01758 U64 value;
01759 BOOL is_negative;
01760 value_string = parseInteger(value_string, &value, &is_negative, 64, encoding);
01761 if (value_string == NULL)
01762 {
01763 break;
01764 }
01765 if (is_negative)
01766 {
01767 llwarns << "getLongValue: Value outside of valid range." << llendl;
01768 break;
01769 }
01770 array[i] = value;
01771 }
01772
01773 #if LL_DEBUG
01774 if (i != expected_length)
01775 {
01776 lldebugs << "LLXMLNode::getLongValue() failed for node named '"
01777 << mName->mString << "' -- expected " << expected_length << " but "
01778 << "only found " << i << llendl;
01779 }
01780 #endif
01781
01782 return i;
01783 }
01784
01785 U32 LLXMLNode::getFloatValue(U32 expected_length, F32 *array, Encoding encoding)
01786 {
01787 llassert(array);
01788
01789
01790 if (mType != TYPE_FLOAT && mType != TYPE_UNKNOWN)
01791 {
01792 return 0;
01793 }
01794
01795 if (mLength > 0 && mLength != expected_length)
01796 {
01797 llwarns << "XMLNode::getFloatValue asked for " << expected_length << " elements, while node has " << mLength << llendl;
01798 return 0;
01799 }
01800
01801 if (encoding == ENCODING_DEFAULT)
01802 {
01803 encoding = mEncoding;
01804 }
01805
01806 const char *value_string = mValue.c_str();
01807
01808 U32 i;
01809 for (i=0; i<expected_length; ++i)
01810 {
01811 F64 value;
01812 value_string = parseFloat(value_string, &value, 32, encoding);
01813 if (value_string == NULL)
01814 {
01815 break;
01816 }
01817 array[i] = F32(value);
01818 }
01819 #if LL_DEBUG
01820 if (i != expected_length)
01821 {
01822 lldebugs << "LLXMLNode::getFloatValue() failed for node named '"
01823 << mName->mString << "' -- expected " << expected_length << " but "
01824 << "only found " << i << llendl;
01825 }
01826 #endif
01827 return i;
01828 }
01829
01830 U32 LLXMLNode::getDoubleValue(U32 expected_length, F64 *array, Encoding encoding)
01831 {
01832 llassert(array);
01833
01834
01835 if (mType != TYPE_FLOAT && mType != TYPE_UNKNOWN)
01836 {
01837 return 0;
01838 }
01839
01840 if (mLength > 0 && mLength != expected_length)
01841 {
01842 llwarns << "XMLNode::getDoubleValue asked for " << expected_length << " elements, while node has " << mLength << llendl;
01843 return 0;
01844 }
01845
01846 if (encoding == ENCODING_DEFAULT)
01847 {
01848 encoding = mEncoding;
01849 }
01850
01851 const char *value_string = mValue.c_str();
01852
01853 U32 i;
01854 for (i=0; i<expected_length; ++i)
01855 {
01856 F64 value;
01857 value_string = parseFloat(value_string, &value, 64, encoding);
01858 if (value_string == NULL)
01859 {
01860 break;
01861 }
01862 array[i] = value;
01863 }
01864 #if LL_DEBUG
01865 if (i != expected_length)
01866 {
01867 lldebugs << "LLXMLNode::getDoubleValue() failed for node named '"
01868 << mName->mString << "' -- expected " << expected_length << " but "
01869 << "only found " << i << llendl;
01870 }
01871 #endif
01872 return i;
01873 }
01874
01875 U32 LLXMLNode::getStringValue(U32 expected_length, LLString *array)
01876 {
01877 llassert(array);
01878
01879
01880
01881 if (mLength > 0 && mLength != expected_length)
01882 {
01883 llwarns << "XMLNode::getStringValue asked for " << expected_length << " elements, while node has " << mLength << llendl;
01884 return 0;
01885 }
01886
01887 U32 num_returned_strings = 0;
01888
01889
01890 const std::string sep(" \n\t");
01891
01892 std::string::size_type n = 0;
01893 std::string::size_type m = 0;
01894 while(1)
01895 {
01896 if (num_returned_strings >= expected_length)
01897 {
01898 break;
01899 }
01900 n = mValue.find_first_not_of(sep, m);
01901 m = mValue.find_first_of(sep, n);
01902 if (m == std::string::npos)
01903 {
01904 break;
01905 }
01906 array[num_returned_strings++] = mValue.substr(n,m-n);
01907 }
01908 if (n != std::string::npos && num_returned_strings < expected_length)
01909 {
01910 array[num_returned_strings++] = mValue.substr(n);
01911 }
01912 #if LL_DEBUG
01913 if (num_returned_strings != expected_length)
01914 {
01915 lldebugs << "LLXMLNode::getStringValue() failed for node named '"
01916 << mName->mString << "' -- expected " << expected_length << " but "
01917 << "only found " << num_returned_strings << llendl;
01918 }
01919 #endif
01920
01921 return num_returned_strings;
01922 }
01923
01924 U32 LLXMLNode::getUUIDValue(U32 expected_length, LLUUID *array)
01925 {
01926 llassert(array);
01927
01928
01929 if (mType != TYPE_UUID && mType != TYPE_UNKNOWN)
01930 {
01931 return 0;
01932 }
01933
01934 const char *value_string = mValue.c_str();
01935
01936 U32 i;
01937 for (i=0; i<expected_length; ++i)
01938 {
01939 LLUUID uuid_value;
01940 value_string = skipWhitespace(value_string);
01941
01942 if (strlen(value_string) < (UUID_STR_LENGTH-1))
01943 {
01944 break;
01945 }
01946 char uuid_string[UUID_STR_LENGTH];
01947 memcpy(uuid_string, value_string, (UUID_STR_LENGTH-1));
01948 uuid_string[(UUID_STR_LENGTH-1)] = 0;
01949
01950 if (!LLUUID::parseUUID(uuid_string, &uuid_value))
01951 {
01952 break;
01953 }
01954 value_string = &value_string[(UUID_STR_LENGTH-1)];
01955 array[i] = uuid_value;
01956 }
01957 #if LL_DEBUG
01958 if (i != expected_length)
01959 {
01960 lldebugs << "LLXMLNode::getUUIDValue() failed for node named '"
01961 << mName->mString << "' -- expected " << expected_length << " but "
01962 << "only found " << i << llendl;
01963 }
01964 #endif
01965 return i;
01966 }
01967
01968 U32 LLXMLNode::getNodeRefValue(U32 expected_length, LLXMLNode **array)
01969 {
01970 llassert(array);
01971
01972
01973 if (mType != TYPE_NODEREF && mType != TYPE_UNKNOWN)
01974 {
01975 return 0;
01976 }
01977
01978 LLString *string_array = new LLString[expected_length];
01979
01980 U32 num_strings = getStringValue(expected_length, string_array);
01981
01982 U32 num_returned_refs = 0;
01983
01984 LLXMLNodePtr root = getRoot();
01985 for (U32 strnum=0; strnum<num_strings; ++strnum)
01986 {
01987 LLXMLNodeList node_list;
01988 root->findID(string_array[strnum], node_list);
01989 if (node_list.empty())
01990 {
01991 llwarns << "XML: Could not find node ID: " << string_array[strnum] << llendl;
01992 }
01993 else if (node_list.size() > 1)
01994 {
01995 llwarns << "XML: Node ID not unique: " << string_array[strnum] << llendl;
01996 }
01997 else
01998 {
01999 LLXMLNodeList::const_iterator list_itr = node_list.begin();
02000 if (list_itr != node_list.end())
02001 {
02002 LLXMLNode* child = (*list_itr).second;
02003
02004 array[num_returned_refs++] = child;
02005 }
02006 }
02007 }
02008
02009 delete[] string_array;
02010
02011 return num_returned_refs;
02012 }
02013
02014 void LLXMLNode::setBoolValue(U32 length, const BOOL *array)
02015 {
02016 if (length == 0) return;
02017
02018 LLString new_value;
02019 for (U32 pos=0; pos<length; ++pos)
02020 {
02021 if (pos > 0)
02022 {
02023 new_value = llformat("%s %s", new_value.c_str(), array[pos]?"true":"false");
02024 }
02025 else
02026 {
02027 new_value = array[pos]?"true":"false";
02028 }
02029 }
02030
02031 mValue = new_value;
02032 mEncoding = ENCODING_DEFAULT;
02033 mLength = length;
02034 mType = TYPE_BOOLEAN;
02035 }
02036
02037 void LLXMLNode::setByteValue(U32 length, const U8* const array, Encoding encoding)
02038 {
02039 if (length == 0) return;
02040
02041 LLString new_value;
02042 if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
02043 {
02044 for (U32 pos=0; pos<length; ++pos)
02045 {
02046 if (pos > 0)
02047 {
02048 new_value.append(llformat(" %u", array[pos]));
02049 }
02050 else
02051 {
02052 new_value = llformat("%u", array[pos]);
02053 }
02054 }
02055 }
02056 if (encoding == ENCODING_HEX)
02057 {
02058 for (U32 pos=0; pos<length; ++pos)
02059 {
02060 if (pos > 0 && pos % 16 == 0)
02061 {
02062 new_value.append(llformat(" %02X", array[pos]));
02063 }
02064 else
02065 {
02066 new_value.append(llformat("%02X", array[pos]));
02067 }
02068 }
02069 }
02070
02071
02072 mValue = new_value;
02073 mEncoding = encoding;
02074 mLength = length;
02075 mType = TYPE_INTEGER;
02076 mPrecision = 8;
02077 }
02078
02079
02080 void LLXMLNode::setIntValue(U32 length, const S32 *array, Encoding encoding)
02081 {
02082 if (length == 0) return;
02083
02084 LLString new_value;
02085 if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
02086 {
02087 for (U32 pos=0; pos<length; ++pos)
02088 {
02089 if (pos > 0)
02090 {
02091 new_value.append(llformat(" %d", array[pos]));
02092 }
02093 else
02094 {
02095 new_value = llformat("%d", array[pos]);
02096 }
02097 }
02098 mValue = new_value;
02099 }
02100 else if (encoding == ENCODING_HEX)
02101 {
02102 for (U32 pos=0; pos<length; ++pos)
02103 {
02104 if (pos > 0 && pos % 16 == 0)
02105 {
02106 new_value.append(llformat(" %08X", ((U32 *)array)[pos]));
02107 }
02108 else
02109 {
02110 new_value.append(llformat("%08X", ((U32 *)array)[pos]));
02111 }
02112 }
02113 mValue = new_value;
02114 }
02115 else
02116 {
02117 mValue = new_value;
02118 }
02119
02120
02121 mEncoding = encoding;
02122 mLength = length;
02123 mType = TYPE_INTEGER;
02124 mPrecision = 32;
02125 }
02126
02127 void LLXMLNode::setUnsignedValue(U32 length, const U32* array, Encoding encoding)
02128 {
02129 if (length == 0) return;
02130
02131 LLString new_value;
02132 if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
02133 {
02134 for (U32 pos=0; pos<length; ++pos)
02135 {
02136 if (pos > 0)
02137 {
02138 new_value.append(llformat(" %u", array[pos]));
02139 }
02140 else
02141 {
02142 new_value = llformat("%u", array[pos]);
02143 }
02144 }
02145 }
02146 if (encoding == ENCODING_HEX)
02147 {
02148 for (U32 pos=0; pos<length; ++pos)
02149 {
02150 if (pos > 0 && pos % 16 == 0)
02151 {
02152 new_value.append(llformat(" %08X", array[pos]));
02153 }
02154 else
02155 {
02156 new_value.append(llformat("%08X", array[pos]));
02157 }
02158 }
02159 mValue = new_value;
02160 }
02161
02162
02163 mValue = new_value;
02164 mEncoding = encoding;
02165 mLength = length;
02166 mType = TYPE_INTEGER;
02167 mPrecision = 32;
02168 }
02169
02170 #if LL_WINDOWS
02171 #define PU64 "I64u"
02172 #else
02173 #define PU64 "llu"
02174 #endif
02175
02176 void LLXMLNode::setLongValue(U32 length, const U64* array, Encoding encoding)
02177 {
02178 if (length == 0) return;
02179
02180 LLString new_value;
02181 if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
02182 {
02183 for (U32 pos=0; pos<length; ++pos)
02184 {
02185 if (pos > 0)
02186 {
02187 new_value.append(llformat(" %" PU64, array[pos]));
02188 }
02189 else
02190 {
02191 new_value = llformat("%" PU64, array[pos]);
02192 }
02193 }
02194 mValue = new_value;
02195 }
02196 if (encoding == ENCODING_HEX)
02197 {
02198 for (U32 pos=0; pos<length; ++pos)
02199 {
02200 U32 upper_32 = U32(array[pos]>>32);
02201 U32 lower_32 = U32(array[pos]&0xffffffff);
02202 if (pos > 0 && pos % 8 == 0)
02203 {
02204 new_value.append(llformat(" %08X%08X", upper_32, lower_32));
02205 }
02206 else
02207 {
02208 new_value.append(llformat("%08X%08X", upper_32, lower_32));
02209 }
02210 }
02211 mValue = new_value;
02212 }
02213 else
02214 {
02215 mValue = new_value;
02216 }
02217
02218
02219 mEncoding = encoding;
02220 mLength = length;
02221 mType = TYPE_INTEGER;
02222 mPrecision = 64;
02223 }
02224
02225 void LLXMLNode::setFloatValue(U32 length, const F32 *array, Encoding encoding, U32 precision)
02226 {
02227 if (length == 0) return;
02228
02229 LLString new_value;
02230 if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
02231 {
02232 char format_string[10];
02233 if (precision > 0)
02234 {
02235 if (precision > 25)
02236 {
02237 precision = 25;
02238 }
02239 snprintf(format_string, sizeof(format_string), "%%.%dg", precision);
02240 }
02241 else
02242 {
02243 snprintf(format_string, sizeof(format_string), "%%g");
02244 }
02245
02246 for (U32 pos=0; pos<length; ++pos)
02247 {
02248 if (pos > 0)
02249 {
02250 new_value.append(" ");
02251 new_value.append(llformat(format_string, array[pos]));
02252 }
02253 else
02254 {
02255 new_value.assign(llformat(format_string, array[pos]));
02256 }
02257 }
02258 mValue = new_value;
02259 }
02260 else if (encoding == ENCODING_HEX)
02261 {
02262 U32 *byte_array = (U32 *)array;
02263 setUnsignedValue(length, byte_array, ENCODING_HEX);
02264 }
02265 else
02266 {
02267 mValue = new_value;
02268 }
02269
02270 mEncoding = encoding;
02271 mLength = length;
02272 mType = TYPE_FLOAT;
02273 mPrecision = 32;
02274 }
02275
02276 void LLXMLNode::setDoubleValue(U32 length, const F64 *array, Encoding encoding, U32 precision)
02277 {
02278 if (length == 0) return;
02279
02280 LLString new_value;
02281 if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
02282 {
02283 char format_string[10];
02284 if (precision > 0)
02285 {
02286 if (precision > 25)
02287 {
02288 precision = 25;
02289 }
02290 snprintf(format_string, sizeof(format_string), "%%.%dg", precision);
02291 }
02292 else
02293 {
02294 snprintf(format_string, sizeof(format_string), "%%g");
02295 }
02296 for (U32 pos=0; pos<length; ++pos)
02297 {
02298 if (pos > 0)
02299 {
02300 new_value.append(" ");
02301 new_value.append(llformat(format_string, array[pos]));
02302 }
02303 else
02304 {
02305 new_value.assign(llformat(format_string, array[pos]));
02306 }
02307 }
02308 mValue = new_value;
02309 }
02310 if (encoding == ENCODING_HEX)
02311 {
02312 U64 *byte_array = (U64 *)array;
02313 setLongValue(length, byte_array, ENCODING_HEX);
02314 }
02315 else
02316 {
02317 mValue = new_value;
02318 }
02319
02320
02321 mEncoding = encoding;
02322 mLength = length;
02323 mType = TYPE_FLOAT;
02324 mPrecision = 64;
02325 }
02326
02327
02328 LLString LLXMLNode::escapeXML(const LLString& xml)
02329 {
02330 LLString out;
02331 for (LLString::size_type i = 0; i < xml.size(); ++i)
02332 {
02333 char c = xml[i];
02334 switch(c)
02335 {
02336 case '"': out.append("""); break;
02337 case '\'': out.append("'"); break;
02338 case '&': out.append("&"); break;
02339 case '<': out.append("<"); break;
02340 case '>': out.append(">"); break;
02341 default: out.push_back(c); break;
02342 }
02343 }
02344 return out;
02345 }
02346
02347 void LLXMLNode::setStringValue(U32 length, const LLString *array)
02348 {
02349 if (length == 0) return;
02350
02351 LLString new_value;
02352 for (U32 pos=0; pos<length; ++pos)
02353 {
02354 new_value.append(escapeXML(array[pos]));
02355 if (pos < length-1) new_value.append(" ");
02356 }
02357
02358 mValue = new_value;
02359 mEncoding = ENCODING_DEFAULT;
02360 mLength = length;
02361 mType = TYPE_STRING;
02362 }
02363
02364 void LLXMLNode::setUUIDValue(U32 length, const LLUUID *array)
02365 {
02366 if (length == 0) return;
02367
02368 LLString new_value;
02369 for (U32 pos=0; pos<length; ++pos)
02370 {
02371 new_value.append(array[pos].asString());
02372 if (pos < length-1) new_value.append(" ");
02373 }
02374
02375 mValue = new_value;
02376 mEncoding = ENCODING_DEFAULT;
02377 mLength = length;
02378 mType = TYPE_UUID;
02379 }
02380
02381 void LLXMLNode::setNodeRefValue(U32 length, const LLXMLNode **array)
02382 {
02383 if (length == 0) return;
02384
02385 LLString new_value;
02386 for (U32 pos=0; pos<length; ++pos)
02387 {
02388 if (array[pos]->mID != "")
02389 {
02390 new_value.append(array[pos]->mID);
02391 }
02392 else
02393 {
02394 new_value.append("(null)");
02395 }
02396 if (pos < length-1) new_value.append(" ");
02397 }
02398
02399 mValue = new_value;
02400 mEncoding = ENCODING_DEFAULT;
02401 mLength = length;
02402 mType = TYPE_NODEREF;
02403 }
02404
02405 void LLXMLNode::setValue(const LLString& value)
02406 {
02407 if (TYPE_CONTAINER == mType)
02408 {
02409 mType = TYPE_UNKNOWN;
02410 }
02411 mValue = value;
02412 }
02413
02414 void LLXMLNode::setDefault(LLXMLNode *default_node)
02415 {
02416 mDefault = default_node;
02417 }
02418
02419 void LLXMLNode::findDefault(LLXMLNode *defaults_list)
02420 {
02421 if (defaults_list)
02422 {
02423 LLXMLNodeList children;
02424 defaults_list->getChildren(mName->mString, children);
02425
02426 LLXMLNodeList::const_iterator children_itr;
02427 LLXMLNodeList::const_iterator children_end = children.end();
02428 for (children_itr = children.begin(); children_itr != children_end; ++children_itr)
02429 {
02430 LLXMLNode* child = (*children_itr).second;
02431 if (child->mVersionMajor == mVersionMajor &&
02432 child->mVersionMinor == mVersionMinor)
02433 {
02434 mDefault = child;
02435 return;
02436 }
02437 }
02438 }
02439 mDefault = NULL;
02440 }
02441
02442 BOOL LLXMLNode::deleteChildren(const LLString& name)
02443 {
02444 U32 removed_count = 0;
02445 LLXMLNodeList node_list;
02446 findName(name, node_list);
02447 if (!node_list.empty())
02448 {
02449
02450
02451 LLXMLNodeList::iterator children_itr;
02452 for (children_itr = node_list.begin(); children_itr != node_list.end(); ++children_itr)
02453 {
02454 LLXMLNode* child = (*children_itr).second;
02455 if (deleteChild(child))
02456 {
02457 removed_count++;
02458 }
02459 }
02460 }
02461 return removed_count > 0 ? TRUE : FALSE;
02462 }
02463
02464 BOOL LLXMLNode::deleteChildren(LLStringTableEntry* name)
02465 {
02466 U32 removed_count = 0;
02467 LLXMLNodeList node_list;
02468 findName(name, node_list);
02469 if (!node_list.empty())
02470 {
02471
02472
02473 LLXMLNodeList::iterator children_itr;
02474 for (children_itr = node_list.begin(); children_itr != node_list.end(); ++children_itr)
02475 {
02476 LLXMLNode* child = (*children_itr).second;
02477 if (deleteChild(child))
02478 {
02479 removed_count++;
02480 }
02481 }
02482 }
02483 return removed_count > 0 ? TRUE : FALSE;
02484 }
02485
02486 void LLXMLNode::setAttributes(LLXMLNode::ValueType type, U32 precision, LLXMLNode::Encoding encoding, U32 length)
02487 {
02488 mType = type;
02489 mEncoding = encoding;
02490 mPrecision = precision;
02491 mLength = length;
02492 }
02493
02494 void LLXMLNode::setName(const LLString& name)
02495 {
02496 setName(gStringTable.addStringEntry(name));
02497 }
02498
02499 void LLXMLNode::setName(LLStringTableEntry* name)
02500 {
02501 LLXMLNode* old_parent = mParent;
02502 if (mParent)
02503 {
02504
02505
02506 mParent->removeChild(this);
02507 }
02508 mName = name;
02509 if (old_parent)
02510 {
02511 old_parent->addChild(this);
02512 }
02513 }
02514
02515 void LLXMLNode::appendValue(const LLString& value)
02516 {
02517 mValue.append(value);
02518 }
02519
02520 U32 LLXMLNode::getChildCount() const
02521 {
02522 if (mChildren)
02523 {
02524 return mChildren->map.size();
02525 }
02526 return 0;
02527 }
02528
02529
02530
02531
02532
02533 U32 get_rand(U32 max_value)
02534 {
02535 U32 random_num = rand() + ((U32)rand() << 16);
02536 return (random_num % max_value);
02537 }
02538
02539 LLXMLNode *get_rand_node(LLXMLNode *node)
02540 {
02541 if (node->mChildren)
02542 {
02543 U32 num_children = node->mChildren->map.size();
02544 if (get_rand(2) == 0)
02545 {
02546 while (true)
02547 {
02548 S32 child_num = S32(get_rand(num_children*2)) - num_children;
02549 LLXMLChildList::iterator itor = node->mChildren->map.begin();
02550 while (child_num > 0)
02551 {
02552 --child_num;
02553 ++itor;
02554 }
02555 if (!itor->second->mIsAttribute)
02556 {
02557 return get_rand_node(itor->second);
02558 }
02559 }
02560 }
02561 }
02562 return node;
02563 }
02564
02565 void LLXMLNode::createUnitTest(S32 max_num_children)
02566 {
02567
02568 char rand_id[20];
02569 U32 rand_id_len = get_rand(10)+5;
02570 U32 pos = 0;
02571 for (; pos<rand_id_len; ++pos)
02572 {
02573 rand_id[pos] = get_rand(26)+'a';
02574 }
02575 rand_id[pos] = 0;
02576 mID = rand_id;
02577
02578 if (max_num_children < 2)
02579 {
02580 setStringValue(1, &mID);
02581 return;
02582 }
02583
02584
02585 U32 integer_checksum = 0;
02586 U64 long_checksum = 0;
02587 U32 bool_true_count = 0;
02588 LLUUID uuid_checksum;
02589 U32 noderef_checksum = 0;
02590 U32 float_checksum = 0;
02591
02592
02593 U32 num_children = get_rand(max_num_children)+1;
02594 for (U32 child_num=0; child_num<num_children; ++child_num)
02595 {
02596
02597 char child_name[20];
02598 U32 child_name_len = get_rand(10)+5;
02599 pos = 0;
02600 for (; pos<child_name_len; ++pos)
02601 {
02602 child_name[pos] = get_rand(26)+'a';
02603 }
02604 child_name[pos] = 0;
02605
02606 LLXMLNode *new_child = createChild(child_name, FALSE);
02607
02608
02609 char child_id[20];
02610 U32 child_id_len = get_rand(10)+5;
02611 pos = 0;
02612 for (; pos<child_id_len; ++pos)
02613 {
02614 child_id[pos] = get_rand(26)+'a';
02615 }
02616 child_id[pos] = 0;
02617 new_child->mID = child_id;
02618
02619
02620 U32 array_size = get_rand(28)+1;
02621
02622
02623 Encoding new_encoding = get_rand(2)?ENCODING_DECIMAL:ENCODING_HEX;
02624
02625
02626 int type = get_rand(8);
02627 switch (type)
02628 {
02629 case 0:
02630 new_child->createUnitTest(max_num_children/2);
02631 break;
02632 case 1:
02633 {
02634 BOOL random_bool_values[30];
02635 for (U32 value=0; value<array_size; ++value)
02636 {
02637 random_bool_values[value] = get_rand(2);
02638 if (random_bool_values[value])
02639 {
02640 ++bool_true_count;
02641 }
02642 }
02643 new_child->setBoolValue(array_size, random_bool_values);
02644 }
02645 break;
02646 case 2:
02647 {
02648 U32 random_int_values[30];
02649 for (U32 value=0; value<array_size; ++value)
02650 {
02651 random_int_values[value] = get_rand(0xffffffff);
02652 integer_checksum ^= random_int_values[value];
02653 }
02654 new_child->setUnsignedValue(array_size, random_int_values, new_encoding);
02655 }
02656 break;
02657 case 3:
02658 {
02659 U64 random_int_values[30];
02660 for (U64 value=0; value<array_size; ++value)
02661 {
02662 random_int_values[value] = (U64(get_rand(0xffffffff)) << 32) + get_rand(0xffffffff);
02663 long_checksum ^= random_int_values[value];
02664 }
02665 new_child->setLongValue(array_size, random_int_values, new_encoding);
02666 }
02667 break;
02668 case 4:
02669 {
02670 F32 random_float_values[30];
02671 for (U32 value=0; value<array_size; ++value)
02672 {
02673 S32 exponent = get_rand(256) - 128;
02674 S32 fractional_part = get_rand(0xffffffff);
02675 S32 sign = get_rand(2) * 2 - 1;
02676 random_float_values[value] = F32(fractional_part) / F32(0xffffffff) * exp(F32(exponent)) * F32(sign);
02677
02678 U32 *float_bits = &((U32 *)random_float_values)[value];
02679 if (*float_bits == 0x80000000)
02680 {
02681 *float_bits = 0x00000000;
02682 }
02683 float_checksum ^= (*float_bits & 0xfffff000);
02684 }
02685 new_child->setFloatValue(array_size, random_float_values, new_encoding, 12);
02686 }
02687 break;
02688 case 5:
02689 {
02690 F64 random_float_values[30];
02691 for (U32 value=0; value<array_size; ++value)
02692 {
02693 S32 exponent = get_rand(2048) - 1024;
02694 S32 fractional_part = get_rand(0xffffffff);
02695 S32 sign = get_rand(2) * 2 - 1;
02696 random_float_values[value] = F64(fractional_part) / F64(0xffffffff) * exp(F64(exponent)) * F64(sign);
02697
02698 U64 *float_bits = &((U64 *)random_float_values)[value];
02699 if (*float_bits == 0x8000000000000000ll)
02700 {
02701 *float_bits = 0x0000000000000000ll;
02702 }
02703 float_checksum ^= ((*float_bits & 0xfffffff000000000ll) >> 32);
02704 }
02705 new_child->setDoubleValue(array_size, random_float_values, new_encoding, 12);
02706 }
02707 break;
02708 case 6:
02709 {
02710 LLUUID random_uuid_values[30];
02711 for (U32 value=0; value<array_size; ++value)
02712 {
02713 random_uuid_values[value].generate();
02714 for (S32 byte=0; byte<UUID_BYTES; ++byte)
02715 {
02716 uuid_checksum.mData[byte] ^= random_uuid_values[value].mData[byte];
02717 }
02718 }
02719 new_child->setUUIDValue(array_size, random_uuid_values);
02720 }
02721 break;
02722 case 7:
02723 {
02724 LLXMLNode *random_node_array[30];
02725 LLXMLNode *root = getRoot();
02726 for (U32 value=0; value<array_size; ++value)
02727 {
02728 random_node_array[value] = get_rand_node(root);
02729 const char *node_name = random_node_array[value]->mName->mString;
02730 for (U32 pos=0; pos<strlen(node_name); ++pos)
02731 {
02732 U32 hash_contrib = U32(node_name[pos]) << ((pos % 4) * 8);
02733 noderef_checksum ^= hash_contrib;
02734 }
02735 }
02736 new_child->setNodeRefValue(array_size, (const LLXMLNode **)random_node_array);
02737 }
02738 break;
02739 }
02740 }
02741
02742 createChild("integer_checksum", TRUE)->setUnsignedValue(1, &integer_checksum, LLXMLNode::ENCODING_HEX);
02743 createChild("long_checksum", TRUE)->setLongValue(1, &long_checksum, LLXMLNode::ENCODING_HEX);
02744 createChild("bool_true_count", TRUE)->setUnsignedValue(1, &bool_true_count, LLXMLNode::ENCODING_HEX);
02745 createChild("uuid_checksum", TRUE)->setUUIDValue(1, &uuid_checksum);
02746 createChild("noderef_checksum", TRUE)->setUnsignedValue(1, &noderef_checksum, LLXMLNode::ENCODING_HEX);
02747 createChild("float_checksum", TRUE)->setUnsignedValue(1, &float_checksum, LLXMLNode::ENCODING_HEX);
02748 }
02749
02750 BOOL LLXMLNode::performUnitTest(LLString &error_buffer)
02751 {
02752 if (!mChildren)
02753 {
02754 error_buffer.append(llformat("ERROR Node %s: No children found.\n", mName->mString));
02755 return FALSE;
02756 }
02757
02758
02759 U32 integer_checksum = 0;
02760 U32 bool_true_count = 0;
02761 LLUUID uuid_checksum;
02762 U32 noderef_checksum = 0;
02763 U32 float_checksum = 0;
02764 U64 long_checksum = 0;
02765
02766 LLXMLChildList::iterator itor;
02767 for (itor=mChildren->map.begin(); itor!=mChildren->map.end(); ++itor)
02768 {
02769 LLXMLNode *node = itor->second;
02770 if (node->mIsAttribute)
02771 {
02772 continue;
02773 }
02774 if (node->mType == TYPE_CONTAINER)
02775 {
02776 if (!node->performUnitTest(error_buffer))
02777 {
02778 error_buffer.append(llformat("Child test failed for %s.\n", mName->mString));
02779
02780 }
02781 continue;
02782 }
02783 if (node->mLength < 1 || node->mLength > 30)
02784 {
02785 error_buffer.append(llformat("ERROR Node %s: Invalid array length %d, child %s.\n", mName->mString, node->mLength, node->mName->mString));
02786 return FALSE;
02787 }
02788 switch (node->mType)
02789 {
02790 case TYPE_CONTAINER:
02791 case TYPE_UNKNOWN:
02792 break;
02793 case TYPE_BOOLEAN:
02794 {
02795 BOOL bool_array[30];
02796 if (node->getBoolValue(node->mLength, bool_array) < node->mLength)
02797 {
02798 error_buffer.append(llformat("ERROR Node %s: Could not read boolean array, child %s.\n", mName->mString, node->mName->mString));
02799 return FALSE;
02800 }
02801 for (U32 pos=0; pos<(U32)node->mLength; ++pos)
02802 {
02803 if (bool_array[pos])
02804 {
02805 ++bool_true_count;
02806 }
02807 }
02808 }
02809 break;
02810 case TYPE_INTEGER:
02811 {
02812 if (node->mPrecision == 32)
02813 {
02814 U32 integer_array[30];
02815 if (node->getUnsignedValue(node->mLength, integer_array, node->mEncoding) < node->mLength)
02816 {
02817 error_buffer.append(llformat("ERROR Node %s: Could not read integer array, child %s.\n", mName->mString, node->mName->mString));
02818 return FALSE;
02819 }
02820 for (U32 pos=0; pos<(U32)node->mLength; ++pos)
02821 {
02822 integer_checksum ^= integer_array[pos];
02823 }
02824 }
02825 else
02826 {
02827 U64 integer_array[30];
02828 if (node->getLongValue(node->mLength, integer_array, node->mEncoding) < node->mLength)
02829 {
02830 error_buffer.append(llformat("ERROR Node %s: Could not read long integer array, child %s.\n", mName->mString, node->mName->mString));
02831 return FALSE;
02832 }
02833 for (U32 pos=0; pos<(U32)node->mLength; ++pos)
02834 {
02835 long_checksum ^= integer_array[pos];
02836 }
02837 }
02838 }
02839 break;
02840 case TYPE_FLOAT:
02841 {
02842 if (node->mPrecision == 32)
02843 {
02844 F32 float_array[30];
02845 if (node->getFloatValue(node->mLength, float_array, node->mEncoding) < node->mLength)
02846 {
02847 error_buffer.append(llformat("ERROR Node %s: Could not read float array, child %s.\n", mName->mString, node->mName->mString));
02848 return FALSE;
02849 }
02850 for (U32 pos=0; pos<(U32)node->mLength; ++pos)
02851 {
02852 U32 float_bits = ((U32 *)float_array)[pos];
02853 float_checksum ^= (float_bits & 0xfffff000);
02854 }
02855 }
02856 else
02857 {
02858 F64 float_array[30];
02859 if (node->getDoubleValue(node->mLength, float_array, node->mEncoding) < node->mLength)
02860 {
02861 error_buffer.append(llformat("ERROR Node %s: Could not read float array, child %s.\n", mName->mString, node->mName->mString));
02862 return FALSE;
02863 }
02864 for (U32 pos=0; pos<(U32)node->mLength; ++pos)
02865 {
02866 U64 float_bits = ((U64 *)float_array)[pos];
02867 float_checksum ^= ((float_bits & 0xfffffff000000000ll) >> 32);
02868 }
02869 }
02870 }
02871 break;
02872 case TYPE_STRING:
02873 break;
02874 case TYPE_UUID:
02875 {
02876 LLUUID uuid_array[30];
02877 if (node->getUUIDValue(node->mLength, uuid_array) < node->mLength)
02878 {
02879 error_buffer.append(llformat("ERROR Node %s: Could not read uuid array, child %s.\n", mName->mString, node->mName->mString));
02880 return FALSE;
02881 }
02882 for (U32 pos=0; pos<(U32)node->mLength; ++pos)
02883 {
02884 for (S32 byte=0; byte<UUID_BYTES; ++byte)
02885 {
02886 uuid_checksum.mData[byte] ^= uuid_array[pos].mData[byte];
02887 }
02888 }
02889 }
02890 break;
02891 case TYPE_NODEREF:
02892 {
02893 LLXMLNode *node_array[30];
02894 if (node->getNodeRefValue(node->mLength, node_array) < node->mLength)
02895 {
02896 error_buffer.append(llformat("ERROR Node %s: Could not read node ref array, child %s.\n", mName->mString, node->mName->mString));
02897 return FALSE;
02898 }
02899 for (U32 pos=0; pos<node->mLength; ++pos)
02900 {
02901 const char *node_name = node_array[pos]->mName->mString;
02902 for (U32 pos2=0; pos2<strlen(node_name); ++pos2)
02903 {
02904 U32 hash_contrib = U32(node_name[pos2]) << ((pos2 % 4) * 8);
02905 noderef_checksum ^= hash_contrib;
02906 }
02907 }
02908 }
02909 break;
02910 }
02911 }
02912
02913 LLXMLNodePtr checksum_node;
02914
02915
02916 {
02917 U32 node_integer_checksum = 0;
02918 if (!getAttribute("integer_checksum", checksum_node, FALSE) ||
02919 checksum_node->getUnsignedValue(1, &node_integer_checksum, ENCODING_HEX) != 1)
02920 {
02921 error_buffer.append(llformat("ERROR Node %s: Integer checksum missing.\n", mName->mString));
02922 return FALSE;
02923 }
02924 if (node_integer_checksum != integer_checksum)
02925 {
02926 error_buffer.append(llformat("ERROR Node %s: Integer checksum mismatch: read %X / calc %X.\n", mName->mString, node_integer_checksum, integer_checksum));
02927 return FALSE;
02928 }
02929 }
02930
02931 {
02932 U64 node_long_checksum = 0;
02933 if (!getAttribute("long_checksum", checksum_node, FALSE) ||
02934 checksum_node->getLongValue(1, &node_long_checksum, ENCODING_HEX) != 1)
02935 {
02936 error_buffer.append(llformat("ERROR Node %s: Long Integer checksum missing.\n", mName->mString));
02937 return FALSE;
02938 }
02939 if (node_long_checksum != long_checksum)
02940 {
02941 U32 *pp1 = (U32 *)&node_long_checksum;
02942 U32 *pp2 = (U32 *)&long_checksum;
02943 error_buffer.append(llformat("ERROR Node %s: Long Integer checksum mismatch: read %08X%08X / calc %08X%08X.\n", mName->mString, pp1[1], pp1[0], pp2[1], pp2[0]));
02944 return FALSE;
02945 }
02946 }
02947
02948 {
02949 U32 node_bool_true_count = 0;
02950 if (!getAttribute("bool_true_count", checksum_node, FALSE) ||
02951 checksum_node->getUnsignedValue(1, &node_bool_true_count, ENCODING_HEX) != 1)
02952 {
02953 error_buffer.append(llformat("ERROR Node %s: Boolean checksum missing.\n", mName->mString));
02954 return FALSE;
02955 }
02956 if (node_bool_true_count != bool_true_count)
02957 {
02958 error_buffer.append(llformat("ERROR Node %s: Boolean checksum mismatch: read %X / calc %X.\n", mName->mString, node_bool_true_count, bool_true_count));
02959 return FALSE;
02960 }
02961 }
02962
02963 {
02964 LLUUID node_uuid_checksum;
02965 if (!getAttribute("uuid_checksum", checksum_node, FALSE) ||
02966 checksum_node->getUUIDValue(1, &node_uuid_checksum) != 1)
02967 {
02968 error_buffer.append(llformat("ERROR Node %s: UUID checksum missing.\n", mName->mString));
02969 return FALSE;
02970 }
02971 if (node_uuid_checksum != uuid_checksum)
02972 {
02973 error_buffer.append(llformat("ERROR Node %s: UUID checksum mismatch: read %s / calc %s.\n", mName->mString, node_uuid_checksum.asString().c_str(), uuid_checksum.asString().c_str()));
02974 return FALSE;
02975 }
02976 }
02977
02978 {
02979 U32 node_noderef_checksum = 0;
02980 if (!getAttribute("noderef_checksum", checksum_node, FALSE) ||
02981 checksum_node->getUnsignedValue(1, &node_noderef_checksum, ENCODING_HEX) != 1)
02982 {
02983 error_buffer.append(llformat("ERROR Node %s: Node Ref checksum missing.\n", mName->mString));
02984 return FALSE;
02985 }
02986 if (node_noderef_checksum != noderef_checksum)
02987 {
02988 error_buffer.append(llformat("ERROR Node %s: Node Ref checksum mismatch: read %X / calc %X.\n", mName->mString, node_noderef_checksum, noderef_checksum));
02989 return FALSE;
02990 }
02991 }
02992
02993 {
02994 U32 node_float_checksum = 0;
02995 if (!getAttribute("float_checksum", checksum_node, FALSE) ||
02996 checksum_node->getUnsignedValue(1, &node_float_checksum, ENCODING_HEX) != 1)
02997 {
02998 error_buffer.append(llformat("ERROR Node %s: Float checksum missing.\n", mName->mString));
02999 return FALSE;
03000 }
03001 if (node_float_checksum != float_checksum)
03002 {
03003 error_buffer.append(llformat("ERROR Node %s: Float checksum mismatch: read %X / calc %X.\n", mName->mString, node_float_checksum, float_checksum));
03004 return FALSE;
03005 }
03006 }
03007
03008 return TRUE;
03009 }
03010
03011 LLXMLNodePtr LLXMLNode::getFirstChild()
03012 {
03013 if (!mChildren) return NULL;
03014 LLXMLNodePtr ret = mChildren->head;
03015 return ret;
03016 }
03017
03018 LLXMLNodePtr LLXMLNode::getNextSibling()
03019 {
03020 LLXMLNodePtr ret = mNext;
03021 return ret;
03022 }
03023
03024 LLString LLXMLNode::getTextContents() const
03025 {
03026 std::string msg;
03027 LLXMLNodeList p_children;
03028 getChildren("p", p_children);
03029 if (p_children.size() > 0)
03030 {
03031
03032 LLXMLNodeList::iterator itor;
03033 for (itor = p_children.begin(); itor != p_children.end(); ++itor)
03034 {
03035 LLXMLNodePtr p = itor->second;
03036 msg += p->getValue() + "\n";
03037 }
03038 }
03039 else
03040 {
03041 LLString contents = mValue;
03042 std::string::size_type n = contents.find_first_not_of(" \t\n");
03043 if (n != std::string::npos && contents[n] == '\"')
03044 {
03045
03046 S32 num_lines = 0;
03047 while(1)
03048 {
03049
03050 ++n;
03051 std::string::size_type t = n;
03052 std::string::size_type m = 0;
03053
03054 while(1)
03055 {
03056 m = contents.find_first_of("\\\"", t);
03057 if ((m == std::string::npos) || (contents[m] == '\"'))
03058 {
03059 break;
03060 }
03061 contents.erase(m,1);
03062 t = m+1;
03063 }
03064 if (m == std::string::npos)
03065 {
03066 break;
03067 }
03068
03069 num_lines++;
03070 msg += contents.substr(n,m-n) + "\n";
03071 n = contents.find_first_of("\"", m+1);
03072 if (n == std::string::npos)
03073 {
03074 if (num_lines == 1)
03075 {
03076 msg.erase(msg.size()-1);
03077 }
03078 break;
03079 }
03080 }
03081 }
03082 else
03083 {
03084
03085 LLString::size_type start = mValue.find_first_not_of(" \t\n");
03086 if (start != mValue.npos)
03087 {
03088 LLString::size_type end = mValue.find_last_not_of(" \t\n");
03089 if (end != mValue.npos)
03090 {
03091 msg = mValue.substr(start, end+1-start);
03092 }
03093 else
03094 {
03095 msg = mValue.substr(start);
03096 }
03097 }
03098
03099 msg = utf8str_removeCRLF(msg);
03100 }
03101 }
03102 return msg;
03103 }