llxmlnode.cpp

Go to the documentation of this file.
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 // static
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 // virtual
00108 LLXMLNode::~LLXMLNode()
00109 {
00110         // Strictly speaking none of this should be required execept 'delete mChildren'...
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 // protected
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 // virtual 
00239 LLXMLNodePtr LLXMLNode::createChild(const LLString& name, BOOL is_attribute)
00240 {
00241         return createChild(gStringTable.addStringEntry(name), is_attribute);
00242 }
00243 
00244 // virtual 
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                 // Find default value in parent's default tree
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         // Create a new node
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         // Set the parent-child relationship with the current active node
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         // Set the current active node to the new node
00327         XML_Parser *parser = parent->mParser;
00328         XML_SetUserData(*parser, (void *)new_node_ptr);
00329 
00330         // Parse attributes
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                 // Special cases
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                         /*else if (attr_value == "base32")
00406                         {
00407                                 new_node->mEncoding = LLXMLNode::ENCODING_BASE32;
00408                         }*/
00409                 }
00410 
00411                 // only one attribute child per description
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         // [FUGLY] Set the current active node to the current node's parent
00433         LLXMLNode *node = (LLXMLNode *)userData;
00434         XML_Parser *parser = node->mParser;
00435         XML_SetUserData(*parser, (void *)node->mParent);
00436         // SJB: total hack:
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                         // Special-case: Escaped string.
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 // static 
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         //update the node value
00511         node->mValue = update_node->mValue;
00512 
00513         //update all attribute values
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         //update all of node's children with updateNodes children that match name
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                         //if it's a combobox there's no name, but there is a value
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 // static
00569 bool LLXMLNode::parseFile(
00570         LLString filename,
00571         LLXMLNodePtr& node,
00572         LLXMLNode* defaults_tree)
00573 {
00574         // Read file
00575         FILE* fp = LLFile::fopen(filename.c_str(), "rb");               /* Flawfinder: ignore */
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 // static
00596 bool LLXMLNode::parseBuffer(
00597         U8* buffer,
00598         U32 length,
00599         LLXMLNodePtr& node, 
00600         LLXMLNode* defaults)
00601 {
00602         // Init
00603         XML_Parser my_parser = XML_ParserCreate(NULL);
00604         XML_SetElementHandler(my_parser, StartXMLNode, EndXMLNode);
00605         XML_SetCharacterDataHandler(my_parser, XMLData);
00606 
00607         // Create a root node
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         // Do the parsing
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         // Deinit
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 // static
00645 bool LLXMLNode::parseStream(
00646         std::istream& str,
00647         LLXMLNodePtr& node, 
00648         LLXMLNode* defaults)
00649 {
00650         // Init
00651         XML_Parser my_parser = XML_ParserCreate(NULL);
00652         XML_SetElementHandler(my_parser, StartXMLNode, EndXMLNode);
00653         XML_SetCharacterDataHandler(my_parser, XMLData);
00654 
00655         // Create a root node
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         // Deinit
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 // static
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                 // Don't write out nodes that are an exact match to defaults
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                 // Don't write out nodes that are an exact match to defaults
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         // stream the name
00780         output_stream << indent.c_str() << "<" << mName->mString;
00781 
00782         // ID
00783         if (mID != "")
00784         {
00785                 output_stream << " id=\"" << mID.c_str() << "\"";
00786         }
00787 
00788         // Type
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                         // default on switch(enum) eliminates a warning on linux
00813                         break;
00814                 };
00815         }
00816 
00817         // Encoding
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                 /*case ENCODING_BASE32:
00829                         output_stream << " encoding=\"base32\"";
00830                         break;*/
00831                 default:
00832                         // default on switch(enum) eliminates a warning on linux
00833                         break;
00834                 };
00835         }
00836 
00837         // Precision
00838         if (!has_default_precision && (mType == TYPE_INTEGER || mType == TYPE_FLOAT))
00839         {
00840                 output_stream << " precision=\"" << mPrecision << "\"";
00841         }
00842 
00843         // Version
00844         if (mVersionMajor > 0 || mVersionMinor > 0)
00845         {
00846                 output_stream << " version=\"" << mVersionMajor << "." << mVersionMinor << "\"";
00847         }
00848 
00849         // Array length
00850         if (!has_default_length && mLength > 0)
00851         {
00852                 output_stream << " length=\"" << mLength << "\"";
00853         }
00854 
00855         {
00856                 // Write out attributes
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; // skip built-in attributes
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                         // stream non-attributes
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                         // Look for this child in the default's children
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 /*static */
01248 const char *LLXMLNode::skipWhitespace(const char *str)
01249 {
01250         // skip whitespace characters
01251         while (str[0] == ' ' || str[0] == '\t' || str[0] == '\n') ++str;
01252         return str;
01253 }
01254 
01255 /*static */
01256 const char *LLXMLNode::skipNonWhitespace(const char *str)
01257 {
01258         // skip non-whitespace characters
01259         while (str[0] != ' ' && str[0] != '\t' && str[0] != '\n' && str[0] != 0) ++str;
01260         return str;
01261 }
01262 
01263 /*static */
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                         // If there is a fractional part, skip it
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 // 25 elements - decimal expansions of 1/(2^n), multiplied by 10 each iteration
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 // 36 elements - decimal expansions of 1/(2^n) after the last 28, truncated, no multiply each iteration
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 /*static */
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                 // Parse the integer part of the expression
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;//, f_decimal = 1;
01416                 if (str[0] == '.')
01417                 {
01418                         ++str;
01419                         U64 remainder = 0;
01420                         U32 pos = 0;
01421                         // Parse the decimal part of the expression
01422                         while (str[0] >= '0' && str[0] <= '9' && pos < 25)
01423                         {
01424                                 remainder = (remainder*10) + U64(str[0] - '0');
01425                                 f_part <<= 1;
01426                                 //f_decimal <<= 1;
01427                                 // Check the n'th bit
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                                 // Drop any excessive digits
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                                         //f_decimal <<= 1;
01451                                         // Check the n'th bit
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                                 //f_decimal <<= 1;
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                         // Scientific notation!
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                         // no digits parsed
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                 // Upcast to F64
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         // Check type - accept booleans or strings
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         // Check type - accept bytes or integers (below 256 only)
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         // Check type - accept bytes or integers
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         // Check type - accept bytes or integers
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         // Int type
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         // Check type - accept bytes or integers
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         // Int type
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         // Check type - accept only floats or doubles
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         // Check type - accept only floats or doubles
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         // Can always return any value as a string
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         // Array of strings is whitespace-separated
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         // Check type
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))         /* Flawfinder: ignore */
01943                 {
01944                         break;
01945                 }
01946                 char uuid_string[UUID_STR_LENGTH];              /* Flawfinder: ignore */
01947                 memcpy(uuid_string, value_string, (UUID_STR_LENGTH-1));         /* Flawfinder: ignore */
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         // Check type
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         // TODO -- Handle Base32
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         // TODO -- Handle Base32
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         // TODO -- Handle Base32
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         // TODO -- Handle Base32
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];         /* Flawfinder: ignore */
02233                 if (precision > 0)
02234                 {
02235                         if (precision > 25)
02236                         {
02237                                 precision = 25;
02238                         }
02239                         snprintf(format_string, sizeof(format_string), "%%.%dg", precision);    /* Flawfinder: ignore */
02240                 }
02241                 else
02242                 {
02243                         snprintf(format_string, sizeof(format_string), "%%g");          /* Flawfinder: ignore */
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];         /* Flawfinder: ignore */
02284                 if (precision > 0)
02285                 {
02286                         if (precision > 25)
02287                         {
02288                                 precision = 25;
02289                         }
02290                         snprintf(format_string, sizeof(format_string), "%%.%dg", precision);    /* Flawfinder: ignore */
02291                 }
02292                 else
02293                 {
02294                         snprintf(format_string, sizeof(format_string), "%%g");          /* Flawfinder: ignore */
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         // TODO -- Handle Base32
02320 
02321         mEncoding = encoding;
02322         mLength = length;
02323         mType = TYPE_FLOAT;
02324         mPrecision = 64;
02325 }
02326 
02327 // static
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("&quot;");   break;
02337                 case '\'':      out.append("&apos;");   break;
02338                 case '&':       out.append("&amp;");    break;
02339                 case '<':       out.append("&lt;");             break;
02340                 case '>':       out.append("&gt;");             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                 // TODO -- use multimap::find()
02450                 // TODO -- need to watch out for invalid iterators
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                 // TODO -- use multimap::find()
02472                 // TODO -- need to watch out for invalid iterators
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                 // we need to remove and re-add to the parent so that
02505                 // the multimap key agrees with this node's name
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 //  UNIT TESTING 
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         // Random ID
02568         char rand_id[20];               /* Flawfinder: ignore */
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         // Checksums
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         // Create a random number of children
02593         U32 num_children = get_rand(max_num_children)+1;
02594         for (U32 child_num=0; child_num<num_children; ++child_num)
02595         {
02596                 // Random Name
02597                 char child_name[20];            /* Flawfinder: ignore */
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                 // Random ID
02609                 char child_id[20];              /* Flawfinder: ignore */
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                 // Random Length
02620                 U32 array_size = get_rand(28)+1;
02621 
02622                 // Random Encoding
02623                 Encoding new_encoding = get_rand(2)?ENCODING_DECIMAL:ENCODING_HEX;
02624 
02625                 // Random Type
02626                 int type = get_rand(8);
02627                 switch (type)
02628                 {
02629                 case 0: // TYPE_CONTAINER
02630                         new_child->createUnitTest(max_num_children/2);
02631                         break;
02632                 case 1: // TYPE_BOOLEAN
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: // TYPE_INTEGER (32-bit)
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: // TYPE_INTEGER (64-bit)
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: // TYPE_FLOAT (32-bit)
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: // TYPE_FLOAT (64-bit)
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: // TYPE_UUID
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: // TYPE_NODEREF
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)           /* Flawfinder: ignore */
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         // Checksums
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                                 //return FALSE;
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)                /* Flawfinder: ignore */
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         // Compare checksums
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                 // Case 1: node has <p>text</p> tags
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                         // Case 2: node has quoted text
03046                         S32 num_lines = 0;
03047                         while(1)
03048                         {
03049                                 // mContents[n] == '"'
03050                                 ++n;
03051                                 std::string::size_type t = n;
03052                                 std::string::size_type m = 0;
03053                                 // fix-up escaped characters
03054                                 while(1)
03055                                 {
03056                                         m = contents.find_first_of("\\\"", t); // find first \ or "
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                                 // mContents[m] == '"'
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); // remove "\n" if only one line
03077                                         }
03078                                         break;
03079                                 }
03080                         }
03081                 }
03082                 else
03083                 {
03084                         // Case 3: node has embedded text (beginning and trailing whitespace trimmed)
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                         // Convert any internal CR to LF
03099                         msg = utf8str_removeCRLF(msg);
03100                 }
03101         }
03102         return msg;
03103 }

Generated on Thu Jul 1 06:09:48 2010 for Second Life Viewer by  doxygen 1.4.7