PageRenderTime 189ms CodeModel.GetById 37ms app.highlight 139ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llxuixml/llxuiparser.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1756 lines | 1373 code | 235 blank | 148 comment | 163 complexity | a7ffd009142e689ab4d36a96c224e1cf MD5 | raw file
   1/** 
   2 * @file llxuiparser.cpp
   3 * @brief Utility functions for handling XUI structures in XML
   4 *
   5 * $LicenseInfo:firstyear=2003&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "linden_common.h"
  28
  29#include "llxuiparser.h"
  30
  31#include "llxmlnode.h"
  32
  33#ifdef LL_STANDALONE
  34#include <expat.h>
  35#else
  36#include "expat/expat.h"
  37#endif
  38
  39#include <fstream>
  40#include <boost/tokenizer.hpp>
  41//#include <boost/spirit/include/qi.hpp>
  42#include <boost/spirit/include/classic_core.hpp>
  43
  44#include "lluicolor.h"
  45
  46using namespace BOOST_SPIRIT_CLASSIC_NS;
  47
  48const S32 MAX_STRING_ATTRIBUTE_SIZE = 40;
  49
  50static 	LLInitParam::Parser::parser_read_func_map_t sXSDReadFuncs;
  51static 	LLInitParam::Parser::parser_write_func_map_t sXSDWriteFuncs;
  52static 	LLInitParam::Parser::parser_inspect_func_map_t sXSDInspectFuncs;
  53
  54static 	LLInitParam::Parser::parser_read_func_map_t sSimpleXUIReadFuncs;
  55static 	LLInitParam::Parser::parser_write_func_map_t sSimpleXUIWriteFuncs;
  56static 	LLInitParam::Parser::parser_inspect_func_map_t sSimpleXUIInspectFuncs;
  57
  58const char* NO_VALUE_MARKER = "no_value";
  59
  60const S32 LINE_NUMBER_HERE = 0;
  61
  62struct MaxOccursValues : public LLInitParam::TypeValuesHelper<U32, MaxOccursValues>
  63{
  64	static void declareValues()
  65	{
  66		declare("unbounded", U32_MAX);
  67	}
  68};
  69
  70struct Occurs : public LLInitParam::Block<Occurs>
  71{
  72	Optional<U32>					minOccurs;
  73	Optional<U32, MaxOccursValues>	maxOccurs;
  74
  75	Occurs()
  76	:	minOccurs("minOccurs", 0),
  77		maxOccurs("maxOccurs", U32_MAX)
  78
  79	{}
  80};
  81
  82
  83typedef enum
  84{
  85	USE_REQUIRED,
  86	USE_OPTIONAL
  87} EUse;
  88
  89namespace LLInitParam
  90{
  91	template<>
  92	struct TypeValues<EUse> : public TypeValuesHelper<EUse>
  93	{
  94		static void declareValues()
  95		{
  96			declare("required", USE_REQUIRED);
  97			declare("optional", USE_OPTIONAL);
  98		}
  99	};
 100}
 101
 102struct Element;
 103struct Group;
 104struct Choice;
 105struct Sequence;
 106struct Any;
 107
 108struct Attribute : public LLInitParam::Block<Attribute>
 109{
 110	Mandatory<std::string>	name;
 111	Mandatory<std::string>	type;
 112	Mandatory<EUse>			use;
 113	
 114	Attribute()
 115	:	name("name"),
 116		type("type"),
 117		use("use")
 118	{}
 119};
 120
 121struct Any : public LLInitParam::Block<Any, Occurs>
 122{
 123	Optional<std::string> _namespace;
 124
 125	Any()
 126	:	_namespace("namespace")
 127	{}
 128};
 129
 130struct All : public LLInitParam::Block<All, Occurs>
 131{
 132	Multiple< Lazy<Element> > elements;
 133
 134	All()
 135	:	elements("element")
 136	{
 137		maxOccurs = 1;
 138	}
 139};
 140
 141struct Choice : public LLInitParam::ChoiceBlock<Choice, Occurs>
 142{
 143	Alternative< Lazy<Element> >	element;
 144	Alternative< Lazy<Group> >		group;
 145	Alternative< Lazy<Choice> >		choice;
 146	Alternative< Lazy<Sequence> >	sequence;
 147	Alternative< Lazy<Any> >		any;
 148
 149	Choice()
 150	:	element("element"),
 151		group("group"),
 152		choice("choice"),
 153		sequence("sequence"),
 154		any("any")
 155	{}
 156
 157};
 158
 159struct Sequence : public LLInitParam::ChoiceBlock<Sequence, Occurs>
 160{
 161	Alternative< Lazy<Element> >	element;
 162	Alternative< Lazy<Group> >		group;
 163	Alternative< Lazy<Choice> >		choice;
 164	Alternative< Lazy<Sequence> >	sequence;
 165	Alternative< Lazy<Any> >		any;
 166};
 167
 168struct GroupContents : public LLInitParam::ChoiceBlock<GroupContents, Occurs>
 169{
 170	Alternative<All>		all;
 171	Alternative<Choice>		choice;
 172	Alternative<Sequence>	sequence;
 173
 174	GroupContents()
 175	:	all("all"),
 176		choice("choice"),
 177		sequence("sequence")
 178	{}
 179};
 180
 181struct Group : public LLInitParam::Block<Group, GroupContents>
 182{
 183	Optional<std::string>	name,
 184							ref;
 185
 186	Group()
 187	:	name("name"),
 188		ref("ref")
 189	{}
 190};
 191
 192struct Restriction : public LLInitParam::Block<Restriction>
 193{
 194};
 195
 196struct Extension : public LLInitParam::Block<Extension>
 197{
 198};
 199
 200struct SimpleContent : public LLInitParam::ChoiceBlock<SimpleContent>
 201{
 202	Alternative<Restriction> restriction;
 203	Alternative<Extension> extension;
 204
 205	SimpleContent()
 206	:	restriction("restriction"),
 207		extension("extension")
 208	{}
 209};
 210
 211struct SimpleType : public LLInitParam::Block<SimpleType>
 212{
 213	// TODO
 214};
 215
 216struct ComplexContent : public LLInitParam::Block<ComplexContent, SimpleContent>
 217{
 218	Optional<bool> mixed;
 219
 220	ComplexContent()
 221	:	mixed("mixed", true)
 222	{}
 223};
 224
 225struct ComplexTypeContents : public LLInitParam::ChoiceBlock<ComplexTypeContents>
 226{
 227	Alternative<SimpleContent>	simple_content;
 228	Alternative<ComplexContent> complex_content;
 229	Alternative<Group>			group;
 230	Alternative<All>			all;
 231	Alternative<Choice>			choice;
 232	Alternative<Sequence>		sequence;
 233
 234	ComplexTypeContents()
 235	:	simple_content("simpleContent"),
 236		complex_content("complexContent"),
 237		group("group"),
 238		all("all"),
 239		choice("choice"),
 240		sequence("sequence")
 241	{}
 242};
 243
 244struct ComplexType : public LLInitParam::Block<ComplexType, ComplexTypeContents>
 245{
 246	Optional<std::string>			name;
 247	Optional<bool>					mixed;
 248
 249	Multiple<Attribute>				attribute;
 250	Multiple< Lazy<Element> >			elements;
 251
 252	ComplexType()
 253	:	name("name"),
 254		attribute("xs:attribute"),
 255		elements("xs:element"),
 256		mixed("mixed")
 257	{
 258	}
 259};
 260
 261struct ElementContents : public LLInitParam::ChoiceBlock<ElementContents, Occurs>
 262{
 263	Alternative<SimpleType>		simpleType;
 264	Alternative<ComplexType>	complexType;
 265
 266	ElementContents()
 267	:	simpleType("simpleType"),
 268		complexType("complexType")
 269	{}
 270};
 271
 272struct Element : public LLInitParam::Block<Element, ElementContents>
 273{
 274	Optional<std::string>	name,
 275							ref,
 276							type;
 277
 278	Element()
 279	:	name("xs:name"),
 280		ref("xs:ref"),
 281		type("xs:type")
 282	{}
 283};
 284
 285struct Schema : public LLInitParam::Block<Schema>
 286{
 287private:
 288	Mandatory<std::string>	targetNamespace,
 289							xmlns,
 290							xs;
 291
 292public:
 293	Optional<std::string>	attributeFormDefault,
 294							elementFormDefault;
 295
 296	Mandatory<Element>		root_element;
 297	
 298	void setNameSpace(const std::string& ns) {targetNamespace = ns; xmlns = ns;}
 299
 300	Schema(const std::string& ns = LLStringUtil::null)
 301	:	attributeFormDefault("attributeFormDefault"),
 302		elementFormDefault("elementFormDefault"),
 303		xs("xmlns:xs"),
 304		targetNamespace("targetNamespace"),
 305		xmlns("xmlns"),
 306		root_element("xs:element")
 307	{
 308		attributeFormDefault = "unqualified";
 309		elementFormDefault = "qualified";
 310		xs = "http://www.w3.org/2001/XMLSchema";
 311		if (!ns.empty())
 312		{
 313			setNameSpace(ns);
 314		};
 315	}
 316
 317};
 318
 319//
 320// LLXSDWriter
 321//
 322LLXSDWriter::LLXSDWriter()
 323: Parser(sXSDReadFuncs, sXSDWriteFuncs, sXSDInspectFuncs)
 324{
 325	registerInspectFunc<bool>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:boolean", _1, _2, _3, _4));
 326	registerInspectFunc<std::string>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
 327	registerInspectFunc<U8>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedByte", _1, _2, _3, _4));
 328	registerInspectFunc<S8>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedByte", _1, _2, _3, _4));
 329	registerInspectFunc<U16>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedShort", _1, _2, _3, _4));
 330	registerInspectFunc<S16>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedShort", _1, _2, _3, _4));
 331	registerInspectFunc<U32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedInt", _1, _2, _3, _4));
 332	registerInspectFunc<S32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:integer", _1, _2, _3, _4));
 333	registerInspectFunc<F32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:float", _1, _2, _3, _4));
 334	registerInspectFunc<F64>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:double", _1, _2, _3, _4));
 335	registerInspectFunc<LLColor4>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
 336	registerInspectFunc<LLUIColor>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
 337	registerInspectFunc<LLUUID>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
 338	registerInspectFunc<LLSD>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
 339}
 340
 341void LLXSDWriter::writeXSD(const std::string& type_name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace)
 342{
 343	Schema schema(xml_namespace);
 344
 345	schema.root_element.name = type_name;
 346	Choice& choice = schema.root_element.complexType.choice;
 347
 348	choice.minOccurs = 0;
 349	choice.maxOccurs = "unbounded";
 350
 351	mSchemaNode = node;
 352	//node->setName("xs:schema");
 353	//node->createChild("attributeFormDefault", true)->setStringValue("unqualified");
 354	//node->createChild("elementFormDefault", true)->setStringValue("qualified");
 355	//node->createChild("targetNamespace", true)->setStringValue(xml_namespace);
 356	//node->createChild("xmlns:xs", true)->setStringValue("http://www.w3.org/2001/XMLSchema");
 357	//node->createChild("xmlns", true)->setStringValue(xml_namespace);
 358
 359	//node = node->createChild("xs:complexType", false);
 360	//node->createChild("name", true)->setStringValue(type_name);
 361	//node->createChild("mixed", true)->setStringValue("true");
 362
 363	//mAttributeNode = node;
 364	//mElementNode = node->createChild("xs:choice", false);
 365	//mElementNode->createChild("minOccurs", true)->setStringValue("0");
 366	//mElementNode->createChild("maxOccurs", true)->setStringValue("unbounded");
 367	block.inspectBlock(*this);
 368
 369	// duplicate element choices
 370	LLXMLNodeList children;
 371	mElementNode->getChildren("xs:element", children, FALSE);
 372	for (LLXMLNodeList::iterator child_it = children.begin(); child_it != children.end(); ++child_it)
 373	{
 374		LLXMLNodePtr child_copy = child_it->second->deepCopy();
 375		std::string child_name;
 376		child_copy->getAttributeString("name", child_name);
 377		child_copy->setAttributeString("name", type_name + "." + child_name);
 378		mElementNode->addChild(child_copy);
 379	}
 380
 381	LLXMLNodePtr element_declaration_node = mSchemaNode->createChild("xs:element", false);
 382	element_declaration_node->createChild("name", true)->setStringValue(type_name);
 383	element_declaration_node->createChild("type", true)->setStringValue(type_name);
 384}
 385
 386void LLXSDWriter::writeAttribute(const std::string& type, const Parser::name_stack_t& stack, S32 min_count, S32 max_count, const std::vector<std::string>* possible_values)
 387{
 388	name_stack_t non_empty_names;
 389	std::string attribute_name;
 390	for (name_stack_t::const_iterator it = stack.begin();
 391		it != stack.end();
 392		++it)
 393	{
 394		const std::string& name = it->first;
 395		if (!name.empty())
 396		{
 397			non_empty_names.push_back(*it);
 398		}
 399	}
 400
 401	for (name_stack_t::const_iterator it = non_empty_names.begin();
 402		it != non_empty_names.end();
 403		++it)
 404	{
 405		if (!attribute_name.empty())
 406		{
 407			attribute_name += ".";
 408		}
 409		attribute_name += it->first;
 410	}
 411
 412	// only flag non-nested attributes as mandatory, nested attributes have variant syntax
 413	// that can't be properly constrained in XSD
 414	// e.g. <foo mandatory.value="bar"/> vs <foo><mandatory value="bar"/></foo>
 415	bool attribute_mandatory = min_count == 1 && max_count == 1 && non_empty_names.size() == 1;
 416
 417	// don't bother supporting "Multiple" params as xml attributes
 418	if (max_count <= 1)
 419	{
 420		// add compound attribute to root node
 421		addAttributeToSchema(mAttributeNode, attribute_name, type, attribute_mandatory, possible_values);
 422	}
 423
 424	// now generated nested elements for compound attributes
 425	if (non_empty_names.size() > 1 && !attribute_mandatory)
 426	{
 427		std::string element_name;
 428
 429		// traverse all but last element, leaving that as an attribute name
 430		name_stack_t::const_iterator end_it = non_empty_names.end();
 431		end_it--;
 432
 433		for (name_stack_t::const_iterator it = non_empty_names.begin();
 434			it != end_it;
 435			++it)
 436		{
 437			if (it != non_empty_names.begin())
 438			{
 439				element_name += ".";
 440			}
 441			element_name += it->first;
 442		}
 443
 444		std::string short_attribute_name = non_empty_names.back().first;
 445
 446		LLXMLNodePtr complex_type_node;
 447
 448		// find existing element node here, starting at tail of child list
 449		if (mElementNode->mChildren.notNull())
 450		{
 451			for(LLXMLNodePtr element = mElementNode->mChildren->tail;
 452				element.notNull(); 
 453				element = element->mPrev)
 454			{
 455				std::string name;
 456				if(element->getAttributeString("name", name) && name == element_name)
 457				{
 458					complex_type_node = element->mChildren->head;
 459					break;
 460				}
 461			}
 462		}
 463		//create complex_type node
 464		//
 465		//<xs:element
 466        //    maxOccurs="1"
 467        //    minOccurs="0"
 468        //    name="name">
 469        //       <xs:complexType>
 470        //       </xs:complexType>
 471        //</xs:element>
 472		if(complex_type_node.isNull())
 473		{
 474			complex_type_node = mElementNode->createChild("xs:element", false);
 475
 476			complex_type_node->createChild("minOccurs", true)->setIntValue(min_count);
 477			complex_type_node->createChild("maxOccurs", true)->setIntValue(max_count);
 478			complex_type_node->createChild("name",		true)->setStringValue(element_name);
 479			complex_type_node = complex_type_node->createChild("xs:complexType", false);
 480		}
 481
 482		addAttributeToSchema(complex_type_node, short_attribute_name, type, false, possible_values);
 483	}
 484}
 485
 486void LLXSDWriter::addAttributeToSchema(LLXMLNodePtr type_declaration_node, const std::string& attribute_name, const std::string& type, bool mandatory, const std::vector<std::string>* possible_values)
 487{
 488	if (!attribute_name.empty())
 489	{
 490		LLXMLNodePtr new_enum_type_node;
 491		if (possible_values != NULL)
 492		{
 493			// custom attribute type, for example
 494			//<xs:simpleType>
 495			 // <xs:restriction
 496			 //    base="xs:string">
 497			 //     <xs:enumeration
 498			 //      value="a" />
 499			 //     <xs:enumeration
 500			 //      value="b" />
 501			 //   </xs:restriction>
 502			 // </xs:simpleType>
 503			new_enum_type_node = new LLXMLNode("xs:simpleType", false);
 504
 505			LLXMLNodePtr restriction_node = new_enum_type_node->createChild("xs:restriction", false);
 506			restriction_node->createChild("base", true)->setStringValue("xs:string");
 507
 508			for (std::vector<std::string>::const_iterator it = possible_values->begin();
 509				it != possible_values->end();
 510				++it)
 511			{
 512				LLXMLNodePtr enum_node = restriction_node->createChild("xs:enumeration", false);
 513				enum_node->createChild("value", true)->setStringValue(*it);
 514			}
 515		}
 516
 517		string_set_t& attributes_written = mAttributesWritten[type_declaration_node];
 518
 519		string_set_t::iterator found_it = attributes_written.lower_bound(attribute_name);
 520
 521		// attribute not yet declared
 522		if (found_it == attributes_written.end() || attributes_written.key_comp()(attribute_name, *found_it))
 523		{
 524			attributes_written.insert(found_it, attribute_name);
 525
 526			LLXMLNodePtr attribute_node = type_declaration_node->createChild("xs:attribute", false);
 527
 528			// attribute name
 529			attribute_node->createChild("name", true)->setStringValue(attribute_name);
 530
 531			if (new_enum_type_node.notNull())
 532			{
 533				attribute_node->addChild(new_enum_type_node);
 534			}
 535			else
 536			{
 537				// simple attribute type
 538				attribute_node->createChild("type", true)->setStringValue(type);
 539			}
 540
 541			// required or optional
 542			attribute_node->createChild("use", true)->setStringValue(mandatory ? "required" : "optional");
 543		}
 544		 // attribute exists...handle collision of same name attributes with potentially different types
 545		else
 546		{
 547			LLXMLNodePtr attribute_declaration;
 548			if (type_declaration_node.notNull())
 549			{
 550				for(LLXMLNodePtr node = type_declaration_node->mChildren->tail; 
 551					node.notNull(); 
 552					node = node->mPrev)
 553				{
 554					std::string name;
 555					if (node->getAttributeString("name", name) && name == attribute_name)
 556					{
 557						attribute_declaration = node;
 558						break;
 559					}
 560				}
 561			}
 562
 563			bool new_type_is_enum = new_enum_type_node.notNull();
 564			bool existing_type_is_enum = !attribute_declaration->hasAttribute("type");
 565
 566			// either type is enum, revert to string in collision
 567			// don't bother to check for enum equivalence
 568			if (new_type_is_enum || existing_type_is_enum)
 569			{
 570				if (attribute_declaration->hasAttribute("type"))
 571				{
 572					attribute_declaration->setAttributeString("type", "xs:string");
 573				}
 574				else
 575				{
 576					attribute_declaration->createChild("type", true)->setStringValue("xs:string");
 577				}
 578				attribute_declaration->deleteChildren("xs:simpleType");
 579			}
 580			else 
 581			{
 582				// check for collision of different standard types
 583				std::string existing_type;
 584				attribute_declaration->getAttributeString("type", existing_type);
 585				// if current type is not the same as the new type, revert to strnig
 586				if (existing_type != type)
 587				{
 588					// ...than use most general type, string
 589					attribute_declaration->setAttributeString("type", "string");
 590				}
 591			}
 592		}
 593	}
 594}
 595
 596//
 597// LLXUIXSDWriter
 598//
 599void LLXUIXSDWriter::writeXSD(const std::string& type_name, const std::string& path, const LLInitParam::BaseBlock& block)
 600{
 601	std::string file_name(path);
 602	file_name += type_name + ".xsd";
 603	LLXMLNodePtr root_nodep = new LLXMLNode();
 604
 605	LLXSDWriter::writeXSD(type_name, root_nodep, block, "http://www.lindenlab.com/xui");
 606
 607	// add includes for all possible children
 608	const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name);
 609	const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type);
 610
 611	// add choices for valid children
 612	if (widget_registryp)
 613	{
 614		// add include declarations for all valid children
 615		for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems();
 616		     it != widget_registryp->currentRegistrar().endItems();
 617		     ++it)
 618		{
 619			std::string widget_name = it->first;
 620			if (widget_name == type_name)
 621			{
 622				continue;
 623			}
 624			LLXMLNodePtr nodep = new LLXMLNode("xs:include", false);
 625			nodep->createChild("schemaLocation", true)->setStringValue(widget_name + ".xsd");
 626			
 627			// add to front of schema
 628			mSchemaNode->addChild(nodep, mSchemaNode);
 629		}
 630
 631		for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems();
 632			it != widget_registryp->currentRegistrar().endItems();
 633			++it)
 634		{
 635			std::string widget_name = it->first;
 636			//<xs:element name="widget_name" type="widget_name">
 637			LLXMLNodePtr widget_node = mElementNode->createChild("xs:element", false);
 638			widget_node->createChild("name", true)->setStringValue(widget_name);
 639			widget_node->createChild("type", true)->setStringValue(widget_name);
 640		}
 641	}
 642
 643	LLFILE* xsd_file = LLFile::fopen(file_name.c_str(), "w");
 644	LLXMLNode::writeHeaderToFile(xsd_file);
 645	root_nodep->writeToFile(xsd_file);
 646	fclose(xsd_file);
 647}
 648
 649static 	LLInitParam::Parser::parser_read_func_map_t sXUIReadFuncs;
 650static 	LLInitParam::Parser::parser_write_func_map_t sXUIWriteFuncs;
 651static 	LLInitParam::Parser::parser_inspect_func_map_t sXUIInspectFuncs;
 652
 653//
 654// LLXUIParser
 655//
 656LLXUIParser::LLXUIParser()
 657:	Parser(sXUIReadFuncs, sXUIWriteFuncs, sXUIInspectFuncs),
 658	mCurReadDepth(0)
 659{
 660	if (sXUIReadFuncs.empty())
 661	{
 662		registerParserFuncs<LLInitParam::Flag>(readFlag, writeFlag);
 663		registerParserFuncs<bool>(readBoolValue, writeBoolValue);
 664		registerParserFuncs<std::string>(readStringValue, writeStringValue);
 665		registerParserFuncs<U8>(readU8Value, writeU8Value);
 666		registerParserFuncs<S8>(readS8Value, writeS8Value);
 667		registerParserFuncs<U16>(readU16Value, writeU16Value);
 668		registerParserFuncs<S16>(readS16Value, writeS16Value);
 669		registerParserFuncs<U32>(readU32Value, writeU32Value);
 670		registerParserFuncs<S32>(readS32Value, writeS32Value);
 671		registerParserFuncs<F32>(readF32Value, writeF32Value);
 672		registerParserFuncs<F64>(readF64Value, writeF64Value);
 673		registerParserFuncs<LLColor4>(readColor4Value, writeColor4Value);
 674		registerParserFuncs<LLUIColor>(readUIColorValue, writeUIColorValue);
 675		registerParserFuncs<LLUUID>(readUUIDValue, writeUUIDValue);
 676		registerParserFuncs<LLSD>(readSDValue, writeSDValue);
 677	}
 678}
 679
 680static LLFastTimer::DeclareTimer FTM_PARSE_XUI("XUI Parsing");
 681const LLXMLNodePtr DUMMY_NODE = new LLXMLNode();
 682
 683void LLXUIParser::readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, const std::string& filename, bool silent)
 684{
 685	LLFastTimer timer(FTM_PARSE_XUI);
 686	mNameStack.clear();
 687	mRootNodeName = node->getName()->mString;
 688	mCurFileName = filename;
 689	mCurReadDepth = 0;
 690	setParseSilently(silent);
 691
 692	if (node.isNull())
 693	{
 694		parserWarning("Invalid node");
 695	}
 696	else
 697	{
 698		readXUIImpl(node, block);
 699	}
 700}
 701
 702bool LLXUIParser::readXUIImpl(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block)
 703{
 704	typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
 705	boost::char_separator<char> sep(".");
 706
 707	bool values_parsed = false;
 708	bool silent = mCurReadDepth > 0;
 709
 710	if (nodep->getFirstChild().isNull() 
 711		&& nodep->mAttributes.empty() 
 712		&& nodep->getSanitizedValue().empty())
 713	{
 714		// empty node, just parse as flag
 715		mCurReadNode = DUMMY_NODE;
 716		return block.submitValue(mNameStack, *this, silent);
 717	}
 718
 719	// submit attributes for current node
 720	values_parsed |= readAttributes(nodep, block);
 721
 722	// treat text contents of xml node as "value" parameter
 723	std::string text_contents = nodep->getSanitizedValue();
 724	if (!text_contents.empty())
 725	{
 726		mCurReadNode = nodep;
 727		mNameStack.push_back(std::make_pair(std::string("value"), true));
 728		// child nodes are not necessarily valid parameters (could be a child widget)
 729		// so don't complain once we've recursed
 730		if (!block.submitValue(mNameStack, *this, true))
 731		{
 732			mNameStack.pop_back();
 733			block.submitValue(mNameStack, *this, silent);
 734		}
 735		else
 736		{
 737			mNameStack.pop_back();
 738		}
 739	}
 740
 741	// then traverse children
 742	// child node must start with last name of parent node (our "scope")
 743	// for example: "<button><button.param nested_param1="foo"><param.nested_param2 nested_param3="bar"/></button.param></button>"
 744	// which equates to the following nesting:
 745	// button
 746	//     param
 747	//         nested_param1
 748	//         nested_param2
 749	//             nested_param3	
 750	mCurReadDepth++;
 751	for(LLXMLNodePtr childp = nodep->getFirstChild(); childp.notNull();)
 752	{
 753		std::string child_name(childp->getName()->mString);
 754		S32 num_tokens_pushed = 0;
 755
 756		// for non "dotted" child nodes	check to see if child node maps to another widget type
 757		// and if not, treat as a child element of the current node
 758		// e.g. <button><rect left="10"/></button> will interpret <rect> as "button.rect"
 759		// since there is no widget named "rect"
 760		if (child_name.find(".") == std::string::npos) 
 761		{
 762			mNameStack.push_back(std::make_pair(child_name, true));
 763			num_tokens_pushed++;
 764		}
 765		else
 766		{
 767			// parse out "dotted" name into individual tokens
 768			tokenizer name_tokens(child_name, sep);
 769
 770			tokenizer::iterator name_token_it = name_tokens.begin();
 771			if(name_token_it == name_tokens.end()) 
 772			{
 773				childp = childp->getNextSibling();
 774				continue;
 775			}
 776
 777			// check for proper nesting
 778			if (mNameStack.empty())
 779			{
 780				if (*name_token_it != mRootNodeName)
 781				{
 782					childp = childp->getNextSibling();
 783					continue;
 784				}
 785			}
 786			else if(mNameStack.back().first != *name_token_it)
 787			{
 788				childp = childp->getNextSibling();
 789				continue;
 790			}
 791
 792			// now ignore first token
 793			++name_token_it; 
 794
 795			// copy remaining tokens on to our running token list
 796			for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push)
 797			{
 798				mNameStack.push_back(std::make_pair(*token_to_push, true));
 799				num_tokens_pushed++;
 800			}
 801		}
 802
 803		// recurse and visit children XML nodes
 804		if(readXUIImpl(childp, block))
 805		{
 806			// child node successfully parsed, remove from DOM
 807
 808			values_parsed = true;
 809			LLXMLNodePtr node_to_remove = childp;
 810			childp = childp->getNextSibling();
 811
 812			nodep->deleteChild(node_to_remove);
 813		}
 814		else
 815		{
 816			childp = childp->getNextSibling();
 817		}
 818
 819		while(num_tokens_pushed-- > 0)
 820		{
 821			mNameStack.pop_back();
 822		}
 823	}
 824	mCurReadDepth--;
 825	return values_parsed;
 826}
 827
 828bool LLXUIParser::readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block)
 829{
 830	typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
 831	boost::char_separator<char> sep(".");
 832
 833	bool any_parsed = false;
 834	bool silent = mCurReadDepth > 0;
 835
 836	for(LLXMLAttribList::const_iterator attribute_it = nodep->mAttributes.begin(); 
 837		attribute_it != nodep->mAttributes.end(); 
 838		++attribute_it)
 839	{
 840		S32 num_tokens_pushed = 0;
 841		std::string attribute_name(attribute_it->first->mString);
 842		mCurReadNode = attribute_it->second;
 843
 844		tokenizer name_tokens(attribute_name, sep);
 845		// copy remaining tokens on to our running token list
 846		for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push)
 847		{
 848			mNameStack.push_back(std::make_pair(*token_to_push, true));
 849			num_tokens_pushed++;
 850		}
 851
 852		// child nodes are not necessarily valid attributes, so don't complain once we've recursed
 853		any_parsed |= block.submitValue(mNameStack, *this, silent);
 854		
 855		while(num_tokens_pushed-- > 0)
 856		{
 857			mNameStack.pop_back();
 858		}
 859	}
 860
 861	return any_parsed;
 862}
 863
 864void LLXUIParser::writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock &block, const LLInitParam::BaseBlock* diff_block)
 865{
 866	mWriteRootNode = node;
 867	name_stack_t name_stack = Parser::name_stack_t();
 868	block.serializeBlock(*this, name_stack, diff_block);
 869	mOutNodes.clear();
 870}
 871
 872// go from a stack of names to a specific XML node
 873LLXMLNodePtr LLXUIParser::getNode(name_stack_t& stack)
 874{
 875	LLXMLNodePtr out_node = mWriteRootNode;
 876
 877	name_stack_t::iterator next_it = stack.begin();
 878	for (name_stack_t::iterator it = stack.begin();
 879		it != stack.end();
 880		it = next_it)
 881	{
 882		++next_it;
 883		if (it->first.empty())
 884		{
 885			it->second = false;
 886			continue;
 887		}
 888
 889		out_nodes_t::iterator found_it = mOutNodes.find(it->first);
 890
 891		// node with this name not yet written
 892		if (found_it == mOutNodes.end() || it->second)
 893		{
 894			// make an attribute if we are the last element on the name stack
 895			bool is_attribute = next_it == stack.end();
 896			LLXMLNodePtr new_node = new LLXMLNode(it->first.c_str(), is_attribute);
 897			out_node->addChild(new_node);
 898			mOutNodes[it->first] = new_node;
 899			out_node = new_node;
 900			it->second = false;
 901		}
 902		else
 903		{
 904			out_node = found_it->second;
 905		}
 906	}
 907
 908	return (out_node == mWriteRootNode ? LLXMLNodePtr(NULL) : out_node);
 909}
 910
 911bool LLXUIParser::readFlag(Parser& parser, void* val_ptr)
 912{
 913	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
 914	return self.mCurReadNode == DUMMY_NODE;
 915}
 916
 917bool LLXUIParser::writeFlag(Parser& parser, const void* val_ptr, name_stack_t& stack)
 918{
 919	// just create node
 920	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
 921	LLXMLNodePtr node = self.getNode(stack);
 922	return node.notNull();
 923}
 924
 925bool LLXUIParser::readBoolValue(Parser& parser, void* val_ptr)
 926{
 927	S32 value;
 928	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
 929	bool success = self.mCurReadNode->getBoolValue(1, &value);
 930	*((bool*)val_ptr) = (value != FALSE);
 931	return success;
 932}
 933
 934bool LLXUIParser::writeBoolValue(Parser& parser, const void* val_ptr, name_stack_t& stack)
 935{
 936	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
 937	LLXMLNodePtr node = self.getNode(stack);
 938	if (node.notNull())
 939	{
 940		node->setBoolValue(*((bool*)val_ptr));
 941		return true;
 942	}
 943	return false;
 944}
 945
 946bool LLXUIParser::readStringValue(Parser& parser, void* val_ptr)
 947{
 948	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
 949	*((std::string*)val_ptr) = self.mCurReadNode->getSanitizedValue();
 950	return true;
 951}
 952
 953bool LLXUIParser::writeStringValue(Parser& parser, const void* val_ptr, name_stack_t& stack)
 954{
 955	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
 956	LLXMLNodePtr node = self.getNode(stack);
 957	if (node.notNull())
 958	{
 959		const std::string* string_val = reinterpret_cast<const std::string*>(val_ptr);
 960		if (string_val->find('\n') != std::string::npos 
 961			|| string_val->size() > MAX_STRING_ATTRIBUTE_SIZE)
 962		{
 963			// don't write strings with newlines into attributes
 964			std::string attribute_name = node->getName()->mString;
 965			LLXMLNodePtr parent_node = node->mParent;
 966			parent_node->deleteChild(node);
 967			// write results in text contents of node
 968			if (attribute_name == "value")
 969			{
 970				// "value" is implicit, just write to parent
 971				node = parent_node;
 972			}
 973			else
 974			{
 975				// create a child that is not an attribute, but with same name
 976				node = parent_node->createChild(attribute_name.c_str(), false);
 977			}
 978		}
 979		node->setStringValue(*string_val);
 980		return true;
 981	}
 982	return false;
 983}
 984
 985bool LLXUIParser::readU8Value(Parser& parser, void* val_ptr)
 986{
 987	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
 988	return self.mCurReadNode->getByteValue(1, (U8*)val_ptr);
 989}
 990
 991bool LLXUIParser::writeU8Value(Parser& parser, const void* val_ptr, name_stack_t& stack)
 992{
 993	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
 994	LLXMLNodePtr node = self.getNode(stack);
 995	if (node.notNull())
 996	{
 997		node->setUnsignedValue(*((U8*)val_ptr));
 998		return true;
 999	}
1000	return false;
1001}
1002
1003bool LLXUIParser::readS8Value(Parser& parser, void* val_ptr)
1004{
1005	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1006	S32 value;
1007	if(self.mCurReadNode->getIntValue(1, &value))
1008	{
1009		*((S8*)val_ptr) = value;
1010		return true;
1011	}
1012	return false;
1013}
1014
1015bool LLXUIParser::writeS8Value(Parser& parser, const void* val_ptr, name_stack_t& stack)
1016{
1017	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1018	LLXMLNodePtr node = self.getNode(stack);
1019	if (node.notNull())
1020	{
1021		node->setIntValue(*((S8*)val_ptr));
1022		return true;
1023	}
1024	return false;
1025}
1026
1027bool LLXUIParser::readU16Value(Parser& parser, void* val_ptr)
1028{
1029	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1030	U32 value;
1031	if(self.mCurReadNode->getUnsignedValue(1, &value))
1032	{
1033		*((U16*)val_ptr) = value;
1034		return true;
1035	}
1036	return false;
1037}
1038
1039bool LLXUIParser::writeU16Value(Parser& parser, const void* val_ptr, name_stack_t& stack)
1040{
1041	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1042	LLXMLNodePtr node = self.getNode(stack);
1043	if (node.notNull())
1044	{
1045		node->setUnsignedValue(*((U16*)val_ptr));
1046		return true;
1047	}
1048	return false;
1049}
1050
1051bool LLXUIParser::readS16Value(Parser& parser, void* val_ptr)
1052{
1053	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1054	S32 value;
1055	if(self.mCurReadNode->getIntValue(1, &value))
1056	{
1057		*((S16*)val_ptr) = value;
1058		return true;
1059	}
1060	return false;
1061}
1062
1063bool LLXUIParser::writeS16Value(Parser& parser, const void* val_ptr, name_stack_t& stack)
1064{
1065	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1066	LLXMLNodePtr node = self.getNode(stack);
1067	if (node.notNull())
1068	{
1069		node->setIntValue(*((S16*)val_ptr));
1070		return true;
1071	}
1072	return false;
1073}
1074
1075bool LLXUIParser::readU32Value(Parser& parser, void* val_ptr)
1076{
1077	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1078	return self.mCurReadNode->getUnsignedValue(1, (U32*)val_ptr);
1079}
1080
1081bool LLXUIParser::writeU32Value(Parser& parser, const void* val_ptr, name_stack_t& stack)
1082{
1083	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1084	LLXMLNodePtr node = self.getNode(stack);
1085	if (node.notNull())
1086	{
1087		node->setUnsignedValue(*((U32*)val_ptr));
1088		return true;
1089	}
1090	return false;
1091}
1092
1093bool LLXUIParser::readS32Value(Parser& parser, void* val_ptr)
1094{
1095	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1096	return self.mCurReadNode->getIntValue(1, (S32*)val_ptr);
1097}
1098
1099bool LLXUIParser::writeS32Value(Parser& parser, const void* val_ptr, name_stack_t& stack)
1100{
1101	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1102	LLXMLNodePtr node = self.getNode(stack);
1103	if (node.notNull())
1104	{
1105		node->setIntValue(*((S32*)val_ptr));
1106		return true;
1107	}
1108	return false;
1109}
1110
1111bool LLXUIParser::readF32Value(Parser& parser, void* val_ptr)
1112{
1113	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1114	return self.mCurReadNode->getFloatValue(1, (F32*)val_ptr);
1115}
1116
1117bool LLXUIParser::writeF32Value(Parser& parser, const void* val_ptr, name_stack_t& stack)
1118{
1119	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1120	LLXMLNodePtr node = self.getNode(stack);
1121	if (node.notNull())
1122	{
1123		node->setFloatValue(*((F32*)val_ptr));
1124		return true;
1125	}
1126	return false;
1127}
1128
1129bool LLXUIParser::readF64Value(Parser& parser, void* val_ptr)
1130{
1131	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1132	return self.mCurReadNode->getDoubleValue(1, (F64*)val_ptr);
1133}
1134
1135bool LLXUIParser::writeF64Value(Parser& parser, const void* val_ptr, name_stack_t& stack)
1136{
1137	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1138	LLXMLNodePtr node = self.getNode(stack);
1139	if (node.notNull())
1140	{
1141		node->setDoubleValue(*((F64*)val_ptr));
1142		return true;
1143	}
1144	return false;
1145}
1146
1147bool LLXUIParser::readColor4Value(Parser& parser, void* val_ptr)
1148{
1149	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1150	LLColor4* colorp = (LLColor4*)val_ptr;
1151	if(self.mCurReadNode->getFloatValue(4, colorp->mV) >= 3)
1152	{
1153		return true;
1154	}
1155
1156	return false;
1157}
1158
1159bool LLXUIParser::writeColor4Value(Parser& parser, const void* val_ptr, name_stack_t& stack)
1160{
1161	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1162	LLXMLNodePtr node = self.getNode(stack);
1163	if (node.notNull())
1164	{
1165		LLColor4 color = *((LLColor4*)val_ptr);
1166		node->setFloatValue(4, color.mV);
1167		return true;
1168	}
1169	return false;
1170}
1171
1172bool LLXUIParser::readUIColorValue(Parser& parser, void* val_ptr)
1173{
1174	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1175	LLUIColor* param = (LLUIColor*)val_ptr;
1176	LLColor4 color;
1177	bool success =  self.mCurReadNode->getFloatValue(4, color.mV) >= 3;
1178	if (success)
1179	{
1180		param->set(color);
1181		return true;
1182	}
1183	return false;
1184}
1185
1186bool LLXUIParser::writeUIColorValue(Parser& parser, const void* val_ptr, name_stack_t& stack)
1187{
1188	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1189	LLXMLNodePtr node = self.getNode(stack);
1190	if (node.notNull())
1191	{
1192		LLUIColor color = *((LLUIColor*)val_ptr);
1193		//RN: don't write out the color that is represented by a function
1194		// rely on param block exporting to get the reference to the color settings
1195		if (color.isReference()) return false;
1196		node->setFloatValue(4, color.get().mV);
1197		return true;
1198	}
1199	return false;
1200}
1201
1202bool LLXUIParser::readUUIDValue(Parser& parser, void* val_ptr)
1203{
1204	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1205	LLUUID temp_id;
1206	// LLUUID::set is destructive, so use temporary value
1207	if (temp_id.set(self.mCurReadNode->getSanitizedValue()))
1208	{
1209		*(LLUUID*)(val_ptr) = temp_id;
1210		return true;
1211	}
1212	return false;
1213}
1214
1215bool LLXUIParser::writeUUIDValue(Parser& parser, const void* val_ptr, name_stack_t& stack)
1216{
1217	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1218	LLXMLNodePtr node = self.getNode(stack);
1219	if (node.notNull())
1220	{
1221		node->setStringValue(((LLUUID*)val_ptr)->asString());
1222		return true;
1223	}
1224	return false;
1225}
1226
1227bool LLXUIParser::readSDValue(Parser& parser, void* val_ptr)
1228{
1229	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1230	*((LLSD*)val_ptr) = LLSD(self.mCurReadNode->getSanitizedValue());
1231	return true;
1232}
1233
1234bool LLXUIParser::writeSDValue(Parser& parser, const void* val_ptr, name_stack_t& stack)
1235{
1236	LLXUIParser& self = static_cast<LLXUIParser&>(parser);
1237
1238	LLXMLNodePtr node = self.getNode(stack);
1239	if (node.notNull())
1240	{
1241		std::string string_val = ((LLSD*)val_ptr)->asString();
1242		if (string_val.find('\n') != std::string::npos || string_val.size() > MAX_STRING_ATTRIBUTE_SIZE)
1243		{
1244			// don't write strings with newlines into attributes
1245			std::string attribute_name = node->getName()->mString;
1246			LLXMLNodePtr parent_node = node->mParent;
1247			parent_node->deleteChild(node);
1248			// write results in text contents of node
1249			if (attribute_name == "value")
1250			{
1251				// "value" is implicit, just write to parent
1252				node = parent_node;
1253			}
1254			else
1255			{
1256				node = parent_node->createChild(attribute_name.c_str(), false);
1257			}
1258		}
1259
1260		node->setStringValue(string_val);
1261		return true;
1262	}
1263	return false;
1264}
1265
1266/*virtual*/ std::string LLXUIParser::getCurrentElementName()
1267{
1268	std::string full_name;
1269	for (name_stack_t::iterator it = mNameStack.begin();	
1270		it != mNameStack.end();
1271		++it)
1272	{
1273		full_name += it->first + "."; // build up dotted names: "button.param.nestedparam."
1274	}
1275
1276	return full_name;
1277}
1278
1279void LLXUIParser::parserWarning(const std::string& message)
1280{
1281#ifdef LL_WINDOWS
1282	// use Visual Studo friendly formatting of output message for easy access to originating xml
1283	llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str());
1284	utf16str += '\n';
1285	OutputDebugString(utf16str.c_str());
1286#else
1287	Parser::parserWarning(message);
1288#endif
1289}
1290
1291void LLXUIParser::parserError(const std::string& message)
1292{
1293#ifdef LL_WINDOWS
1294	llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str());
1295	utf16str += '\n';
1296	OutputDebugString(utf16str.c_str());
1297#else
1298	Parser::parserError(message);
1299#endif
1300}
1301
1302
1303//
1304// LLSimpleXUIParser
1305//
1306
1307struct ScopedFile
1308{
1309	ScopedFile( const std::string& filename, const char* accessmode )
1310	{
1311		mFile = LLFile::fopen(filename, accessmode);
1312	}
1313
1314	~ScopedFile()
1315	{
1316		fclose(mFile);
1317		mFile = NULL;
1318	}
1319
1320	S32 getRemainingBytes()
1321	{
1322		if (!isOpen()) return 0;
1323
1324		S32 cur_pos = ftell(mFile);
1325		fseek(mFile, 0L, SEEK_END);
1326		S32 file_size = ftell(mFile);
1327		fseek(mFile, cur_pos, SEEK_SET);
1328		return file_size - cur_pos;
1329	}
1330
1331	bool isOpen() { return mFile != NULL; }
1332
1333	LLFILE* mFile;
1334};
1335LLSimpleXUIParser::LLSimpleXUIParser(LLSimpleXUIParser::element_start_callback_t element_cb)
1336:	Parser(sSimpleXUIReadFuncs, sSimpleXUIWriteFuncs, sSimpleXUIInspectFuncs),
1337	mCurReadDepth(0),
1338	mElementCB(element_cb)
1339{
1340	if (sSimpleXUIReadFuncs.empty())
1341	{
1342		registerParserFuncs<LLInitParam::Flag>(readFlag);
1343		registerParserFuncs<bool>(readBoolValue);
1344		registerParserFuncs<std::string>(readStringValue);
1345		registerParserFuncs<U8>(readU8Value);
1346		registerParserFuncs<S8>(readS8Value);
1347		registerParserFuncs<U16>(readU16Value);
1348		registerParserFuncs<S16>(readS16Value);
1349		registerParserFuncs<U32>(readU32Value);
1350		registerParserFuncs<S32>(readS32Value);
1351		registerParserFuncs<F32>(readF32Value);
1352		registerParserFuncs<F64>(readF64Value);
1353		registerParserFuncs<LLColor4>(readColor4Value);
1354		registerParserFuncs<LLUIColor>(readUIColorValue);
1355		registerParserFuncs<LLUUID>(readUUIDValue);
1356		registerParserFuncs<LLSD>(readSDValue);
1357	}
1358}
1359
1360LLSimpleXUIParser::~LLSimpleXUIParser()
1361{
1362}
1363
1364
1365bool LLSimpleXUIParser::readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent)
1366{
1367	LLFastTimer timer(FTM_PARSE_XUI);
1368
1369	mParser = XML_ParserCreate(NULL);
1370	XML_SetUserData(mParser, this);
1371	XML_SetElementHandler(			mParser,	startElementHandler, endElementHandler);
1372	XML_SetCharacterDataHandler(	mParser,	characterDataHandler);
1373
1374	mOutputStack.push_back(std::make_pair(&block, 0));
1375	mNameStack.clear();
1376	mCurFileName = filename;
1377	mCurReadDepth = 0;
1378	setParseSilently(silent);
1379
1380	ScopedFile file(filename, "rb");
1381	if( !file.isOpen() )
1382	{
1383		LL_WARNS("ReadXUI") << "Unable to open file " << filename << LL_ENDL;
1384		XML_ParserFree( mParser );
1385		return false;
1386	}
1387
1388	S32 bytes_read = 0;
1389	
1390	S32 buffer_size = file.getRemainingBytes();
1391	void* buffer = XML_GetBuffer(mParser, buffer_size);
1392	if( !buffer ) 
1393	{
1394		LL_WARNS("ReadXUI") << "Unable to allocate XML buffer while reading file " << filename << LL_ENDL;
1395		XML_ParserFree( mParser );
1396		return false;
1397	}
1398
1399	bytes_read = (S32)fread(buffer, 1, buffer_size, file.mFile);
1400	if( bytes_read <= 0 )
1401	{
1402		LL_WARNS("ReadXUI") << "Error while reading file  " << filename << LL_ENDL;
1403		XML_ParserFree( mParser );
1404		return false;
1405	}
1406	
1407	mEmptyLeafNode.push_back(false);
1408
1409	if( !XML_ParseBuffer(mParser, bytes_read, TRUE ) )
1410	{
1411		LL_WARNS("ReadXUI") << "Error while parsing file  " << filename << LL_ENDL;
1412		XML_ParserFree( mParser );
1413		return false;
1414	}
1415
1416	mEmptyLeafNode.pop_back();
1417
1418	XML_ParserFree( mParser );
1419	return true;
1420}
1421
1422void LLSimpleXUIParser::startElementHandler(void *userData, const char *name, const char **atts)
1423{
1424	LLSimpleXUIParser* self = reinterpret_cast<LLSimpleXUIParser*>(userData);
1425	self->startElement(name, atts);
1426}
1427
1428void LLSimpleXUIParser::endElementHandler(void *userData, const char *name)
1429{
1430	LLSimpleXUIParser* self = reinterpret_cast<LLSimpleXUIParser*>(userData);
1431	self->endElement(name);
1432}
1433
1434void LLSimpleXUIParser::characterDataHandler(void *userData, const char *s, int len)
1435{
1436	LLSimpleXUIParser* self = reinterpret_cast<LLSimpleXUIParser*>(userData);
1437	self->characterData(s, len);
1438}
1439
1440void LLSimpleXUIParser::characterData(const char *s, int len)
1441{
1442	mTextContents += std::string(s, len);
1443}
1444
1445void LLSimpleXUIParser::startElement(const char *name, const char **atts)
1446{
1447	processText();
1448
1449	typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
1450	boost::char_separator<char> sep(".");
1451
1452	if (mElementCB) 
1453	{
1454		LLInitParam::BaseBlock* blockp = mElementCB(*this, name);
1455		if (blockp)
1456		{
1457			mOutputStack.push_back(std::make_pair(blockp, 0));
1458		}
1459	}
1460
1461	mOutputStack.back().second++;
1462	S32 num_tokens_pushed = 0;
1463	std::string child_name(name);
1464
1465	if (mOutputStack.back().second == 1)
1466	{	// root node for this block
1467		mScope.push_back(child_name);
1468	}
1469	else
1470	{	// compound attribute
1471		if (child_name.find(".") == std::string::npos) 
1472		{
1473			mNameStack.push_back(std::make_pair(child_name, true));
1474			num_tokens_pushed++;
1475			mScope.push_back(child_name);
1476		}
1477		else
1478		{
1479			// parse out "dotted" name into individual tokens
1480			tokenizer name_tokens(child_name, sep);
1481
1482			tokenizer::iterator name_token_it = name_tokens.begin();
1483			if(name_token_it == name_tokens.end()) 
1484			{
1485				return;
1486			}
1487
1488			// check for proper nesting
1489			if(!mScope.empty() && *name_token_it != mScope.back())
1490			{
1491				return;
1492			}
1493
1494			// now ignore first token
1495			++name_token_it; 
1496
1497			// copy remaining tokens on to our running token list
1498			for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push)
1499			{
1500				mNameStack.push_back(std::make_pair(*token_to_push, true));
1501				num_tokens_pushed++;
1502			}
1503			mScope.push_back(mNameStack.back().first);
1504		}
1505	}
1506
1507	// parent node is not empty
1508	mEmptyLeafNode.back() = false;
1509	// we are empty if we have no attributes
1510	mEmptyLeafNode.push_back(atts[0] == NULL);
1511
1512	mTokenSizeStack.push_back(num_tokens_pushed);
1513	readAttributes(atts);
1514
1515}
1516
1517void LLSimpleXUIParser::endElement(const char *name)
1518{
1519	bool has_text = processText();
1520
1521	// no text, attributes, or children
1522	if (!has_text && mEmptyLeafNode.back())
1523	{
1524		// submit this as a valueless name (even though there might be text contents we haven't seen yet)
1525		mCurAttributeValueBegin = NO_VALUE_MARKER;
1526		mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently);
1527	}
1528
1529	if (--mOutputStack.back().second == 0)
1530	{
1531		if (mOutputStack.empty())
1532		{
1533			LL_ERRS("ReadXUI") << "Parameter block output stack popped while empty." << LL_ENDL;
1534		}
1535		mOutputStack.pop_back();
1536	}
1537
1538	S32 num_tokens_to_pop = mTokenSizeStack.back();
1539	mTokenSizeStack.pop_back();
1540	while(num_tokens_to_pop-- > 0)
1541	{
1542		mNameStack.pop_back();
1543	}
1544	mScope.pop_back();
1545	mEmptyLeafNode.pop_back();
1546}
1547
1548bool LLSimpleXUIParser::readAttributes(const char **atts)
1549{
1550	typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
1551	boost::char_separator<char> sep(".");
1552
1553	bool any_parsed = false;
1554	for(S32 i = 0; atts[i] && atts[i+1]; i += 2 )
1555	{
1556		std::string attribute_name(atts[i]);
1557		mCurAttributeValueBegin = atts[i+1];
1558		
1559		S32 num_tokens_pushed = 0;
1560		tokenizer name_tokens(attribute_name, sep);
1561		// copy remaining tokens on to our running token list
1562		for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push)
1563		{
1564			mNameStack.push_back(std::make_pair(*token_to_push, true));
1565			num_tokens_pushed++;
1566		}
1567
1568		// child nodes are not necessarily valid attributes, so don't complain once we've recursed
1569		any_parsed |= mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently);
1570		
1571		while(num_tokens_pushed-- > 0)
1572		{
1573			mNameStack.pop_back();
1574		}
1575	}
1576	return any_parsed;
1577}
1578
1579bool LLSimpleXUIParser::processText()
1580{
1581	if (!mTextContents.empty())
1582	{
1583		LLStringUtil::trim(mTextContents);
1584		if (!mTextContents.empty())
1585		{
1586			mNameStack.push_back(std::make_pair(std::string("value"), true));
1587			mCurAttributeValueBegin = mTextContents.c_str();
1588			mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently);
1589			mNameStack.pop_back();
1590		}
1591		mTextContents.clear();
1592		return true;
1593	}
1594	return false;
1595}
1596
1597/*virtual*/ std::string LLSimpleXUIParser::getCurrentElementName()
1598{
1599	std::string full_name;
1600	for (name_stack_t::iterator it = mNameStack.begin();	
1601		it != mNameStack.end();
1602		++it)
1603	{
1604		full_name += it->first + "."; // build up dotted names: "button.param.nestedparam."
1605	}
1606
1607	return full_name;
1608}
1609
1610void LLSimpleXUIParser::parserWarning(const std::string& message)
1611{
1612#ifdef LL_WINDOWS
1613	// use Visual Studo friendly formatting of output message for easy access to originating xml
1614	llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), LINE_NUMBER_HERE, message.c_str()).c_str());
1615	utf16str += '\n';
1616	OutputDebugString(utf16str.c_str());
1617#else
1618	Parser::parserWarning(message);
1619#endif
1620}
1621
1622void LLSimpleXUIParser::parserError(const std::string& message)
1623{
1624#ifdef LL_WINDOWS
1625	llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), LINE_NUMBER_HERE, message.c_str()).c_str());
1626	utf16str += '\n';
1627	OutputDebugString(utf16str.c_str());
1628#else
1629	Parser::parserError(message);
1630#endif
1631}
1632
1633bool LLSimpleXUIParser::readFlag(Parser& parser, void* val_ptr)
1634{
1635	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
1636	return self.mCurAttributeValueBegin == NO_VALUE_MARKER;
1637}
1638
1639bool LLSimpleXUIParser::readBoolValue(Parser& parser, void* val_ptr)
1640{
1641	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
1642	if (!strcmp(self.mCurAttributeValueBegin, "true")) 
1643	{
1644		*((bool*)val_ptr) = true;
1645		return true;
1646	}
1647	else if (!strcmp(self.mCurAttributeValueBegin, "false"))
1648	{
1649		*((bool*)val_ptr) = false;
1650		return true;
1651	}
1652
1653	return false;
1654}
1655
1656bool LLSimpleXUIParser::readStringValue(Parser& parser, void* val_ptr)
1657{
1658	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
1659	*((std::string*)val_ptr) = self.mCurAttributeValueBegin;
1660	return true;
1661}
1662
1663bool LLSimpleXUIParser::readU8Value(Parser& parser, void* val_ptr)
1664{
1665	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
1666	return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U8*)val_ptr)]).full;
1667}
1668
1669bool LLSimpleXUIParser::readS8Value(Parser& parser, void* val_ptr)
1670{
1671	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
1672	return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S8*)val_ptr)]).full;
1673}
1674
1675bool LLSimpleXUIParser::readU16Value(Parser& parser, void* val_ptr)
1676{
1677	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
1678	return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U16*)val_ptr)]).full;
1679}
1680
1681bool LLSimpleXUIParser::readS16Value(Parser& parser, void* val_ptr)
1682{
1683	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
1684	return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S16*)val_ptr)]).full;
1685}
1686
1687bool LLSimpleXUIParser::readU32Value(Parser& parser, void* val_ptr)
1688{
1689	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
1690	return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U32*)val_ptr)]).full;
1691}
1692
1693bool LLSimpleXUIParser::readS32Value(Parser& parser, void* val_ptr)
1694{
1695	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
1696	return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S32*)val_ptr)]).full;
1697}
1698
1699bool LLSimpleXUIParser::readF32Value(Parser& parser, void* val_ptr)
1700{
1701	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
1702	return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F32*)val_ptr)]).full;
1703}
1704
1705bool LLSimpleXUIParser::readF64Value(Parser& parser, void* val_ptr)
1706{
1707	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
1708	return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F64*)val_ptr)]).full;
1709}
1710	
1711bool LLSimpleXUIParser::readColor4Value(Parser& parser, void* val_ptr)
1712{
1713	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
1714	LLColor4 value;
1715
1716	if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full)
1717	{
1718		*(LLColor4*)(val_ptr) = value;
1719		return true;
1720	}
1721	return false;
1722}
1723
1724bool LLSimpleXUIParser::readUIColorValue(Parser& parser, void* val_ptr)
1725{
1726	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
1727	LLColor4 value;
1728	LLUIColor* colorp = (LLUIColor*)val_ptr;
1729
1730	if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full)
1731	{
1732		colorp->set(value);
1733		return true;
1734	}
1735	return false;
1736}
1737
1738bool LLSimpleXUIParser::readUUIDValue(Parser& parser, void* val_ptr)
1739{
1740	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
1741	LLUUID temp_id;
1742	// LLUUID::set is destructive, so use temporary value
1743	if (temp_id.set(std::string(self.mCurAttributeValueBegin)))
1744	{
1745		*(LLUUID*)(val_ptr) = temp_id;
1746		return true;
1747	}
1748	return false;
1749}
1750
1751bool LLSimpleXUIParser::readSDValue(Parser& parser, void* val_ptr)
1752{
1753	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
1754	*((LLSD*)val_ptr) = LLSD(self.mCurAttributeValueBegin);
1755	return true;
1756}