PageRenderTime 155ms CodeModel.GetById 9ms app.highlight 132ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/llxml/llxmlnode.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2899 lines | 2743 code | 75 blank | 81 comment | 219 complexity | 45bdae29a3554ef9d06b18e382a20d72 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/** 
   2 * @file llxmlnode.cpp
   3 * @author Tom Yedwab
   4 * @brief LLXMLNode implementation
   5 *
   6 * $LicenseInfo:firstyear=2005&license=viewerlgpl$
   7 * Second Life Viewer Source Code
   8 * Copyright (C) 2010, Linden Research, Inc.
   9 * 
  10 * This library is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU Lesser General Public
  12 * License as published by the Free Software Foundation;
  13 * version 2.1 of the License only.
  14 * 
  15 * This library is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18 * Lesser General Public License for more details.
  19 * 
  20 * You should have received a copy of the GNU Lesser General Public
  21 * License along with this library; if not, write to the Free Software
  22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  23 * 
  24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  25 * $/LicenseInfo$
  26 */
  27
  28#include "linden_common.h"
  29
  30#include <iostream>
  31#include <map>
  32
  33#include "llxmlnode.h"
  34
  35#include "v3color.h"
  36#include "v4color.h"
  37#include "v4coloru.h"
  38#include "v3math.h"
  39#include "v3dmath.h"
  40#include "v4math.h"
  41#include "llquaternion.h"
  42#include "llstring.h"
  43#include "lluuid.h"
  44#include "lldir.h"
  45
  46const S32 MAX_COLUMN_WIDTH = 80;
  47
  48// static
  49BOOL LLXMLNode::sStripEscapedStrings = TRUE;
  50BOOL LLXMLNode::sStripWhitespaceValues = FALSE;
  51
  52LLXMLNode::LLXMLNode() : 
  53	mID(""),
  54	mParser(NULL),
  55	mIsAttribute(FALSE),
  56	mVersionMajor(0), 
  57	mVersionMinor(0), 
  58	mLength(0), 
  59	mPrecision(64),
  60	mType(TYPE_CONTAINER),
  61	mEncoding(ENCODING_DEFAULT),
  62	mLineNumber(-1),
  63	mParent(NULL),
  64	mChildren(NULL),
  65	mAttributes(),
  66	mPrev(NULL),
  67	mNext(NULL),
  68	mName(NULL), 
  69	mValue(""), 
  70	mDefault(NULL)
  71{
  72}
  73
  74LLXMLNode::LLXMLNode(const char* name, BOOL is_attribute) : 
  75	mID(""),
  76	mParser(NULL),
  77	mIsAttribute(is_attribute),
  78	mVersionMajor(0), 
  79	mVersionMinor(0), 
  80	mLength(0), 
  81	mPrecision(64),
  82	mType(TYPE_CONTAINER), 
  83	mEncoding(ENCODING_DEFAULT),
  84	mLineNumber(-1),
  85	mParent(NULL),
  86	mChildren(NULL),
  87	mAttributes(),
  88	mPrev(NULL),
  89	mNext(NULL),
  90	mValue(""), 
  91	mDefault(NULL)
  92{
  93    mName = gStringTable.addStringEntry(name);
  94}
  95
  96LLXMLNode::LLXMLNode(LLStringTableEntry* name, BOOL is_attribute) : 
  97	mID(""),
  98	mParser(NULL),
  99	mIsAttribute(is_attribute),
 100	mVersionMajor(0), 
 101	mVersionMinor(0), 
 102	mLength(0), 
 103	mPrecision(64),
 104	mType(TYPE_CONTAINER), 
 105	mEncoding(ENCODING_DEFAULT),
 106	mLineNumber(-1),
 107	mParent(NULL),
 108	mChildren(NULL),
 109	mAttributes(),
 110	mPrev(NULL),
 111	mNext(NULL),
 112	mName(name),
 113	mValue(""), 
 114	mDefault(NULL)
 115{
 116}
 117
 118// copy constructor (except for the children)
 119LLXMLNode::LLXMLNode(const LLXMLNode& rhs) : 
 120	mID(rhs.mID),
 121	mIsAttribute(rhs.mIsAttribute),
 122	mVersionMajor(rhs.mVersionMajor), 
 123	mVersionMinor(rhs.mVersionMinor), 
 124	mLength(rhs.mLength), 
 125	mPrecision(rhs.mPrecision),
 126	mType(rhs.mType),
 127	mEncoding(rhs.mEncoding),
 128	mLineNumber(0),
 129	mParser(NULL),
 130	mParent(NULL),
 131	mChildren(NULL),
 132	mAttributes(),
 133	mPrev(NULL),
 134	mNext(NULL),
 135	mName(rhs.mName), 
 136	mValue(rhs.mValue), 
 137	mDefault(rhs.mDefault)
 138{
 139}
 140
 141// returns a new copy of this node and all its children
 142LLXMLNodePtr LLXMLNode::deepCopy()
 143{
 144	LLXMLNodePtr newnode = LLXMLNodePtr(new LLXMLNode(*this));
 145	if (mChildren.notNull())
 146	{
 147		for (LLXMLChildList::iterator iter = mChildren->map.begin();
 148			 iter != mChildren->map.end(); ++iter)	
 149		{
 150			newnode->addChild(iter->second->deepCopy());
 151		}
 152	}
 153	for (LLXMLAttribList::iterator iter = mAttributes.begin();
 154		 iter != mAttributes.end(); ++iter)
 155	{
 156		newnode->addChild(iter->second->deepCopy());
 157	}
 158
 159	return newnode;
 160}
 161
 162// virtual
 163LLXMLNode::~LLXMLNode()
 164{
 165	// Strictly speaking none of this should be required execept 'delete mChildren'...
 166	// Sadly, that's only true if we hadn't had reference-counted smart pointers linked
 167	// in three different directions. This entire class is a frightening, hard-to-maintain
 168	// mess.
 169	if (mChildren.notNull())
 170	{
 171		for (LLXMLChildList::iterator iter = mChildren->map.begin();
 172			 iter != mChildren->map.end(); ++iter)
 173		{
 174			LLXMLNodePtr child = iter->second;
 175			child->mParent = NULL;
 176			child->mNext = NULL;
 177			child->mPrev = NULL;
 178		}
 179		mChildren->map.clear();
 180		mChildren->head = NULL;
 181		mChildren->tail = NULL;
 182		mChildren = NULL;
 183	}
 184	for (LLXMLAttribList::iterator iter = mAttributes.begin();
 185		 iter != mAttributes.end(); ++iter)
 186	{
 187		LLXMLNodePtr attr = iter->second;
 188		attr->mParent = NULL;
 189		attr->mNext = NULL;
 190		attr->mPrev = NULL;
 191	}
 192	llassert(mParent == NULL);
 193	mDefault = NULL;
 194}
 195
 196BOOL LLXMLNode::isNull()
 197{	
 198	return (mName == NULL);
 199}
 200
 201// protected
 202BOOL LLXMLNode::removeChild(LLXMLNode *target_child) 
 203{
 204	if (!target_child)
 205	{
 206		return FALSE;
 207	}
 208	if (target_child->mIsAttribute)
 209	{
 210		LLXMLAttribList::iterator children_itr = mAttributes.find(target_child->mName);
 211		if (children_itr != mAttributes.end())
 212		{
 213			target_child->mParent = NULL;
 214			mAttributes.erase(children_itr);
 215			return TRUE;
 216		}
 217	}
 218	else if (mChildren.notNull())
 219	{
 220		LLXMLChildList::iterator children_itr = mChildren->map.find(target_child->mName);
 221		while (children_itr != mChildren->map.end())
 222		{
 223			if (target_child == children_itr->second)
 224			{
 225				if (target_child == mChildren->head)
 226				{
 227					mChildren->head = target_child->mNext;
 228				}
 229				if (target_child == mChildren->tail)
 230				{
 231					mChildren->tail = target_child->mPrev;
 232				}
 233
 234				LLXMLNodePtr prev = target_child->mPrev;
 235				LLXMLNodePtr next = target_child->mNext;
 236				if (prev.notNull()) prev->mNext = next;
 237				if (next.notNull()) next->mPrev = prev;
 238
 239				target_child->mPrev = NULL;
 240				target_child->mNext = NULL;
 241				target_child->mParent = NULL;
 242				mChildren->map.erase(children_itr);
 243				if (mChildren->map.empty())
 244				{
 245					mChildren = NULL;
 246				}
 247				return TRUE;
 248			}
 249			else if (children_itr->first != target_child->mName)
 250			{
 251				break;
 252			}
 253			else
 254			{
 255				++children_itr;
 256			}
 257		}
 258	}
 259	return FALSE;
 260}
 261
 262void LLXMLNode::addChild(LLXMLNodePtr new_child, LLXMLNodePtr after_child)
 263{
 264	if (new_child->mParent != NULL)
 265	{
 266		if (new_child->mParent == this)
 267		{
 268			return;
 269		}
 270		new_child->mParent->removeChild(new_child);
 271	}
 272
 273	new_child->mParent = this;
 274	if (new_child->mIsAttribute)
 275	{
 276		mAttributes.insert(std::make_pair(new_child->mName, new_child));
 277	}
 278	else
 279	{
 280		if (mChildren.isNull())
 281		{
 282			mChildren = new LLXMLChildren();
 283			mChildren->head = new_child;
 284			mChildren->tail = new_child;
 285		}
 286		mChildren->map.insert(std::make_pair(new_child->mName, new_child));
 287
 288		// if after_child is specified, it damn well better be in the list of children
 289		// for this node. I'm not going to assert that, because it would be expensive,
 290		// but don't specify that parameter if you didn't get the value for it from the
 291		// list of children of this node!
 292		if (after_child.isNull())
 293		{
 294			if (mChildren->tail != new_child)
 295			{
 296				mChildren->tail->mNext = new_child;
 297				new_child->mPrev = mChildren->tail;
 298				mChildren->tail = new_child;
 299			}
 300		}
 301		// if after_child == parent, then put new_child at beginning
 302		else if (after_child == this)
 303		{
 304			// add to front of list
 305			new_child->mNext = mChildren->head;
 306			if (mChildren->head)
 307			{
 308				mChildren->head->mPrev = new_child;
 309				mChildren->head = new_child;
 310			}
 311			else // no children
 312			{
 313				mChildren->head = new_child;
 314				mChildren->tail = new_child;
 315			}
 316		}
 317		else
 318		{
 319			if (after_child->mNext.notNull())
 320			{
 321				// if after_child was not the last item, fix up some pointers
 322				after_child->mNext->mPrev = new_child;
 323				new_child->mNext = after_child->mNext;
 324			}
 325			new_child->mPrev = after_child;
 326			after_child->mNext = new_child;
 327			if (mChildren->tail == after_child)
 328			{
 329				mChildren->tail = new_child;
 330			}
 331		}
 332	}
 333
 334	new_child->updateDefault();
 335}
 336
 337// virtual 
 338LLXMLNodePtr LLXMLNode::createChild(const char* name, BOOL is_attribute)
 339{
 340	return createChild(gStringTable.addStringEntry(name), is_attribute);
 341}
 342
 343// virtual 
 344LLXMLNodePtr LLXMLNode::createChild(LLStringTableEntry* name, BOOL is_attribute)
 345{
 346	LLXMLNode* ret = new LLXMLNode(name, is_attribute);
 347	ret->mID.clear();
 348	addChild(ret);
 349	return ret;
 350}
 351
 352BOOL LLXMLNode::deleteChild(LLXMLNode *child)
 353{
 354	if (removeChild(child))
 355	{
 356		return TRUE;
 357	}
 358	return FALSE;
 359}
 360
 361void LLXMLNode::setParent(LLXMLNodePtr new_parent)
 362{
 363	if (new_parent.notNull())
 364	{
 365		new_parent->addChild(this);
 366	}
 367	else
 368	{
 369		if (mParent != NULL)
 370		{
 371		    LLXMLNodePtr old_parent = mParent;
 372			mParent = NULL;
 373			old_parent->removeChild(this);
 374		}
 375	}
 376}
 377
 378
 379void LLXMLNode::updateDefault()
 380{
 381	if (mParent != NULL && !mParent->mDefault.isNull())
 382	{
 383		mDefault = NULL;
 384
 385		// Find default value in parent's default tree
 386		if (!mParent->mDefault.isNull())
 387		{
 388			findDefault(mParent->mDefault);
 389		}
 390	}
 391
 392	if (mChildren.notNull())
 393	{
 394		LLXMLChildList::const_iterator children_itr;
 395		LLXMLChildList::const_iterator children_end = mChildren->map.end();
 396		for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
 397		{
 398			LLXMLNodePtr child = (*children_itr).second;
 399			child->updateDefault();
 400		}
 401	}
 402}
 403
 404void XMLCALL StartXMLNode(void *userData,
 405                          const XML_Char *name,
 406                          const XML_Char **atts)
 407{
 408	// Create a new node
 409	LLXMLNode *new_node_ptr = new LLXMLNode(name, FALSE);
 410
 411	LLXMLNodePtr new_node = new_node_ptr;
 412	new_node->mID.clear();
 413	LLXMLNodePtr ptr_new_node = new_node;
 414
 415	// Set the parent-child relationship with the current active node
 416	LLXMLNode* parent = (LLXMLNode *)userData;
 417
 418	if (NULL == parent)
 419	{
 420		llwarns << "parent (userData) is NULL; aborting function" << llendl;
 421		return;
 422	}
 423
 424	new_node_ptr->mParser = parent->mParser;
 425	new_node_ptr->setLineNumber(XML_GetCurrentLineNumber(*new_node_ptr->mParser));
 426	
 427	// Set the current active node to the new node
 428	XML_Parser *parser = parent->mParser;
 429	XML_SetUserData(*parser, (void *)new_node_ptr);
 430
 431	// Parse attributes
 432	U32 pos = 0;
 433	while (atts[pos] != NULL)
 434	{
 435		std::string attr_name = atts[pos];
 436		std::string attr_value = atts[pos+1];
 437
 438		// Special cases
 439		if ('i' == attr_name[0] && "id" == attr_name)
 440		{
 441			new_node->mID = attr_value;
 442		}
 443		else if ('v' == attr_name[0] && "version" == attr_name)
 444		{
 445			U32 version_major = 0;
 446			U32 version_minor = 0;
 447			if (sscanf(attr_value.c_str(), "%d.%d", &version_major, &version_minor) > 0)
 448			{
 449				new_node->mVersionMajor = version_major;
 450				new_node->mVersionMinor = version_minor;
 451			}
 452		}
 453		else if (('s' == attr_name[0] && "size" == attr_name) || ('l' == attr_name[0] && "length" == attr_name))
 454		{
 455			U32 length;
 456			if (sscanf(attr_value.c_str(), "%d", &length) > 0)
 457			{
 458				new_node->mLength = length;
 459			}
 460		}
 461		else if ('p' == attr_name[0] && "precision" == attr_name)
 462		{
 463			U32 precision;
 464			if (sscanf(attr_value.c_str(), "%d", &precision) > 0)
 465			{
 466				new_node->mPrecision = precision;
 467			}
 468		}
 469		else if ('t' == attr_name[0] && "type" == attr_name)
 470		{
 471			if ("boolean" == attr_value)
 472			{
 473				new_node->mType = LLXMLNode::TYPE_BOOLEAN;
 474			}
 475			else if ("integer" == attr_value)
 476			{
 477				new_node->mType = LLXMLNode::TYPE_INTEGER;
 478			}
 479			else if ("float" == attr_value)
 480			{
 481				new_node->mType = LLXMLNode::TYPE_FLOAT;
 482			}
 483			else if ("string" == attr_value)
 484			{
 485				new_node->mType = LLXMLNode::TYPE_STRING;
 486			}
 487			else if ("uuid" == attr_value)
 488			{
 489				new_node->mType = LLXMLNode::TYPE_UUID;
 490			}
 491			else if ("noderef" == attr_value)
 492			{
 493				new_node->mType = LLXMLNode::TYPE_NODEREF;
 494			}
 495		}
 496		else if ('e' == attr_name[0] && "encoding" == attr_name)
 497		{
 498			if ("decimal" == attr_value)
 499			{
 500				new_node->mEncoding = LLXMLNode::ENCODING_DECIMAL;
 501			}
 502			else if ("hex" == attr_value)
 503			{
 504				new_node->mEncoding = LLXMLNode::ENCODING_HEX;
 505			}
 506			/*else if (attr_value == "base32")
 507			{
 508				new_node->mEncoding = LLXMLNode::ENCODING_BASE32;
 509			}*/
 510		}
 511
 512		// only one attribute child per description
 513		LLXMLNodePtr attr_node;
 514		if (!new_node->getAttribute(attr_name.c_str(), attr_node, FALSE))
 515		{
 516			attr_node = new LLXMLNode(attr_name.c_str(), TRUE);
 517			attr_node->setLineNumber(XML_GetCurrentLineNumber(*new_node_ptr->mParser));
 518		}
 519		attr_node->setValue(attr_value);
 520		new_node->addChild(attr_node);
 521
 522		pos += 2;
 523	}
 524
 525	if (parent)
 526	{
 527		parent->addChild(new_node);
 528	}
 529}
 530
 531void XMLCALL EndXMLNode(void *userData,
 532                        const XML_Char *name)
 533{
 534	// [FUGLY] Set the current active node to the current node's parent
 535	LLXMLNode *node = (LLXMLNode *)userData;
 536	XML_Parser *parser = node->mParser;
 537	XML_SetUserData(*parser, (void *)node->mParent);
 538	// SJB: total hack:
 539	if (LLXMLNode::sStripWhitespaceValues)
 540	{
 541		std::string value = node->getValue();
 542		BOOL is_empty = TRUE;
 543		for (std::string::size_type s = 0; s < value.length(); s++)
 544		{
 545			char c = value[s];
 546			if (c != ' ' && c != '\t' && c != '\n')
 547			{
 548				is_empty = FALSE;
 549				break;
 550			}
 551		}
 552		if (is_empty)
 553		{
 554			value.clear();
 555			node->setValue(value);
 556		}
 557	}
 558}
 559
 560void XMLCALL XMLData(void *userData,
 561                     const XML_Char *s,
 562                     int len)
 563{
 564	LLXMLNode* current_node = (LLXMLNode *)userData;
 565	std::string value = current_node->getValue();
 566	if (LLXMLNode::sStripEscapedStrings)
 567	{
 568		if (s[0] == '\"' && s[len-1] == '\"')
 569		{
 570			// Special-case: Escaped string.
 571			std::string unescaped_string;
 572			for (S32 pos=1; pos<len-1; ++pos)
 573			{
 574				if (s[pos] == '\\' && s[pos+1] == '\\')
 575				{
 576					unescaped_string.append("\\");
 577					++pos;
 578				}
 579				else if (s[pos] == '\\' && s[pos+1] == '\"')
 580				{
 581					unescaped_string.append("\"");
 582					++pos;
 583				}
 584				else
 585				{
 586					unescaped_string.append(&s[pos], 1);
 587				}
 588			}
 589			value.append(unescaped_string);
 590			current_node->setValue(value);
 591			return;
 592		}
 593	}
 594	value.append(std::string(s, len));
 595	current_node->setValue(value);
 596}
 597
 598
 599
 600// static 
 601bool LLXMLNode::updateNode(
 602	LLXMLNodePtr& node,
 603	LLXMLNodePtr& update_node)
 604{
 605
 606	if (!node || !update_node)
 607	{
 608		llwarns << "Node invalid" << llendl;
 609		return FALSE;
 610	}
 611
 612	//update the node value
 613	node->mValue = update_node->mValue;
 614
 615	//update all attribute values
 616	LLXMLAttribList::const_iterator itor;
 617
 618	for(itor = update_node->mAttributes.begin(); itor != update_node->mAttributes.end(); ++itor)
 619	{
 620		const LLStringTableEntry* attribNameEntry = (*itor).first;
 621		LLXMLNodePtr updateAttribNode = (*itor).second;
 622
 623		LLXMLNodePtr attribNode;
 624
 625		node->getAttribute(attribNameEntry, attribNode, 0);
 626
 627		if (attribNode)
 628		{
 629			attribNode->mValue = updateAttribNode->mValue;
 630		}
 631	}
 632
 633	//update all of node's children with updateNodes children that match name
 634	LLXMLNodePtr child;
 635	LLXMLNodePtr updateChild;
 636	
 637	for (updateChild = update_node->getFirstChild(); updateChild.notNull(); 
 638		 updateChild = updateChild->getNextSibling())
 639	{
 640		for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
 641		{
 642			std::string nodeName;
 643			std::string updateName;
 644
 645			updateChild->getAttributeString("name", updateName);
 646			child->getAttributeString("name", nodeName);		
 647
 648
 649			//if it's a combobox there's no name, but there is a value
 650			if (updateName.empty())
 651			{
 652				updateChild->getAttributeString("value", updateName);
 653				child->getAttributeString("value", nodeName);
 654			}
 655
 656			if ((nodeName != "") && (updateName == nodeName))
 657			{
 658				updateNode(child, updateChild);
 659				break;
 660			}
 661		}
 662	}
 663
 664	return TRUE;
 665}
 666
 667
 668// static 
 669LLXMLNodePtr LLXMLNode::replaceNode(LLXMLNodePtr node, LLXMLNodePtr update_node)
 670{	
 671	if (!node || !update_node)
 672	{
 673		llwarns << "Node invalid" << llendl;
 674		return node;
 675	}
 676	
 677	LLXMLNodePtr cloned_node = update_node->deepCopy();
 678	node->mParent->addChild(cloned_node, node);	// add after node
 679	LLXMLNodePtr parent = node->mParent;
 680	parent->removeChild(node);
 681	parent->updateDefault();
 682	
 683	return cloned_node;
 684}
 685
 686
 687
 688// static
 689bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree)
 690{
 691	// Read file
 692	LL_DEBUGS("XMLNode") << "parsing XML file: " << filename << LL_ENDL;
 693	LLFILE* fp = LLFile::fopen(filename, "rb");		/* Flawfinder: ignore */
 694	if (fp == NULL)
 695	{
 696		node = NULL ;
 697		return false;
 698	}
 699	fseek(fp, 0, SEEK_END);
 700	U32 length = ftell(fp);
 701	fseek(fp, 0, SEEK_SET);
 702
 703	U8* buffer = new U8[length+1];
 704	size_t nread = fread(buffer, 1, length, fp);
 705	buffer[nread] = 0;
 706	fclose(fp);
 707
 708	bool rv = parseBuffer(buffer, nread, node, defaults_tree);
 709	delete [] buffer;
 710	return rv;
 711}
 712
 713// static
 714bool LLXMLNode::parseBuffer(
 715	U8* buffer,
 716	U32 length,
 717	LLXMLNodePtr& node, 
 718	LLXMLNode* defaults)
 719{
 720	// Init
 721	XML_Parser my_parser = XML_ParserCreate(NULL);
 722	XML_SetElementHandler(my_parser, StartXMLNode, EndXMLNode);
 723	XML_SetCharacterDataHandler(my_parser, XMLData);
 724
 725	// Create a root node
 726	LLXMLNode *file_node_ptr = new LLXMLNode("XML", FALSE);
 727	LLXMLNodePtr file_node = file_node_ptr;
 728
 729	file_node->mParser = &my_parser;
 730
 731	XML_SetUserData(my_parser, (void *)file_node_ptr);
 732
 733	// Do the parsing
 734	if (XML_Parse(my_parser, (const char *)buffer, length, TRUE) != XML_STATUS_OK)
 735	{
 736		llwarns << "Error parsing xml error code: "
 737				<< XML_ErrorString(XML_GetErrorCode(my_parser))
 738				<< " on line " << XML_GetCurrentLineNumber(my_parser)
 739				<< llendl;
 740	}
 741
 742	// Deinit
 743	XML_ParserFree(my_parser);
 744
 745	if (!file_node->mChildren || file_node->mChildren->map.size() != 1)
 746	{
 747		llwarns << "Parse failure - wrong number of top-level nodes xml."
 748				<< llendl;
 749		node = NULL ;
 750		return false;
 751	}
 752
 753	LLXMLNode *return_node = file_node->mChildren->map.begin()->second;
 754
 755	return_node->setDefault(defaults);
 756	return_node->updateDefault();
 757
 758	node = return_node;
 759	return true;
 760}
 761
 762// static
 763bool LLXMLNode::parseStream(
 764	std::istream& str,
 765	LLXMLNodePtr& node, 
 766	LLXMLNode* defaults)
 767{
 768	// Init
 769	XML_Parser my_parser = XML_ParserCreate(NULL);
 770	XML_SetElementHandler(my_parser, StartXMLNode, EndXMLNode);
 771	XML_SetCharacterDataHandler(my_parser, XMLData);
 772
 773	// Create a root node
 774	LLXMLNode *file_node_ptr = new LLXMLNode("XML", FALSE);
 775	LLXMLNodePtr file_node = file_node_ptr;
 776
 777	file_node->mParser = &my_parser;
 778
 779	XML_SetUserData(my_parser, (void *)file_node_ptr);
 780
 781	const int BUFSIZE = 1024; 
 782	U8* buffer = new U8[BUFSIZE];
 783
 784	while(str.good())
 785	{
 786		str.read((char*)buffer, BUFSIZE);
 787		int count = str.gcount();
 788		
 789		if (XML_Parse(my_parser, (const char *)buffer, count, !str.good()) != XML_STATUS_OK)
 790		{
 791			llwarns << "Error parsing xml error code: "
 792					<< XML_ErrorString(XML_GetErrorCode(my_parser))
 793					<< " on lne " << XML_GetCurrentLineNumber(my_parser)
 794					<< llendl;
 795			break;
 796		}
 797	}
 798	
 799	delete [] buffer;
 800
 801	// Deinit
 802	XML_ParserFree(my_parser);
 803
 804	if (!file_node->mChildren || file_node->mChildren->map.size() != 1)
 805	{
 806		llwarns << "Parse failure - wrong number of top-level nodes xml."
 807				<< llendl;
 808		node = NULL;
 809		return false;
 810	}
 811
 812	LLXMLNode *return_node = file_node->mChildren->map.begin()->second;
 813
 814	return_node->setDefault(defaults);
 815	return_node->updateDefault();
 816
 817	node = return_node;
 818	return true;
 819}
 820
 821
 822BOOL LLXMLNode::isFullyDefault()
 823{
 824	if (mDefault.isNull())
 825	{
 826		return FALSE;
 827	}
 828	BOOL has_default_value = (mValue == mDefault->mValue);
 829	BOOL has_default_attribute = (mIsAttribute == mDefault->mIsAttribute);
 830	BOOL has_default_type = mIsAttribute || (mType == mDefault->mType);
 831	BOOL has_default_encoding = mIsAttribute || (mEncoding == mDefault->mEncoding);
 832	BOOL has_default_precision = mIsAttribute || (mPrecision == mDefault->mPrecision);
 833	BOOL has_default_length = mIsAttribute || (mLength == mDefault->mLength);
 834
 835	if (has_default_value 
 836		&& has_default_type 
 837		&& has_default_encoding 
 838		&& has_default_precision
 839		&& has_default_length
 840		&& has_default_attribute)
 841	{
 842		if (mChildren.notNull())
 843		{
 844			LLXMLChildList::const_iterator children_itr;
 845			LLXMLChildList::const_iterator children_end = mChildren->map.end();
 846			for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
 847			{
 848				LLXMLNodePtr child = (*children_itr).second;
 849				if (!child->isFullyDefault())
 850				{
 851					return FALSE;
 852				}
 853			}
 854		}
 855		return TRUE;
 856	}
 857
 858	return FALSE;
 859}
 860
 861// static
 862bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root,
 863								  const std::vector<std::string>& paths)
 864{
 865	if (paths.empty()) return false;
 866
 867	std::string filename = paths.front();
 868	if (filename.empty())
 869	{
 870		return false;
 871	}
 872	
 873	if (!LLXMLNode::parseFile(filename, root, NULL))
 874	{
 875		llwarns << "Problem reading UI description file: " << filename << llendl;
 876		return false;
 877	}
 878
 879	LLXMLNodePtr updateRoot;
 880
 881	std::vector<std::string>::const_iterator itor;
 882
 883	for (itor = paths.begin(), ++itor; itor != paths.end(); ++itor)
 884	{
 885		std::string nodeName;
 886		std::string updateName;
 887
 888		std::string layer_filename = *itor;
 889		if(layer_filename.empty())
 890		{
 891			// no localized version of this file, that's ok, keep looking
 892			continue;
 893		}
 894
 895		if (!LLXMLNode::parseFile(layer_filename, updateRoot, NULL))
 896		{
 897			llwarns << "Problem reading localized UI description file: " << layer_filename << llendl;
 898			return false;
 899		}
 900
 901		updateRoot->getAttributeString("name", updateName);
 902		root->getAttributeString("name", nodeName);
 903
 904		if (updateName == nodeName)
 905		{
 906			LLXMLNode::updateNode(root, updateRoot);
 907		}
 908	}
 909
 910	return true;
 911}
 912
 913// static
 914void LLXMLNode::writeHeaderToFile(LLFILE *out_file)
 915{
 916	fprintf(out_file, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n");
 917}
 918
 919void LLXMLNode::writeToFile(LLFILE *out_file, const std::string& indent, bool use_type_decorations)
 920{
 921	if (isFullyDefault())
 922	{
 923		// Don't write out nodes that are an exact match to defaults
 924		return;
 925	}
 926
 927	std::ostringstream ostream;
 928	writeToOstream(ostream, indent, use_type_decorations);
 929	std::string outstring = ostream.str();
 930	size_t written = fwrite(outstring.c_str(), 1, outstring.length(), out_file);
 931	if (written != outstring.length())
 932	{
 933		llwarns << "Short write" << llendl;
 934	}
 935}
 936
 937void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& indent, bool use_type_decorations)
 938{
 939	if (isFullyDefault())
 940	{
 941		// Don't write out nodes that are an exact match to defaults
 942		return;
 943	}
 944
 945	BOOL has_default_type = mDefault.isNull()?FALSE:(mType == mDefault->mType);
 946	BOOL has_default_encoding = mDefault.isNull()?FALSE:(mEncoding == mDefault->mEncoding);
 947	BOOL has_default_precision = mDefault.isNull()?FALSE:(mPrecision == mDefault->mPrecision);
 948	BOOL has_default_length = mDefault.isNull()?FALSE:(mLength == mDefault->mLength);
 949
 950	// stream the name
 951	output_stream << indent << "<" << mName->mString << "\n";
 952
 953	if (use_type_decorations)
 954	{
 955		// ID
 956		if (mID != "")
 957		{
 958			output_stream << indent << " id=\"" << mID << "\"\n";
 959		}
 960
 961		// Type
 962		if (!has_default_type)
 963		{
 964			switch (mType)
 965			{
 966			case TYPE_BOOLEAN:
 967				output_stream << indent << " type=\"boolean\"\n";
 968				break;
 969			case TYPE_INTEGER:
 970				output_stream << indent << " type=\"integer\"\n";
 971				break;
 972			case TYPE_FLOAT:
 973				output_stream << indent << " type=\"float\"\n";
 974				break;
 975			case TYPE_STRING:
 976				output_stream << indent << " type=\"string\"\n";
 977				break;
 978			case TYPE_UUID:
 979				output_stream << indent << " type=\"uuid\"\n";
 980				break;
 981			case TYPE_NODEREF:
 982				output_stream << indent << " type=\"noderef\"\n";
 983				break;
 984			default:
 985				// default on switch(enum) eliminates a warning on linux
 986				break;
 987			};
 988		}
 989
 990		// Encoding
 991		if (!has_default_encoding)
 992		{
 993			switch (mEncoding)
 994			{
 995			case ENCODING_DECIMAL:
 996				output_stream << indent << " encoding=\"decimal\"\n";
 997				break;
 998			case ENCODING_HEX:
 999				output_stream << indent << " encoding=\"hex\"\n";
1000				break;
1001			/*case ENCODING_BASE32:
1002				output_stream << indent << " encoding=\"base32\"\n";
1003				break;*/
1004			default:
1005				// default on switch(enum) eliminates a warning on linux
1006				break;
1007			};
1008		}
1009
1010		// Precision
1011		if (!has_default_precision && (mType == TYPE_INTEGER || mType == TYPE_FLOAT))
1012		{
1013			output_stream << indent << " precision=\"" << mPrecision << "\"\n";
1014		}
1015
1016		// Version
1017		if (mVersionMajor > 0 || mVersionMinor > 0)
1018		{
1019			output_stream << indent << " version=\"" << mVersionMajor << "." << mVersionMinor << "\"\n";
1020		}
1021
1022		// Array length
1023		if (!has_default_length && mLength > 0)
1024		{
1025			output_stream << indent << " length=\"" << mLength << "\"\n";
1026		}
1027	}
1028
1029	{
1030		// Write out attributes
1031		LLXMLAttribList::const_iterator attr_itr;
1032		LLXMLAttribList::const_iterator attr_end = mAttributes.end();
1033		for (attr_itr = mAttributes.begin(); attr_itr != attr_end; ++attr_itr)
1034		{
1035			LLXMLNodePtr child = (*attr_itr).second;
1036			if (child->mDefault.isNull() || child->mDefault->mValue != child->mValue)
1037			{
1038				std::string attr = child->mName->mString;
1039				if (use_type_decorations
1040					&& (attr == "id" ||
1041						attr == "type" ||
1042						attr == "encoding" ||
1043						attr == "precision" ||
1044						attr == "version" ||
1045						attr == "length"))
1046				{
1047					continue; // skip built-in attributes
1048				}
1049				
1050				std::string attr_str = llformat(" %s=\"%s\"",
1051											 attr.c_str(),
1052											 escapeXML(child->mValue).c_str());
1053				output_stream << indent << attr_str << "\n";
1054			}
1055		}
1056	}
1057
1058	// erase last \n before attaching final > or />
1059	output_stream.seekp(-1, std::ios::cur);
1060
1061	if (mChildren.isNull() && mValue == "")
1062	{
1063		output_stream << " />\n";
1064		return;
1065	}
1066	else
1067	{
1068		output_stream << ">\n";
1069		if (mChildren.notNull())
1070		{
1071			// stream non-attributes
1072			std::string next_indent = indent + "    ";
1073			for (LLXMLNode* child = getFirstChild(); child; child = child->getNextSibling())
1074			{
1075				child->writeToOstream(output_stream, next_indent, use_type_decorations);
1076			}
1077		}
1078		if (!mValue.empty())
1079		{
1080			std::string contents = getTextContents();
1081			output_stream << indent << "    " << escapeXML(contents) << "\n";
1082		}
1083		output_stream << indent << "</" << mName->mString << ">\n";
1084	}
1085}
1086
1087void LLXMLNode::findName(const std::string& name, LLXMLNodeList &results)
1088{
1089    LLStringTableEntry* name_entry = gStringTable.checkStringEntry(name);
1090	if (name_entry == mName)
1091	{
1092		results.insert(std::make_pair(this->mName->mString, this));
1093		return;
1094	}
1095	if (mChildren.notNull())
1096	{
1097		LLXMLChildList::const_iterator children_itr;
1098		LLXMLChildList::const_iterator children_end = mChildren->map.end();
1099		for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
1100		{
1101			LLXMLNodePtr child = (*children_itr).second;
1102			child->findName(name_entry, results);
1103		}
1104	}
1105}
1106
1107void LLXMLNode::findName(LLStringTableEntry* name, LLXMLNodeList &results)
1108{
1109	if (name == mName)
1110	{
1111		results.insert(std::make_pair(this->mName->mString, this));
1112		return;
1113	}
1114	if (mChildren.notNull())
1115	{
1116		LLXMLChildList::const_iterator children_itr;
1117		LLXMLChildList::const_iterator children_end = mChildren->map.end();
1118		for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
1119		{
1120			LLXMLNodePtr child = (*children_itr).second;
1121			child->findName(name, results);
1122		}
1123	}
1124}
1125
1126void LLXMLNode::findID(const std::string& id, LLXMLNodeList &results)
1127{
1128	if (id == mID)
1129	{
1130		results.insert(std::make_pair(this->mName->mString, this));
1131		return;
1132	}
1133	if (mChildren.notNull())
1134	{
1135		LLXMLChildList::const_iterator children_itr;
1136		LLXMLChildList::const_iterator children_end = mChildren->map.end();
1137		for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
1138		{
1139			LLXMLNodePtr child = (*children_itr).second;
1140			child->findID(id, results);
1141		}
1142	}
1143}
1144
1145void LLXMLNode::scrubToTree(LLXMLNode *tree)
1146{
1147	if (!tree || tree->mChildren.isNull())
1148	{
1149		return;
1150	}
1151	if (mChildren.notNull())
1152	{
1153		std::vector<LLXMLNodePtr> to_delete_list;
1154		LLXMLChildList::iterator itor = mChildren->map.begin();
1155		while (itor != mChildren->map.end())
1156		{
1157			LLXMLNodePtr child = itor->second;
1158			LLXMLNodePtr child_tree = NULL;
1159			// Look for this child in the default's children
1160			bool found = false;
1161			LLXMLChildList::iterator itor2 = tree->mChildren->map.begin();
1162			while (itor2 != tree->mChildren->map.end())
1163			{
1164				if (child->mName == itor2->second->mName)
1165				{
1166					child_tree = itor2->second;
1167					found = true;
1168				}
1169				++itor2;
1170			}
1171			if (!found)
1172			{
1173				to_delete_list.push_back(child);
1174			}
1175			else
1176			{
1177				child->scrubToTree(child_tree);
1178			}
1179			++itor;
1180		}
1181		std::vector<LLXMLNodePtr>::iterator itor3;
1182		for (itor3=to_delete_list.begin(); itor3!=to_delete_list.end(); ++itor3)
1183		{
1184			(*itor3)->setParent(NULL);
1185		}
1186	}
1187}
1188
1189bool LLXMLNode::getChild(const char* name, LLXMLNodePtr& node, BOOL use_default_if_missing)
1190{
1191    return getChild(gStringTable.checkStringEntry(name), node, use_default_if_missing);
1192}
1193
1194bool LLXMLNode::getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing)
1195{
1196	if (mChildren.notNull())
1197	{
1198		LLXMLChildList::const_iterator child_itr = mChildren->map.find(name);
1199		if (child_itr != mChildren->map.end())
1200		{
1201			node = (*child_itr).second;
1202			return true;
1203		}
1204	}
1205	if (use_default_if_missing && !mDefault.isNull())
1206	{
1207		return mDefault->getChild(name, node, FALSE);
1208	}
1209	node = NULL;
1210	return false;
1211}
1212
1213void LLXMLNode::getChildren(const char* name, LLXMLNodeList &children, BOOL use_default_if_missing) const
1214{
1215    getChildren(gStringTable.checkStringEntry(name), children, use_default_if_missing);
1216}
1217
1218void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, BOOL use_default_if_missing) const
1219{
1220	if (mChildren.notNull())
1221	{
1222		LLXMLChildList::const_iterator child_itr = mChildren->map.find(name);
1223		if (child_itr != mChildren->map.end())
1224		{
1225			LLXMLChildList::const_iterator children_end = mChildren->map.end();
1226			while (child_itr != children_end)
1227			{
1228				LLXMLNodePtr child = (*child_itr).second;
1229				if (name != child->mName)
1230				{
1231					break;
1232				}
1233				children.insert(std::make_pair(child->mName->mString, child));
1234				child_itr++;
1235			}
1236		}
1237	}
1238	if (children.size() == 0 && use_default_if_missing && !mDefault.isNull())
1239	{
1240		mDefault->getChildren(name, children, FALSE);
1241	}
1242}
1243
1244// recursively walks the tree and returns all children at all nesting levels matching the name
1245void LLXMLNode::getDescendants(const LLStringTableEntry* name, LLXMLNodeList &children) const
1246{
1247	if (mChildren.notNull())
1248	{
1249		for (LLXMLChildList::const_iterator child_itr = mChildren->map.begin();
1250			 child_itr != mChildren->map.end(); ++child_itr)
1251		{
1252			LLXMLNodePtr child = (*child_itr).second;
1253			if (name == child->mName)
1254			{
1255				children.insert(std::make_pair(child->mName->mString, child));
1256			}
1257			// and check each child as well
1258			child->getDescendants(name, children);
1259		}
1260	}
1261}
1262
1263bool LLXMLNode::getAttribute(const char* name, LLXMLNodePtr& node, BOOL use_default_if_missing)
1264{
1265    return getAttribute(gStringTable.checkStringEntry(name), node, use_default_if_missing);
1266}
1267
1268bool LLXMLNode::getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing)
1269{
1270	LLXMLAttribList::const_iterator child_itr = mAttributes.find(name);
1271	if (child_itr != mAttributes.end())
1272	{
1273		node = (*child_itr).second;
1274		return true;
1275	}
1276	if (use_default_if_missing && !mDefault.isNull())
1277	{
1278		return mDefault->getAttribute(name, node, FALSE);
1279	}
1280	
1281	return false;
1282}
1283
1284bool LLXMLNode::setAttributeString(const char* attr, const std::string& value)
1285{
1286	LLStringTableEntry* name = gStringTable.checkStringEntry(attr);
1287	LLXMLAttribList::const_iterator child_itr = mAttributes.find(name);
1288	if (child_itr != mAttributes.end())
1289	{
1290		LLXMLNodePtr node = (*child_itr).second;
1291		node->setValue(value);
1292		return true;
1293	}
1294	return false;
1295}
1296
1297BOOL LLXMLNode::hasAttribute(const char* name )
1298{
1299	LLXMLNodePtr node;
1300	return getAttribute(name, node);
1301}
1302
1303// the structure of these getAttribute_ functions is ugly, but it's because the
1304// underlying system is based on BOOL and LLString; if we change
1305// so that they're based on more generic mechanisms, these will be
1306// simplified.
1307bool LLXMLNode::getAttribute_bool(const char* name, bool& value )
1308{
1309	LLXMLNodePtr node;
1310    if (!getAttribute(name, node))
1311    {
1312        return false;
1313    }
1314    BOOL temp;
1315	bool retval = node->getBoolValue(1, &temp);
1316    value = temp;
1317    return retval;
1318}
1319
1320BOOL LLXMLNode::getAttributeBOOL(const char* name, BOOL& value )
1321{
1322	LLXMLNodePtr node;
1323	return (getAttribute(name, node) && node->getBoolValue(1, &value));
1324}
1325
1326BOOL LLXMLNode::getAttributeU8(const char* name, U8& value )
1327{
1328	LLXMLNodePtr node;
1329	return (getAttribute(name, node) && node->getByteValue(1, &value));
1330}
1331
1332BOOL LLXMLNode::getAttributeS8(const char* name, S8& value )
1333{
1334	LLXMLNodePtr node;
1335	S32 val;
1336	if (!(getAttribute(name, node) && node->getIntValue(1, &val)))
1337	{
1338		return false;
1339	}
1340	value = val;
1341	return true;
1342}
1343
1344BOOL LLXMLNode::getAttributeU16(const char* name, U16& value )
1345{
1346	LLXMLNodePtr node;
1347	U32 val;
1348	if (!(getAttribute(name, node) && node->getUnsignedValue(1, &val)))
1349	{
1350		return false;
1351	}
1352	value = val;
1353	return true;
1354}
1355
1356BOOL LLXMLNode::getAttributeS16(const char* name, S16& value )
1357{
1358	LLXMLNodePtr node;
1359	S32 val;
1360	if (!(getAttribute(name, node) && node->getIntValue(1, &val)))
1361	{
1362		return false;
1363	}
1364	value = val;
1365	return true;
1366}
1367
1368BOOL LLXMLNode::getAttributeU32(const char* name, U32& value )
1369{
1370	LLXMLNodePtr node;
1371	return (getAttribute(name, node) && node->getUnsignedValue(1, &value));
1372}
1373
1374BOOL LLXMLNode::getAttributeS32(const char* name, S32& value )
1375{
1376	LLXMLNodePtr node;
1377	return (getAttribute(name, node) && node->getIntValue(1, &value));
1378}
1379
1380BOOL LLXMLNode::getAttributeF32(const char* name, F32& value )
1381{
1382	LLXMLNodePtr node;
1383	return (getAttribute(name, node) && node->getFloatValue(1, &value));
1384}
1385
1386BOOL LLXMLNode::getAttributeF64(const char* name, F64& value )
1387{
1388	LLXMLNodePtr node;
1389	return (getAttribute(name, node) && node->getDoubleValue(1, &value));
1390}
1391
1392BOOL LLXMLNode::getAttributeColor(const char* name, LLColor4& value )
1393{
1394	LLXMLNodePtr node;
1395	return (getAttribute(name, node) && node->getFloatValue(4, value.mV));
1396}
1397
1398BOOL LLXMLNode::getAttributeColor4(const char* name, LLColor4& value )
1399{
1400	LLXMLNodePtr node;
1401	return (getAttribute(name, node) && node->getFloatValue(4, value.mV));
1402}
1403
1404BOOL LLXMLNode::getAttributeColor4U(const char* name, LLColor4U& value )
1405{
1406	LLXMLNodePtr node;
1407	return (getAttribute(name, node) && node->getByteValue(4, value.mV));
1408}
1409
1410BOOL LLXMLNode::getAttributeVector3(const char* name, LLVector3& value )
1411{
1412	LLXMLNodePtr node;
1413	return (getAttribute(name, node) && node->getFloatValue(3, value.mV));
1414}
1415
1416BOOL LLXMLNode::getAttributeVector3d(const char* name, LLVector3d& value )
1417{
1418	LLXMLNodePtr node;
1419	return (getAttribute(name, node) && node->getDoubleValue(3, value.mdV));
1420}
1421
1422BOOL LLXMLNode::getAttributeQuat(const char* name, LLQuaternion& value )
1423{
1424	LLXMLNodePtr node;
1425	return (getAttribute(name, node) && node->getFloatValue(4, value.mQ));
1426}
1427
1428BOOL LLXMLNode::getAttributeUUID(const char* name, LLUUID& value )
1429{
1430	LLXMLNodePtr node;
1431	return (getAttribute(name, node) && node->getUUIDValue(1, &value));
1432}
1433
1434BOOL LLXMLNode::getAttributeString(const char* name, std::string& value )
1435{
1436	LLXMLNodePtr node;
1437	if (!getAttribute(name, node))
1438	{
1439		return false;
1440	}
1441	value = node->getValue();
1442	return true;
1443}
1444
1445LLXMLNodePtr LLXMLNode::getRoot()
1446{
1447	if (mParent == NULL)
1448	{
1449		return this;
1450	}
1451	return mParent->getRoot();
1452}
1453
1454/*static */
1455const char *LLXMLNode::skipWhitespace(const char *str)
1456{
1457	// skip whitespace characters
1458	while (str[0] == ' ' || str[0] == '\t' || str[0] == '\n') ++str;
1459	return str;
1460}
1461
1462/*static */
1463const char *LLXMLNode::skipNonWhitespace(const char *str)
1464{
1465	// skip non-whitespace characters
1466	while (str[0] != ' ' && str[0] != '\t' && str[0] != '\n' && str[0] != 0) ++str;
1467	return str;
1468}
1469
1470/*static */
1471const char *LLXMLNode::parseInteger(const char *str, U64 *dest, BOOL *is_negative, U32 precision, Encoding encoding)
1472{
1473	*dest = 0;
1474	*is_negative = FALSE;
1475
1476	str = skipWhitespace(str);
1477
1478	if (str[0] == 0) return NULL;
1479
1480	if (encoding == ENCODING_DECIMAL || encoding == ENCODING_DEFAULT)
1481	{
1482		if (str[0] == '+')
1483		{
1484			++str;
1485		}
1486		if (str[0] == '-')
1487		{
1488			*is_negative = TRUE;
1489			++str;
1490		}
1491
1492		str = skipWhitespace(str);
1493
1494		U64 ret = 0;
1495		while (str[0] >= '0' && str[0] <= '9')
1496		{
1497			ret *= 10;
1498			ret += str[0] - '0';
1499			++str;
1500		}
1501
1502		if (str[0] == '.')
1503		{
1504			// If there is a fractional part, skip it
1505			str = skipNonWhitespace(str);
1506		}
1507
1508		*dest = ret;
1509		return str;
1510	}
1511	if (encoding == ENCODING_HEX)
1512	{
1513		U64 ret = 0;
1514		str = skipWhitespace(str);
1515		for (U32 pos=0; pos<(precision/4); ++pos)
1516		{
1517			ret <<= 4;
1518			str = skipWhitespace(str);
1519			if (str[0] >= '0' && str[0] <= '9')
1520			{
1521				ret += str[0] - '0';
1522			} 
1523			else if (str[0] >= 'a' && str[0] <= 'f')
1524			{
1525				ret += str[0] - 'a' + 10;
1526			}
1527			else if (str[0] >= 'A' && str[0] <= 'F')
1528			{
1529				ret += str[0] - 'A' + 10;
1530			}
1531			else
1532			{
1533				return NULL;
1534			}
1535			++str;
1536		}
1537
1538		*dest = ret;
1539		return str;
1540	}
1541	return NULL;
1542}
1543
1544// 25 elements - decimal expansions of 1/(2^n), multiplied by 10 each iteration
1545const U64 float_coeff_table[] = 
1546	{ 5, 25, 125, 625, 3125, 
1547	  15625, 78125, 390625, 1953125, 9765625,
1548	  48828125, 244140625, 1220703125, 6103515625LL, 30517578125LL,
1549	  152587890625LL, 762939453125LL, 3814697265625LL, 19073486328125LL, 95367431640625LL,
1550	  476837158203125LL, 2384185791015625LL, 11920928955078125LL, 59604644775390625LL, 298023223876953125LL };
1551
1552// 36 elements - decimal expansions of 1/(2^n) after the last 28, truncated, no multiply each iteration
1553const U64 float_coeff_table_2[] =
1554	{  149011611938476562LL,74505805969238281LL,
1555	   37252902984619140LL, 18626451492309570LL, 9313225746154785LL, 4656612873077392LL,
1556	   2328306436538696LL,  1164153218269348LL,  582076609134674LL,  291038304567337LL,
1557	   145519152283668LL,   72759576141834LL,    36379788070917LL,   18189894035458LL,
1558	   9094947017729LL,     4547473508864LL,     2273736754432LL,    1136868377216LL,
1559	   568434188608LL,      284217094304LL,      142108547152LL,     71054273576LL,
1560	   35527136788LL,       17763568394LL,       8881784197LL,       4440892098LL,
1561	   2220446049LL,        1110223024LL,        555111512LL,        277555756LL,
1562	   138777878,         69388939,          34694469,         17347234,
1563	   8673617,           4336808,           2168404,          1084202,
1564	   542101,            271050,            135525,           67762,
1565	};
1566
1567/*static */
1568const char *LLXMLNode::parseFloat(const char *str, F64 *dest, U32 precision, Encoding encoding)
1569{
1570	str = skipWhitespace(str);
1571
1572	if (str[0] == 0) return NULL;
1573
1574	if (encoding == ENCODING_DECIMAL || encoding == ENCODING_DEFAULT)
1575	{
1576		str = skipWhitespace(str);
1577
1578		if (memcmp(str, "inf", 3) == 0)
1579		{
1580			*(U64 *)dest = 0x7FF0000000000000ll;
1581			return str + 3;
1582		}
1583		if (memcmp(str, "-inf", 4) == 0)
1584		{
1585			*(U64 *)dest = 0xFFF0000000000000ll;
1586			return str + 4;
1587		}
1588		if (memcmp(str, "1.#INF", 6) == 0)
1589		{
1590			*(U64 *)dest = 0x7FF0000000000000ll;
1591			return str + 6;
1592		}
1593		if (memcmp(str, "-1.#INF", 7) == 0)
1594		{
1595			*(U64 *)dest = 0xFFF0000000000000ll;
1596			return str + 7;
1597		}
1598
1599		F64 negative = 1.0f;
1600		if (str[0] == '+')
1601		{
1602			++str;
1603		}
1604		if (str[0] == '-')
1605		{
1606			negative = -1.0f;
1607			++str;
1608		}
1609
1610		const char* base_str = str;
1611		str = skipWhitespace(str);
1612
1613		// Parse the integer part of the expression
1614		U64 int_part = 0;
1615		while (str[0] >= '0' && str[0] <= '9')
1616		{
1617			int_part *= 10;
1618			int_part += U64(str[0] - '0');
1619			++str;
1620		}
1621
1622		U64 f_part = 0;//, f_decimal = 1;
1623		if (str[0] == '.')
1624		{
1625			++str;
1626			U64 remainder = 0;
1627			U32 pos = 0;
1628			// Parse the decimal part of the expression
1629			while (str[0] >= '0' && str[0] <= '9' && pos < 25)
1630			{
1631				remainder = (remainder*10) + U64(str[0] - '0');
1632				f_part <<= 1;
1633				//f_decimal <<= 1;
1634				// Check the n'th bit
1635				if (remainder >= float_coeff_table[pos])
1636				{
1637					remainder -= float_coeff_table[pos];
1638					f_part |= 1;
1639				}
1640				++pos;
1641				++str;
1642			}
1643			if (pos == 25)
1644			{
1645				// Drop any excessive digits
1646				while (str[0] >= '0' && str[0] <= '9')
1647				{
1648					++str;
1649				}
1650			}
1651			else
1652			{
1653				while (pos < 25)
1654				{
1655					remainder *= 10;
1656					f_part <<= 1;
1657					//f_decimal <<= 1;
1658					// Check the n'th bit
1659					if (remainder >= float_coeff_table[pos])
1660					{
1661						remainder -= float_coeff_table[pos];
1662						f_part |= 1;
1663					}
1664					++pos;
1665				}
1666			}
1667			pos = 0;
1668			while (pos < 36)
1669			{
1670				f_part <<= 1;
1671				//f_decimal <<= 1;
1672				if (remainder >= float_coeff_table_2[pos])
1673				{
1674					remainder -= float_coeff_table_2[pos];
1675					f_part |= 1;
1676				}
1677				++pos;
1678			}
1679		}
1680		
1681		F64 ret = F64(int_part) + (F64(f_part)/F64(1LL<<61));
1682
1683		F64 exponent = 1.f;
1684		if (str[0] == 'e')
1685		{
1686			// Scientific notation!
1687			++str;
1688			U64 exp;
1689			BOOL is_negative;
1690			str = parseInteger(str, &exp, &is_negative, 64, ENCODING_DECIMAL);
1691			if (str == NULL)
1692			{
1693				exp = 1;
1694			}
1695			F64 exp_d = F64(exp) * (is_negative?-1:1);
1696			exponent = pow(10.0, exp_d);
1697		}
1698
1699		if (str == base_str)
1700		{
1701			// no digits parsed
1702			return NULL;
1703		}
1704		else
1705		{
1706			*dest = ret*negative*exponent;
1707			return str;
1708		}
1709	}
1710	if (encoding == ENCODING_HEX)
1711	{
1712		U64 bytes_dest;
1713		BOOL is_negative;
1714		str = parseInteger(str, (U64 *)&bytes_dest, &is_negative, precision, ENCODING_HEX);
1715		// Upcast to F64
1716		switch (precision)
1717		{
1718		case 32:
1719			{
1720				U32 short_dest = (U32)bytes_dest;
1721				F32 ret_val = *(F32 *)&short_dest;
1722				*dest = ret_val;
1723			}
1724			break;
1725		case 64:
1726			*dest = *(F64 *)&bytes_dest;
1727			break;
1728		default:
1729			return NULL;
1730		}
1731		return str;
1732	}
1733	return NULL;
1734}
1735
1736U32 LLXMLNode::getBoolValue(U32 expected_length, BOOL *array)
1737{
1738	llassert(array);
1739
1740	// Check type - accept booleans or strings
1741	if (mType != TYPE_BOOLEAN && mType != TYPE_STRING && mType != TYPE_UNKNOWN)
1742	{
1743		return 0;
1744	}
1745
1746	std::string *str_array = new std::string[expected_length];
1747
1748	U32 length = getStringValue(expected_length, str_array);
1749
1750	U32 ret_length = 0;
1751	for (U32 i=0; i<length; ++i)
1752	{
1753		LLStringUtil::toLower(str_array[i]);
1754		if (str_array[i] == "false")
1755		{
1756			array[ret_length++] = FALSE;
1757		}
1758		else if (str_array[i] == "true")
1759		{
1760			array[ret_length++] = TRUE;
1761		}
1762	}
1763
1764	delete[] str_array;
1765
1766#if LL_DEBUG
1767	if (ret_length != expected_length)
1768	{
1769		lldebugs << "LLXMLNode::getBoolValue() failed for node named '" 
1770			<< mName->mString << "' -- expected " << expected_length << " but "
1771			<< "only found " << ret_length << llendl;
1772	}
1773#endif
1774	return ret_length;
1775}
1776
1777U32 LLXMLNode::getByteValue(U32 expected_length, U8 *array, Encoding encoding)
1778{
1779	llassert(array);
1780
1781	// Check type - accept bytes or integers (below 256 only)
1782	if (mType != TYPE_INTEGER 
1783		&& mType != TYPE_UNKNOWN)
1784	{
1785		return 0;
1786	}
1787
1788	if (mLength > 0 && mLength != expected_length)
1789	{
1790		llwarns << "XMLNode::getByteValue asked for " << expected_length 
1791			<< " elements, while node has " << mLength << llendl;
1792		return 0;
1793	}
1794
1795	if (encoding == ENCODING_DEFAULT)
1796	{
1797		encoding = mEncoding;
1798	}
1799
1800	const char *value_string = mValue.c_str();
1801
1802	U32 i;
1803	for (i=0; i<expected_length; ++i)
1804	{
1805		U64 value;
1806		BOOL is_negative;
1807		value_string = parseInteger(value_string, &value, &is_negative, 8, encoding);
1808		if (value_string == NULL)
1809		{
1810			break;
1811		}
1812		if (value > 255 || is_negative)
1813		{
1814			llwarns << "getByteValue: Value outside of valid range." << llendl;
1815			break;
1816		}
1817		array[i] = U8(value);
1818	}
1819#if LL_DEBUG
1820	if (i != expected_length)
1821	{
1822		lldebugs << "LLXMLNode::getByteValue() failed for node named '" 
1823			<< mName->mString << "' -- expected " << expected_length << " but "
1824			<< "only found " << i << llendl;
1825	}
1826#endif
1827	return i;
1828}
1829
1830U32 LLXMLNode::getIntValue(U32 expected_length, S32 *array, Encoding encoding)
1831{
1832	llassert(array);
1833
1834	// Check type - accept bytes or integers
1835	if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN)
1836	{
1837		return 0;
1838	}
1839
1840	if (mLength > 0 && mLength != expected_length)
1841	{
1842		llwarns << "XMLNode::getIntValue asked for " << expected_length 
1843			<< " elements, while node has " << mLength << llendl;
1844		return 0;
1845	}
1846
1847	if (encoding == ENCODING_DEFAULT)
1848	{
1849		encoding = mEncoding;
1850	}
1851
1852	const char *value_string = mValue.c_str();
1853
1854	U32 i = 0;
1855	for (i=0; i<expected_length; ++i)
1856	{
1857		U64 value;
1858		BOOL is_negative;
1859		value_string = parseInteger(value_string, &value, &is_negative, 32, encoding);
1860		if (value_string == NULL)
1861		{
1862			break;
1863		}
1864		if (value > 0x7fffffff)
1865		{
1866			llwarns << "getIntValue: Value outside of valid range." << llendl;
1867			break;
1868		}
1869		array[i] = S32(value) * (is_negative?-1:1);
1870	}
1871
1872#if LL_DEBUG
1873	if (i != expected_length)
1874	{
1875		lldebugs << "LLXMLNode::getIntValue() failed for node named '" 
1876			<< mName->mString << "' -- expected " << expected_length << " but "
1877			<< "only found " << i << llendl;
1878	}
1879#endif
1880	return i;
1881}
1882
1883U32 LLXMLNode::getUnsignedValue(U32 expected_length, U32 *array, Encoding encoding)
1884{
1885	llassert(array);
1886
1887	// Check type - accept bytes or integers
1888	if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN)
1889	{
1890		return 0;
1891	}
1892
1893	if (mLength > 0 && mLength != expected_length)
1894	{
1895		llwarns << "XMLNode::getUnsignedValue asked for " << expected_length 
1896			<< " elements, while node has " << mLength << llendl;
1897		return 0;
1898	}
1899
1900	if (encoding == ENCODING_DEFAULT)
1901	{
1902		encoding = mEncoding;
1903	}
1904
1905	const char *value_string = mValue.c_str();
1906
1907	U32 i = 0;
1908	// Int type
1909	for (i=0; i<expected_length; ++i)
1910	{
1911		U64 value;
1912		BOOL is_negative;
1913		value_string = parseInteger(value_string, &value, &is_negative, 32, encoding);
1914		if (value_string == NULL)
1915		{
1916			break;
1917		}
1918		if (is_negative || value > 0xffffffff)
1919		{
1920			llwarns << "getUnsignedValue: Value outside of valid range." << llendl;
1921			break;
1922		}
1923		array[i] = U32(value);
1924	}
1925
1926#if LL_DEBUG
1927	if (i != expected_length)
1928	{
1929		lldebugs << "LLXMLNode::getUnsignedValue() failed for node named '" 
1930			<< mName->mString << "' -- expected " << expected_length << " but "
1931			<< "only found " << i << llendl;
1932	}
1933#endif
1934
1935	return i;
1936}
1937
1938U32 LLXMLNode::getLongValue(U32 expected_length, U64 *array, Encoding encoding)
1939{
1940	llassert(array);
1941
1942	// Check type - accept bytes or integers
1943	if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN)
1944	{
1945		return 0;
1946	}
1947
1948	if (mLength > 0 && mLength != expected_length)
1949	{
1950		llwarns << "XMLNode::getLongValue asked for " << expected_length << " elements, while node has " << mLength << llendl;
1951		return 0;
1952	}
1953
1954	if (encoding == ENCODING_DEFAULT)
1955	{
1956		encoding = mEncoding;
1957	}
1958
1959	const char *value_string = mValue.c_str();
1960
1961	U32 i = 0;
1962	// Int type
1963	for (i=0; i<expected_length; ++i)
1964	{
1965		U64 value;
1966		BOOL is_negative;
1967		value_string = parseInteger(value_string, &value, &is_negative, 64, encoding);
1968		if (value_string == NULL)
1969		{
1970			break;
1971		}
1972		if (is_negative)
1973		{
1974			llwarns << "getLongValue: Value outside of valid range." << llendl;
1975			break;
1976		}
1977		array[i] = value;
1978	}
1979
1980#if LL_DEBUG
1981	if (i != expected_length)
1982	{
1983		lldebugs << "LLXMLNode::getLongValue() failed for node named '" 
1984			<< mName->mString << "' -- expected " << expected_length << " but "
1985			<< "only found " << i << llendl;
1986	}
1987#endif
1988
1989	return i;
1990}
1991
1992U32 LLXMLNode::getFloatValue(U32 expected_length, F32 *array, Encoding encoding)
1993{
1994	llassert(array);
1995
1996	// Check type - accept only floats or doubles
1997	if (mType != TYPE_FLOAT && mType != TYPE_UNKNOWN)
1998	{
1999		return 0;
2000	}
2001
2002	if (mLength > 0 && mLength != expected_length)
2003	{
2004		llwarns << "XMLNode::getFloatValue asked for " << expected_length << " elements, while node has " << mLength << llendl;
2005		return 0;
2006	}
2007
2008	if (encoding == ENCODING_DEFAULT)
2009	{
2010		encoding = mEncoding;
2011	}
2012
2013	const char *value_string = mValue.c_str();
2014
2015	U32 i;
2016	for (i=0; i<expected_length; ++i)
2017	{
2018		F64 value;
2019		value_string = parseFloat(value_string, &value, 32, encoding);
2020		if (value_string == NULL)
2021		{
2022			break;
2023		}
2024		array[i] = F32(value);
2025	}
2026#if LL_DEBUG
2027	if (i != expected_length)
2028	{
2029		lldebugs << "LLXMLNode::getFloatValue() failed for node named '" 
2030			<< mName->mString << "' -- expected " << expected_length << " but "
2031			<< "only found " << i << llendl;
2032	}
2033#endif
2034	return i;
2035}
2036
2037U32 LLXMLNode::getDoubleValue(U32 expected_length, F64 *array, Encoding encoding)
2038{
2039	llassert(array);
2040
2041	// Check type - accept only floats or doubles
2042	if (mType != TYPE_FLOAT && mType != TYPE_UNKNOWN)
2043	{
2044		return 0;
2045	}
2046
2047	if (mLength > 0 && mLength != expected_length)
2048	{
2049		llwarns << "XMLNode::getDoubleValue asked for " << expected_length << " elements, while node has " << mLength << llendl;
2050		return 0;
2051	}
2052
2053	if (encoding == ENCODING_DEFAULT)
2054	{
2055		encoding = mEncoding;
2056	}
2057
2058	const char *value_string = mValue.c_str();
2059
2060	U32 i;
2061	for (i=0; i<expected_length; ++i)
2062	{
2063		F64 value;
2064		value_string = parseFloat(value_string, &value, 64, encoding);
2065		if (value_string == NULL)
2066		{
2067			break;
2068		}
2069		array[i] = value;
2070	}
2071#if LL_DEBUG
2072	if (i != expected_length)
2073	{
2074		lldebugs << "LLXMLNode::getDoubleValue() failed for node named '" 
2075			<< mName->mString << "' -- expected " << expected_length << " but "
2076			<< "only found " << i << llendl;
2077	}
2078#endif
2079	return i;
2080}
2081
2082U32 LLXMLNode::getStringValue(U32 expected_length, std::string *array)
2083{
2084	llassert(array);
2085
2086	// Can always return any value as a string
2087
2088	if (mLength > 0 && mLength != expected_length)
2089	{
2090		llwarns << "XMLNode::getStringValue asked for " << expected_length << " elements, while node has " << mLength << llendl;
2091		return 0;
2092	}
2093
2094	U32 num_returned_strings = 0;
2095
2096	// Array of strings is whitespace-separated
2097	const std::string sep(" \n\t");
2098	
2099	std::string::size_type n = 0;
2100	std::string::size_type m = 0;
2101	while(1)
2102	{
2103		if (num_returned_strings >= expected_length)
2104		{
2105			break;
2106		}
2107		n = mValue.find_first_not_of(sep, m);
2108		m = mValue.find_first_of(sep, n);
2109		if (m == std::string::npos)
2110		{
2111			break;
2112		}
2113		array[num_returned_strings++] = mValue.substr(n,m-n);
2114	}
2115	if (n != std::string::npos && num_returned_strings < expected_length)
2116	{
2117		array[num_returned_strings++] = mValue.substr(n);
2118	}
2119#if LL_DEBUG
2120	if (num_returned_strings != expected_length)
2121	{
2122		lldebugs << "LLXMLNode::getStringValue() failed for node named '" 
2123			<< mName->mString << "' -- expected " << expected_length << " but "
2124			<< "only found " << num_returned_strings << llendl;
2125	}
2126#endif
2127
2128	return num_returned_strings;
2129}
2130
2131U32 LLXMLNode::getUUIDValue(U32 expected_length, LLUUID *array)
2132{
2133	llassert(array);
2134
2135	// Check type
2136	if (mType != TYPE_UUID && mType != TYPE_UNKNOWN)
2137	{
2138		return 0;
2139	}
2140
2141	const char *value_string = mValue.c_str();
2142
2143	U32 i;
2144	for (i=0; i<expected_length; ++i)
2145	{
2146		LLUUID uuid_value;
2147		value_string = skipWhitespace(value_string);
2148
2149		if (strlen(value_string) < (UUID_STR_LENGTH-1))		/* Flawfinder: ignore */
2150		{
2151			break;
2152		}
2153		char uuid_string[UUID_STR_LENGTH];		/* Flawfinder: ignore */
2154		memcpy(uuid_string, value_string, (UUID_STR_LENGTH-1));		/* Flawfind…

Large files files are truncated, but you can click here to view the full file