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