llxuiparser.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:29k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llxuiparser.cpp
  3.  * @brief Utility functions for handling XUI structures in XML
  4.  *
  5.  * $LicenseInfo:firstyear=2003&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2003-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "linden_common.h"
  33. #include "llxuiparser.h"
  34. #include "llxmlnode.h"
  35. #include <fstream>
  36. #include <boost/tokenizer.hpp>
  37. #include "lluicolor.h"
  38. const S32 MAX_STRING_ATTRIBUTE_SIZE = 40;
  39. //
  40. // LLXSDWriter
  41. //
  42. LLXSDWriter::LLXSDWriter()
  43. {
  44. registerInspectFunc<bool>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:boolean", _1, _2, _3, _4));
  45. registerInspectFunc<std::string>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
  46. registerInspectFunc<U8>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedByte", _1, _2, _3, _4));
  47. registerInspectFunc<S8>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedByte", _1, _2, _3, _4));
  48. registerInspectFunc<U16>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedShort", _1, _2, _3, _4));
  49. registerInspectFunc<S16>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedShort", _1, _2, _3, _4));
  50. registerInspectFunc<U32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedInt", _1, _2, _3, _4));
  51. registerInspectFunc<S32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:integer", _1, _2, _3, _4));
  52. registerInspectFunc<F32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:float", _1, _2, _3, _4));
  53. registerInspectFunc<F64>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:double", _1, _2, _3, _4));
  54. registerInspectFunc<LLColor4>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
  55. registerInspectFunc<LLUIColor>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
  56. registerInspectFunc<LLUUID>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
  57. registerInspectFunc<LLSD>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
  58. }
  59. void LLXSDWriter::writeXSD(const std::string& type_name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace)
  60. {
  61. mSchemaNode = node;
  62. node->setName("xs:schema");
  63. node->createChild("attributeFormDefault", true)->setStringValue("unqualified");
  64. node->createChild("elementFormDefault", true)->setStringValue("qualified");
  65. node->createChild("targetNamespace", true)->setStringValue(xml_namespace);
  66. node->createChild("xmlns:xs", true)->setStringValue("http://www.w3.org/2001/XMLSchema");
  67. node->createChild("xmlns", true)->setStringValue(xml_namespace);
  68. node = node->createChild("xs:complexType", false);
  69. node->createChild("name", true)->setStringValue(type_name);
  70. node->createChild("mixed", true)->setStringValue("true");
  71. mAttributeNode = node;
  72. mElementNode = node->createChild("xs:choice", false);
  73. mElementNode->createChild("minOccurs", true)->setStringValue("0");
  74. mElementNode->createChild("maxOccurs", true)->setStringValue("unbounded");
  75. block.inspectBlock(*this);
  76. // duplicate element choices
  77. LLXMLNodeList children;
  78. mElementNode->getChildren("xs:element", children, FALSE);
  79. for (LLXMLNodeList::iterator child_it = children.begin(); child_it != children.end(); ++child_it)
  80. {
  81. LLXMLNodePtr child_copy = child_it->second->deepCopy();
  82. std::string child_name;
  83. child_copy->getAttributeString("name", child_name);
  84. child_copy->setAttributeString("name", type_name + "." + child_name);
  85. mElementNode->addChild(child_copy);
  86. }
  87. LLXMLNodePtr element_declaration_node = mSchemaNode->createChild("xs:element", false);
  88. element_declaration_node->createChild("name", true)->setStringValue(type_name);
  89. element_declaration_node->createChild("type", true)->setStringValue(type_name);
  90. }
  91. 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)
  92. {
  93. name_stack_t non_empty_names;
  94. std::string attribute_name;
  95. for (name_stack_t::const_iterator it = stack.begin();
  96. it != stack.end();
  97. ++it)
  98. {
  99. const std::string& name = it->first;
  100. if (!name.empty())
  101. {
  102. non_empty_names.push_back(*it);
  103. }
  104. }
  105. for (name_stack_t::const_iterator it = non_empty_names.begin();
  106. it != non_empty_names.end();
  107. ++it)
  108. {
  109. if (!attribute_name.empty())
  110. {
  111. attribute_name += ".";
  112. }
  113. attribute_name += it->first;
  114. }
  115. // only flag non-nested attributes as mandatory, nested attributes have variant syntax
  116. // that can't be properly constrained in XSD
  117. // e.g. <foo mandatory.value="bar"/> vs <foo><mandatory value="bar"/></foo>
  118. bool attribute_mandatory = min_count == 1 && max_count == 1 && non_empty_names.size() == 1;
  119. // don't bother supporting "Multiple" params as xml attributes
  120. if (max_count <= 1)
  121. {
  122. // add compound attribute to root node
  123. addAttributeToSchema(mAttributeNode, attribute_name, type, attribute_mandatory, possible_values);
  124. }
  125. // now generated nested elements for compound attributes
  126. if (non_empty_names.size() > 1 && !attribute_mandatory)
  127. {
  128. std::string element_name;
  129. // traverse all but last element, leaving that as an attribute name
  130. name_stack_t::const_iterator end_it = non_empty_names.end();
  131. end_it--;
  132. for (name_stack_t::const_iterator it = non_empty_names.begin();
  133. it != end_it;
  134. ++it)
  135. {
  136. if (it != non_empty_names.begin())
  137. {
  138. element_name += ".";
  139. }
  140. element_name += it->first;
  141. }
  142. std::string short_attribute_name = non_empty_names.back().first;
  143. LLXMLNodePtr complex_type_node;
  144. // find existing element node here, starting at tail of child list
  145. if (mElementNode->mChildren.notNull())
  146. {
  147. for(LLXMLNodePtr element = mElementNode->mChildren->tail;
  148. element.notNull(); 
  149. element = element->mPrev)
  150. {
  151. std::string name;
  152. if(element->getAttributeString("name", name) && name == element_name)
  153. {
  154. complex_type_node = element->mChildren->head;
  155. break;
  156. }
  157. }
  158. }
  159. //create complex_type node
  160. //
  161. //<xs:element
  162.         //    maxOccurs="1"
  163.         //    minOccurs="0"
  164.         //    name="name">
  165.         //       <xs:complexType>
  166.         //       </xs:complexType>
  167.         //</xs:element>
  168. if(complex_type_node.isNull())
  169. {
  170. complex_type_node = mElementNode->createChild("xs:element", false);
  171. complex_type_node->createChild("minOccurs", true)->setIntValue(min_count);
  172. complex_type_node->createChild("maxOccurs", true)->setIntValue(max_count);
  173. complex_type_node->createChild("name", true)->setStringValue(element_name);
  174. complex_type_node = complex_type_node->createChild("xs:complexType", false);
  175. }
  176. addAttributeToSchema(complex_type_node, short_attribute_name, type, false, possible_values);
  177. }
  178. }
  179. 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)
  180. {
  181. if (!attribute_name.empty())
  182. {
  183. LLXMLNodePtr new_enum_type_node;
  184. if (possible_values != NULL)
  185. {
  186. // custom attribute type, for example
  187. //<xs:simpleType>
  188.  // <xs:restriction
  189.  //    base="xs:string">
  190.  //     <xs:enumeration
  191.  //      value="a" />
  192.  //     <xs:enumeration
  193.  //      value="b" />
  194.  //   </xs:restriction>
  195.  // </xs:simpleType>
  196. new_enum_type_node = new LLXMLNode("xs:simpleType", false);
  197. LLXMLNodePtr restriction_node = new_enum_type_node->createChild("xs:restriction", false);
  198. restriction_node->createChild("base", true)->setStringValue("xs:string");
  199. for (std::vector<std::string>::const_iterator it = possible_values->begin();
  200. it != possible_values->end();
  201. ++it)
  202. {
  203. LLXMLNodePtr enum_node = restriction_node->createChild("xs:enumeration", false);
  204. enum_node->createChild("value", true)->setStringValue(*it);
  205. }
  206. }
  207. string_set_t& attributes_written = mAttributesWritten[type_declaration_node];
  208. string_set_t::iterator found_it = attributes_written.lower_bound(attribute_name);
  209. // attribute not yet declared
  210. if (found_it == attributes_written.end() || attributes_written.key_comp()(attribute_name, *found_it))
  211. {
  212. attributes_written.insert(found_it, attribute_name);
  213. LLXMLNodePtr attribute_node = type_declaration_node->createChild("xs:attribute", false);
  214. // attribute name
  215. attribute_node->createChild("name", true)->setStringValue(attribute_name);
  216. if (new_enum_type_node.notNull())
  217. {
  218. attribute_node->addChild(new_enum_type_node);
  219. }
  220. else
  221. {
  222. // simple attribute type
  223. attribute_node->createChild("type", true)->setStringValue(type);
  224. }
  225. // required or optional
  226. attribute_node->createChild("use", true)->setStringValue(mandatory ? "required" : "optional");
  227. }
  228.  // attribute exists...handle collision of same name attributes with potentially different types
  229. else
  230. {
  231. LLXMLNodePtr attribute_declaration;
  232. if (type_declaration_node.notNull())
  233. {
  234. for(LLXMLNodePtr node = type_declaration_node->mChildren->tail; 
  235. node.notNull(); 
  236. node = node->mPrev)
  237. {
  238. std::string name;
  239. if (node->getAttributeString("name", name) && name == attribute_name)
  240. {
  241. attribute_declaration = node;
  242. break;
  243. }
  244. }
  245. }
  246. bool new_type_is_enum = new_enum_type_node.notNull();
  247. bool existing_type_is_enum = !attribute_declaration->hasAttribute("type");
  248. // either type is enum, revert to string in collision
  249. // don't bother to check for enum equivalence
  250. if (new_type_is_enum || existing_type_is_enum)
  251. {
  252. if (attribute_declaration->hasAttribute("type"))
  253. {
  254. attribute_declaration->setAttributeString("type", "xs:string");
  255. }
  256. else
  257. {
  258. attribute_declaration->createChild("type", true)->setStringValue("xs:string");
  259. }
  260. attribute_declaration->deleteChildren("xs:simpleType");
  261. }
  262. else 
  263. {
  264. // check for collision of different standard types
  265. std::string existing_type;
  266. attribute_declaration->getAttributeString("type", existing_type);
  267. // if current type is not the same as the new type, revert to strnig
  268. if (existing_type != type)
  269. {
  270. // ...than use most general type, string
  271. attribute_declaration->setAttributeString("type", "string");
  272. }
  273. }
  274. }
  275. }
  276. }
  277. //
  278. // LLXUIXSDWriter
  279. //
  280. void LLXUIXSDWriter::writeXSD(const std::string& type_name, const std::string& path, const LLInitParam::BaseBlock& block)
  281. {
  282. std::string file_name(path);
  283. file_name += type_name + ".xsd";
  284. LLXMLNodePtr root_nodep = new LLXMLNode();
  285. LLXSDWriter::writeXSD(type_name, root_nodep, block, "http://www.lindenlab.com/xui");
  286. // add includes for all possible children
  287. const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name);
  288. const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type);
  289. // add choices for valid children
  290. if (widget_registryp)
  291. {
  292. // add include declarations for all valid children
  293. for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems();
  294.      it != widget_registryp->currentRegistrar().endItems();
  295.      ++it)
  296. {
  297. std::string widget_name = it->first;
  298. if (widget_name == type_name)
  299. {
  300. continue;
  301. }
  302. LLXMLNodePtr nodep = new LLXMLNode("xs:include", false);
  303. nodep->createChild("schemaLocation", true)->setStringValue(widget_name + ".xsd");
  304. // add to front of schema
  305. mSchemaNode->addChild(nodep, mSchemaNode);
  306. }
  307. for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems();
  308. it != widget_registryp->currentRegistrar().endItems();
  309. ++it)
  310. {
  311. std::string widget_name = it->first;
  312. //<xs:element name="widget_name" type="widget_name">
  313. LLXMLNodePtr widget_node = mElementNode->createChild("xs:element", false);
  314. widget_node->createChild("name", true)->setStringValue(widget_name);
  315. widget_node->createChild("type", true)->setStringValue(widget_name);
  316. }
  317. }
  318. LLFILE* xsd_file = LLFile::fopen(file_name.c_str(), "w");
  319. LLXMLNode::writeHeaderToFile(xsd_file);
  320. root_nodep->writeToFile(xsd_file);
  321. fclose(xsd_file);
  322. }
  323. //
  324. // LLXUIParser
  325. //
  326. LLXUIParser::LLXUIParser()
  327. : mLastWriteGeneration(-1),
  328. mCurReadDepth(0)
  329. {
  330. registerParserFuncs<bool>(boost::bind(&LLXUIParser::readBoolValue, this, _1),
  331. boost::bind(&LLXUIParser::writeBoolValue, this, _1, _2));
  332. registerParserFuncs<std::string>(boost::bind(&LLXUIParser::readStringValue, this, _1),
  333. boost::bind(&LLXUIParser::writeStringValue, this, _1, _2));
  334. registerParserFuncs<U8>(boost::bind(&LLXUIParser::readU8Value, this, _1),
  335. boost::bind(&LLXUIParser::writeU8Value, this, _1, _2));
  336. registerParserFuncs<S8>(boost::bind(&LLXUIParser::readS8Value, this, _1),
  337. boost::bind(&LLXUIParser::writeS8Value, this, _1, _2));
  338. registerParserFuncs<U16>(boost::bind(&LLXUIParser::readU16Value, this, _1),
  339. boost::bind(&LLXUIParser::writeU16Value, this, _1, _2));
  340. registerParserFuncs<S16>(boost::bind(&LLXUIParser::readS16Value, this, _1),
  341. boost::bind(&LLXUIParser::writeS16Value, this, _1, _2));
  342. registerParserFuncs<U32>(boost::bind(&LLXUIParser::readU32Value, this, _1),
  343. boost::bind(&LLXUIParser::writeU32Value, this, _1, _2));
  344. registerParserFuncs<S32>(boost::bind(&LLXUIParser::readS32Value, this, _1),
  345. boost::bind(&LLXUIParser::writeS32Value, this, _1, _2));
  346. registerParserFuncs<F32>(boost::bind(&LLXUIParser::readF32Value, this, _1),
  347. boost::bind(&LLXUIParser::writeF32Value, this, _1, _2));
  348. registerParserFuncs<F64>(boost::bind(&LLXUIParser::readF64Value, this, _1),
  349. boost::bind(&LLXUIParser::writeF64Value, this, _1, _2));
  350. registerParserFuncs<LLColor4>(boost::bind(&LLXUIParser::readColor4Value, this, _1),
  351. boost::bind(&LLXUIParser::writeColor4Value, this, _1, _2));
  352. registerParserFuncs<LLUIColor>(boost::bind(&LLXUIParser::readUIColorValue, this, _1),
  353. boost::bind(&LLXUIParser::writeUIColorValue, this, _1, _2));
  354. registerParserFuncs<LLUUID>(boost::bind(&LLXUIParser::readUUIDValue, this, _1),
  355. boost::bind(&LLXUIParser::writeUUIDValue, this, _1, _2));
  356. registerParserFuncs<LLSD>(boost::bind(&LLXUIParser::readSDValue, this, _1),
  357. boost::bind(&LLXUIParser::writeSDValue, this, _1, _2));
  358. }
  359. static LLFastTimer::DeclareTimer FTM_PARSE_XUI("XUI Parsing");
  360. void LLXUIParser::readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, const std::string& filename, bool silent)
  361. {
  362. LLFastTimer timer(FTM_PARSE_XUI);
  363. mNameStack.clear();
  364. mCurFileName = filename;
  365. mCurReadDepth = 0;
  366. setParseSilently(silent);
  367. if (node.isNull())
  368. {
  369. parserWarning("Invalid node");
  370. }
  371. else
  372. {
  373. readXUIImpl(node, std::string(node->getName()->mString), block);
  374. }
  375. }
  376. bool LLXUIParser::readXUIImpl(LLXMLNodePtr nodep, const std::string& scope, LLInitParam::BaseBlock& block)
  377. {
  378. typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
  379. boost::char_separator<char> sep(".");
  380. bool values_parsed = false;
  381. // submit attributes for current node
  382. values_parsed |= readAttributes(nodep, block);
  383. // treat text contents of xml node as "value" parameter
  384. std::string text_contents = nodep->getSanitizedValue();
  385. if (!text_contents.empty())
  386. {
  387. mCurReadNode = nodep;
  388. mNameStack.push_back(std::make_pair(std::string("value"), newParseGeneration()));
  389. // child nodes are not necessarily valid parameters (could be a child widget)
  390. // so don't complain once we've recursed
  391. bool silent = mCurReadDepth > 0;
  392. if (!block.submitValue(mNameStack, *this, true))
  393. {
  394. mNameStack.pop_back();
  395. block.submitValue(mNameStack, *this, silent);
  396. }
  397. else
  398. {
  399. mNameStack.pop_back();
  400. }
  401. }
  402. // then traverse children
  403. // child node must start with last name of parent node (our "scope")
  404. // for example: "<button><button.param nested_param1="foo"><param.nested_param2 nested_param3="bar"/></button.param></button>"
  405. // which equates to the following nesting:
  406. // button
  407. //     param
  408. //         nested_param1
  409. //         nested_param2
  410. //             nested_param3
  411. mCurReadDepth++;
  412. for(LLXMLNodePtr childp = nodep->getFirstChild(); childp.notNull();)
  413. {
  414. std::string child_name(childp->getName()->mString);
  415. S32 num_tokens_pushed = 0;
  416. // for non "dotted" child nodes check to see if child node maps to another widget type
  417. // and if not, treat as a child element of the current node
  418. // e.g. <button><rect left="10"/></button> will interpret <rect> as "button.rect"
  419. // since there is no widget named "rect"
  420. if (child_name.find(".") == std::string::npos) 
  421. {
  422. mNameStack.push_back(std::make_pair(child_name, newParseGeneration()));
  423. num_tokens_pushed++;
  424. }
  425. else
  426. {
  427. // parse out "dotted" name into individual tokens
  428. tokenizer name_tokens(child_name, sep);
  429. tokenizer::iterator name_token_it = name_tokens.begin();
  430. if(name_token_it == name_tokens.end()) 
  431. {
  432. childp = childp->getNextSibling();
  433. continue;
  434. }
  435. // check for proper nesting
  436. if(!scope.empty() && *name_token_it != scope)
  437. {
  438. childp = childp->getNextSibling();
  439. continue;
  440. }
  441. // now ignore first token
  442. ++name_token_it; 
  443. // copy remaining tokens on to our running token list
  444. for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push)
  445. {
  446. mNameStack.push_back(std::make_pair(*token_to_push, newParseGeneration()));
  447. num_tokens_pushed++;
  448. }
  449. }
  450. // recurse and visit children XML nodes
  451. if(readXUIImpl(childp, mNameStack.empty() ? scope : mNameStack.back().first, block))
  452. {
  453. // child node successfully parsed, remove from DOM
  454. values_parsed = true;
  455. LLXMLNodePtr node_to_remove = childp;
  456. childp = childp->getNextSibling();
  457. nodep->deleteChild(node_to_remove);
  458. }
  459. else
  460. {
  461. childp = childp->getNextSibling();
  462. }
  463. while(num_tokens_pushed-- > 0)
  464. {
  465. mNameStack.pop_back();
  466. }
  467. }
  468. mCurReadDepth--;
  469. return values_parsed;
  470. }
  471. bool LLXUIParser::readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block)
  472. {
  473. typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
  474. boost::char_separator<char> sep(".");
  475. bool any_parsed = false;
  476. for(LLXMLAttribList::const_iterator attribute_it = nodep->mAttributes.begin(); 
  477. attribute_it != nodep->mAttributes.end(); 
  478. ++attribute_it)
  479. {
  480. S32 num_tokens_pushed = 0;
  481. std::string attribute_name(attribute_it->first->mString);
  482. mCurReadNode = attribute_it->second;
  483. tokenizer name_tokens(attribute_name, sep);
  484. // copy remaining tokens on to our running token list
  485. for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push)
  486. {
  487. mNameStack.push_back(std::make_pair(*token_to_push, newParseGeneration()));
  488. num_tokens_pushed++;
  489. }
  490. // child nodes are not necessarily valid attributes, so don't complain once we've recursed
  491. bool silent = mCurReadDepth > 0;
  492. any_parsed |= block.submitValue(mNameStack, *this, silent);
  493. while(num_tokens_pushed-- > 0)
  494. {
  495. mNameStack.pop_back();
  496. }
  497. }
  498. return any_parsed;
  499. }
  500. void LLXUIParser::writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock &block, const LLInitParam::BaseBlock* diff_block)
  501. {
  502. mWriteRootNode = node;
  503. block.serializeBlock(*this, Parser::name_stack_t(), diff_block);
  504. mOutNodes.clear();
  505. }
  506. // go from a stack of names to a specific XML node
  507. LLXMLNodePtr LLXUIParser::getNode(const name_stack_t& stack)
  508. {
  509. name_stack_t name_stack;
  510. for (name_stack_t::const_iterator it = stack.begin();
  511. it != stack.end();
  512. ++it)
  513. {
  514. if (!it->first.empty())
  515. {
  516. name_stack.push_back(*it);
  517. }
  518. }
  519. LLXMLNodePtr out_node = mWriteRootNode;
  520. name_stack_t::const_iterator next_it = name_stack.begin();
  521. for (name_stack_t::const_iterator it = name_stack.begin();
  522. it != name_stack.end();
  523. it = next_it)
  524. {
  525. ++next_it;
  526. if (it->first.empty())
  527. {
  528. continue;
  529. }
  530. out_nodes_t::iterator found_it = mOutNodes.lower_bound(it->second);
  531. // node with this name not yet written
  532. if (found_it == mOutNodes.end() || mOutNodes.key_comp()(found_it->first, it->second))
  533. {
  534. // make an attribute if we are the last element on the name stack
  535. bool is_attribute = next_it == name_stack.end();
  536. LLXMLNodePtr new_node = new LLXMLNode(it->first.c_str(), is_attribute);
  537. out_node->addChild(new_node);
  538. mOutNodes.insert(found_it, std::make_pair(it->second, new_node));
  539. out_node = new_node;
  540. }
  541. else
  542. {
  543. out_node = found_it->second;
  544. }
  545. }
  546. return (out_node == mWriteRootNode ? LLXMLNodePtr(NULL) : out_node);
  547. }
  548. bool LLXUIParser::readBoolValue(void* val_ptr)
  549. {
  550. S32 value;
  551. bool success = mCurReadNode->getBoolValue(1, &value);
  552. *((bool*)val_ptr) = (value != FALSE);
  553. return success;
  554. }
  555. bool LLXUIParser::writeBoolValue(const void* val_ptr, const name_stack_t& stack)
  556. {
  557. LLXMLNodePtr node = getNode(stack);
  558. if (node.notNull())
  559. {
  560. node->setBoolValue(*((bool*)val_ptr));
  561. return true;
  562. }
  563. return false;
  564. }
  565. bool LLXUIParser::readStringValue(void* val_ptr)
  566. {
  567. *((std::string*)val_ptr) = mCurReadNode->getSanitizedValue();
  568. return true;
  569. }
  570. bool LLXUIParser::writeStringValue(const void* val_ptr, const name_stack_t& stack)
  571. {
  572. LLXMLNodePtr node = getNode(stack);
  573. if (node.notNull())
  574. {
  575. const std::string* string_val = reinterpret_cast<const std::string*>(val_ptr);
  576. if (string_val->find('n') != std::string::npos 
  577. || string_val->size() > MAX_STRING_ATTRIBUTE_SIZE)
  578. {
  579. // don't write strings with newlines into attributes
  580. std::string attribute_name = node->getName()->mString;
  581. LLXMLNodePtr parent_node = node->mParent;
  582. parent_node->deleteChild(node);
  583. // write results in text contents of node
  584. if (attribute_name == "value")
  585. {
  586. // "value" is implicit, just write to parent
  587. node = parent_node;
  588. }
  589. else
  590. {
  591. // create a child that is not an attribute, but with same name
  592. node = parent_node->createChild(attribute_name.c_str(), false);
  593. }
  594. }
  595. node->setStringValue(*string_val);
  596. return true;
  597. }
  598. return false;
  599. }
  600. bool LLXUIParser::readU8Value(void* val_ptr)
  601. {
  602. return mCurReadNode->getByteValue(1, (U8*)val_ptr);
  603. }
  604. bool LLXUIParser::writeU8Value(const void* val_ptr, const name_stack_t& stack)
  605. {
  606. LLXMLNodePtr node = getNode(stack);
  607. if (node.notNull())
  608. {
  609. node->setUnsignedValue(*((U8*)val_ptr));
  610. return true;
  611. }
  612. return false;
  613. }
  614. bool LLXUIParser::readS8Value(void* val_ptr)
  615. {
  616. S32 value;
  617. if(mCurReadNode->getIntValue(1, &value))
  618. {
  619. *((S8*)val_ptr) = value;
  620. return true;
  621. }
  622. return false;
  623. }
  624. bool LLXUIParser::writeS8Value(const void* val_ptr, const name_stack_t& stack)
  625. {
  626. LLXMLNodePtr node = getNode(stack);
  627. if (node.notNull())
  628. {
  629. node->setIntValue(*((S8*)val_ptr));
  630. return true;
  631. }
  632. return false;
  633. }
  634. bool LLXUIParser::readU16Value(void* val_ptr)
  635. {
  636. U32 value;
  637. if(mCurReadNode->getUnsignedValue(1, &value))
  638. {
  639. *((U16*)val_ptr) = value;
  640. return true;
  641. }
  642. return false;
  643. }
  644. bool LLXUIParser::writeU16Value(const void* val_ptr, const name_stack_t& stack)
  645. {
  646. LLXMLNodePtr node = getNode(stack);
  647. if (node.notNull())
  648. {
  649. node->setUnsignedValue(*((U16*)val_ptr));
  650. return true;
  651. }
  652. return false;
  653. }
  654. bool LLXUIParser::readS16Value(void* val_ptr)
  655. {
  656. S32 value;
  657. if(mCurReadNode->getIntValue(1, &value))
  658. {
  659. *((S16*)val_ptr) = value;
  660. return true;
  661. }
  662. return false;
  663. }
  664. bool LLXUIParser::writeS16Value(const void* val_ptr, const name_stack_t& stack)
  665. {
  666. LLXMLNodePtr node = getNode(stack);
  667. if (node.notNull())
  668. {
  669. node->setIntValue(*((S16*)val_ptr));
  670. return true;
  671. }
  672. return false;
  673. }
  674. bool LLXUIParser::readU32Value(void* val_ptr)
  675. {
  676. return mCurReadNode->getUnsignedValue(1, (U32*)val_ptr);
  677. }
  678. bool LLXUIParser::writeU32Value(const void* val_ptr, const name_stack_t& stack)
  679. {
  680. LLXMLNodePtr node = getNode(stack);
  681. if (node.notNull())
  682. {
  683. node->setUnsignedValue(*((U32*)val_ptr));
  684. return true;
  685. }
  686. return false;
  687. }
  688. bool LLXUIParser::readS32Value(void* val_ptr)
  689. {
  690. return mCurReadNode->getIntValue(1, (S32*)val_ptr);
  691. }
  692. bool LLXUIParser::writeS32Value(const void* val_ptr, const name_stack_t& stack)
  693. {
  694. LLXMLNodePtr node = getNode(stack);
  695. if (node.notNull())
  696. {
  697. node->setIntValue(*((S32*)val_ptr));
  698. return true;
  699. }
  700. return false;
  701. }
  702. bool LLXUIParser::readF32Value(void* val_ptr)
  703. {
  704. return mCurReadNode->getFloatValue(1, (F32*)val_ptr);
  705. }
  706. bool LLXUIParser::writeF32Value(const void* val_ptr, const name_stack_t& stack)
  707. {
  708. LLXMLNodePtr node = getNode(stack);
  709. if (node.notNull())
  710. {
  711. node->setFloatValue(*((F32*)val_ptr));
  712. return true;
  713. }
  714. return false;
  715. }
  716. bool LLXUIParser::readF64Value(void* val_ptr)
  717. {
  718. return mCurReadNode->getDoubleValue(1, (F64*)val_ptr);
  719. }
  720. bool LLXUIParser::writeF64Value(const void* val_ptr, const name_stack_t& stack)
  721. {
  722. LLXMLNodePtr node = getNode(stack);
  723. if (node.notNull())
  724. {
  725. node->setDoubleValue(*((F64*)val_ptr));
  726. return true;
  727. }
  728. return false;
  729. }
  730. bool LLXUIParser::readColor4Value(void* val_ptr)
  731. {
  732. LLColor4* colorp = (LLColor4*)val_ptr;
  733. if(mCurReadNode->getFloatValue(4, colorp->mV) >= 3)
  734. {
  735. return true;
  736. }
  737. return false;
  738. }
  739. bool LLXUIParser::writeColor4Value(const void* val_ptr, const name_stack_t& stack)
  740. {
  741. LLXMLNodePtr node = getNode(stack);
  742. if (node.notNull())
  743. {
  744. LLColor4 color = *((LLColor4*)val_ptr);
  745. node->setFloatValue(4, color.mV);
  746. return true;
  747. }
  748. return false;
  749. }
  750. bool LLXUIParser::readUIColorValue(void* val_ptr)
  751. {
  752. LLUIColor* param = (LLUIColor*)val_ptr;
  753. LLColor4 color;
  754. bool success =  mCurReadNode->getFloatValue(4, color.mV) >= 3;
  755. if (success)
  756. {
  757. param->set(color);
  758. return true;
  759. }
  760. return false;
  761. }
  762. bool LLXUIParser::writeUIColorValue(const void* val_ptr, const name_stack_t& stack)
  763. {
  764. LLXMLNodePtr node = getNode(stack);
  765. if (node.notNull())
  766. {
  767. LLUIColor color = *((LLUIColor*)val_ptr);
  768. //RN: don't write out the color that is represented by a function
  769. // rely on param block exporting to get the reference to the color settings
  770. if (color.isReference()) return false;
  771. node->setFloatValue(4, color.get().mV);
  772. return true;
  773. }
  774. return false;
  775. }
  776. bool LLXUIParser::readUUIDValue(void* val_ptr)
  777. {
  778. LLUUID temp_id;
  779. // LLUUID::set is destructive, so use temporary value
  780. if (temp_id.set(mCurReadNode->getSanitizedValue()))
  781. {
  782. *(LLUUID*)(val_ptr) = temp_id;
  783. return true;
  784. }
  785. return false;
  786. }
  787. bool LLXUIParser::writeUUIDValue(const void* val_ptr, const name_stack_t& stack)
  788. {
  789. LLXMLNodePtr node = getNode(stack);
  790. if (node.notNull())
  791. {
  792. node->setStringValue(((LLUUID*)val_ptr)->asString());
  793. return true;
  794. }
  795. return false;
  796. }
  797. bool LLXUIParser::readSDValue(void* val_ptr)
  798. {
  799. *((LLSD*)val_ptr) = LLSD(mCurReadNode->getSanitizedValue());
  800. return true;
  801. }
  802. bool LLXUIParser::writeSDValue(const void* val_ptr, const name_stack_t& stack)
  803. {
  804. LLXMLNodePtr node = getNode(stack);
  805. if (node.notNull())
  806. {
  807. std::string string_val = ((LLSD*)val_ptr)->asString();
  808. if (string_val.find('n') != std::string::npos || string_val.size() > MAX_STRING_ATTRIBUTE_SIZE)
  809. {
  810. // don't write strings with newlines into attributes
  811. std::string attribute_name = node->getName()->mString;
  812. LLXMLNodePtr parent_node = node->mParent;
  813. parent_node->deleteChild(node);
  814. // write results in text contents of node
  815. if (attribute_name == "value")
  816. {
  817. // "value" is implicit, just write to parent
  818. node = parent_node;
  819. }
  820. else
  821. {
  822. node = parent_node->createChild(attribute_name.c_str(), false);
  823. }
  824. }
  825. node->setStringValue(string_val);
  826. return true;
  827. }
  828. return false;
  829. }
  830. /*virtual*/ std::string LLXUIParser::getCurrentElementName()
  831. {
  832. std::string full_name;
  833. for (name_stack_t::iterator it = mNameStack.begin();
  834. it != mNameStack.end();
  835. ++it)
  836. {
  837. full_name += it->first + "."; // build up dotted names: "button.param.nestedparam."
  838. }
  839. return full_name;
  840. }
  841. void LLXUIParser::parserWarning(const std::string& message)
  842. {
  843. #ifdef LL_WINDOWS
  844. // use Visual Studo friendly formatting of output message for easy access to originating xml
  845. llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):t%s", mCurFileName.c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str());
  846. utf16str += 'n';
  847. OutputDebugString(utf16str.c_str());
  848. #else
  849. Parser::parserWarning(message);
  850. #endif
  851. }
  852. void LLXUIParser::parserError(const std::string& message)
  853. {
  854. #ifdef LL_WINDOWS
  855. llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):t%s", mCurFileName.c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str());
  856. utf16str += 'n';
  857. OutputDebugString(utf16str.c_str());
  858. #else
  859. Parser::parserError(message);
  860. #endif
  861. }