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

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llrngwriter.cpp
  3.  * @brief Generates Relax NG schema from param blocks
  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 "llrngwriter.h"
  34. #include "lluicolor.h"
  35. #include "lluictrlfactory.h"
  36. //
  37. // LLRNGWriter - writes Relax NG schema files based on a param block
  38. //
  39. LLRNGWriter::LLRNGWriter()
  40. {
  41. // register various callbacks for inspecting the contents of a param block
  42. registerInspectFunc<bool>(boost::bind(&LLRNGWriter::writeAttribute, this, "boolean", _1, _2, _3, _4));
  43. registerInspectFunc<std::string>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4));
  44. registerInspectFunc<U8>(boost::bind(&LLRNGWriter::writeAttribute, this, "unsignedByte", _1, _2, _3, _4));
  45. registerInspectFunc<S8>(boost::bind(&LLRNGWriter::writeAttribute, this, "signedByte", _1, _2, _3, _4));
  46. registerInspectFunc<U16>(boost::bind(&LLRNGWriter::writeAttribute, this, "unsignedShort", _1, _2, _3, _4));
  47. registerInspectFunc<S16>(boost::bind(&LLRNGWriter::writeAttribute, this, "signedShort", _1, _2, _3, _4));
  48. registerInspectFunc<U32>(boost::bind(&LLRNGWriter::writeAttribute, this, "unsignedInt", _1, _2, _3, _4));
  49. registerInspectFunc<S32>(boost::bind(&LLRNGWriter::writeAttribute, this, "integer", _1, _2, _3, _4));
  50. registerInspectFunc<F32>(boost::bind(&LLRNGWriter::writeAttribute, this, "float", _1, _2, _3, _4));
  51. registerInspectFunc<F64>(boost::bind(&LLRNGWriter::writeAttribute, this, "double", _1, _2, _3, _4));
  52. registerInspectFunc<LLColor4>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4));
  53. registerInspectFunc<LLUIColor>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4));
  54. registerInspectFunc<LLUUID>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4));
  55. registerInspectFunc<LLSD>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4));
  56. }
  57. void LLRNGWriter::writeRNG(const std::string& type_name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace)
  58. {
  59. mGrammarNode = node;
  60. mGrammarNode->setName("grammar");
  61. mGrammarNode->createChild("xmlns", true)->setStringValue("http://relaxng.org/ns/structure/1.0");
  62. mGrammarNode->createChild("datatypeLibrary", true)->setStringValue("http://www.w3.org/2001/XMLSchema-datatypes");
  63. mGrammarNode->createChild("ns", true)->setStringValue(xml_namespace);
  64. node = mGrammarNode->createChild("start", false);
  65. node = node->createChild("ref", false);
  66. node->createChild("name", true)->setStringValue(type_name);
  67. addDefinition(type_name, block);
  68. }
  69. void LLRNGWriter::addDefinition(const std::string& type_name, const LLInitParam::BaseBlock& block)
  70. {
  71. if (mDefinedElements.find(type_name) != mDefinedElements.end()) return;
  72. mDefinedElements.insert(type_name);
  73. LLXMLNodePtr node = mGrammarNode->createChild("define", false);
  74. node->createChild("name", true)->setStringValue(type_name);
  75. mElementNode = node->createChild("element", false);
  76. mElementNode->createChild("name", true)->setStringValue(type_name);
  77. mChildrenNode = mElementNode->createChild("zeroOrMore", false)->createChild("choice", false);
  78. mAttributesWritten.first = mElementNode;
  79. mAttributesWritten.second.clear();
  80. mElementsWritten.clear();
  81. block.inspectBlock(*this);
  82. // add includes for all possible children
  83. const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name);
  84. const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type);
  85. // add include declarations for all valid children
  86. for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems();
  87. it != widget_registryp->currentRegistrar().endItems();
  88. ++it)
  89. {
  90. std::string child_name = it->first;
  91. if (child_name == type_name)
  92. {
  93. continue;
  94. }
  95. LLXMLNodePtr old_element_node = mElementNode;
  96. LLXMLNodePtr old_child_node = mChildrenNode;
  97. //FIXME: add LLDefaultParamBlockRegistry back when working on schema generation
  98. //addDefinition(child_name, (*LLDefaultParamBlockRegistry::instance().getValue(type))());
  99. mElementNode = old_element_node;
  100. mChildrenNode = old_child_node;
  101. mChildrenNode->createChild("ref", false)->createChild("name", true)->setStringValue(child_name);
  102. }
  103. if (mChildrenNode->mChildren.isNull())
  104. {
  105. // remove unused children node
  106. mChildrenNode->mParent->mParent->deleteChild(mChildrenNode->mParent);
  107. }
  108. }
  109. void LLRNGWriter::writeAttribute(const std::string& type, const Parser::name_stack_t& stack, S32 min_count, S32 max_count, const std::vector<std::string>* possible_values)
  110. {
  111. if (max_count == 0) return;
  112. name_stack_t non_empty_names;
  113. std::string attribute_name;
  114. for (name_stack_t::const_iterator it = stack.begin();
  115. it != stack.end();
  116. ++it)
  117. {
  118. const std::string& name = it->first;
  119. if (!name.empty())
  120. {
  121. non_empty_names.push_back(*it);
  122. }
  123. }
  124. if (non_empty_names.empty()) return;
  125. for (name_stack_t::const_iterator it = non_empty_names.begin();
  126. it != non_empty_names.end();
  127. ++it)
  128. {
  129. if (!attribute_name.empty())
  130. {
  131. attribute_name += ".";
  132. }
  133. attribute_name += it->first;
  134. }
  135. // singular attribute, e.g. <foo bar="1"/>
  136. if (non_empty_names.size() == 1 && max_count == 1)
  137. {
  138. if (mAttributesWritten.second.find(attribute_name) == mAttributesWritten.second.end())
  139. {
  140. LLXMLNodePtr node = createCardinalityNode(mElementNode, min_count, max_count)->createChild("attribute", false);
  141. node->createChild("name", true)->setStringValue(attribute_name);
  142. node->createChild("data", false)->createChild("type", true)->setStringValue(type);
  143. mAttributesWritten.second.insert(attribute_name);
  144. }
  145. }
  146. // compound attribute
  147. else
  148. {
  149. std::string element_name;
  150. // traverse all but last element, leaving that as an attribute name
  151. name_stack_t::const_iterator end_it = non_empty_names.end();
  152. end_it--;
  153. for (name_stack_t::const_iterator it = non_empty_names.begin();
  154. it != end_it;
  155. ++it)
  156. {
  157. if (it != non_empty_names.begin())
  158. {
  159. element_name += ".";
  160. }
  161. element_name += it->first;
  162. }
  163. elements_map_t::iterator found_it = mElementsWritten.find(element_name);
  164. // <choice>
  165. //   <group>
  166. //     <optional>
  167. //      <attribute name="foo.bar"><data type="string"/></attribute>
  168. //     </optional>
  169. //     <optional>
  170. //       <attribute name="foo.baz"><data type="integer"/></attribute>
  171. //     </optional>
  172. //   </group>
  173. //   <element name="foo">
  174. //     <optional>
  175. //       <attribute name="bar"><data type="string"/></attribute>
  176. //     </optional>
  177. //     <optional>
  178. //       <attribute name="baz"><data type="string"/></attribute>
  179. //     </optional>
  180. //   </element>
  181. //   <element name="outer.foo">
  182. //     <ref name="foo"/>
  183. //   </element>
  184. // </choice>
  185. if (found_it != mElementsWritten.end())
  186. {
  187. // reuse existing element
  188. LLXMLNodePtr choice_node = found_it->second.first;
  189. // attribute with this name not already written?
  190. if (found_it->second.second.find(attribute_name) == found_it->second.second.end())
  191. {
  192. // append to <group>
  193. LLXMLNodePtr node = choice_node->mChildren->head;
  194. node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false);
  195. node->createChild("name", true)->setStringValue(attribute_name);
  196. addTypeNode(node, type, possible_values);
  197. // append to <element>
  198. node = choice_node->mChildren->head->mNext->mChildren->head;
  199. node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false);
  200. node->createChild("name", true)->setStringValue(non_empty_names.back().first);
  201. addTypeNode(node, type, possible_values);
  202. // append to <element>
  203. //node = choice_node->mChildren->head->mNext->mNext->mChildren->head;
  204. //node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false);
  205. //node->createChild("name", true)->setStringValue(non_empty_names.back().first);
  206. //addTypeNode(node, type, possible_values);
  207. found_it->second.second.insert(attribute_name);
  208. }
  209. }
  210. else
  211. {
  212. LLXMLNodePtr choice_node = mElementNode->createChild("choice", false);
  213. LLXMLNodePtr node = choice_node->createChild("group", false);
  214. node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false);
  215. node->createChild("name", true)->setStringValue(attribute_name);
  216. addTypeNode(node, type, possible_values);
  217. node = choice_node->createChild("optional", false);
  218. node = node->createChild("element", false);
  219. node->createChild("name", true)->setStringValue(element_name);
  220. node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false);
  221. node->createChild("name", true)->setStringValue(non_empty_names.back().first);
  222. addTypeNode(node, type, possible_values);
  223. //node = choice_node->createChild("optional", false);
  224. //node = node->createChild("element", false);
  225. //node->createChild("name", true)->setStringValue(mDefinitionName + "." + element_name);
  226. //node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false);
  227. //node->createChild("name", true)->setStringValue(non_empty_names.back().first);
  228. //addTypeNode(node, type, possible_values);
  229. attribute_data_t& attribute_data = mElementsWritten[element_name];
  230. attribute_data.first = choice_node;
  231. attribute_data.second.insert(attribute_name);
  232. }
  233. }
  234. }
  235. void LLRNGWriter::addTypeNode(LLXMLNodePtr parent_node, const std::string& type, const std::vector<std::string>* possible_values)
  236. {
  237. if (possible_values)
  238. {
  239. LLXMLNodePtr enum_node = parent_node->createChild("choice", false);
  240. for (std::vector<std::string>::const_iterator it = possible_values->begin();
  241. it != possible_values->end();
  242. ++it)
  243. {
  244. enum_node->createChild("value", false)->setStringValue(*it);
  245. }
  246. }
  247. else
  248. {
  249. parent_node->createChild("data", false)->createChild("type", true)->setStringValue(type);
  250. }
  251. }
  252. LLXMLNodePtr LLRNGWriter::createCardinalityNode(LLXMLNodePtr parent_node, S32 min_count, S32 max_count)
  253. {
  254. // unlinked by default, meaning this attribute is forbidden
  255. LLXMLNodePtr count_node = new LLXMLNode();
  256. if (min_count == 0)
  257. {
  258. if (max_count == 1)
  259. {
  260. count_node = parent_node->createChild("optional", false);
  261. }
  262. else if (max_count > 1)
  263. {
  264. count_node = parent_node->createChild("zeroOrMore", false);
  265. }
  266. }
  267. else if (min_count >= 1)
  268. {
  269. if (max_count == 1 && min_count == 1)
  270. {
  271. // just add raw element, will count as 1 and only 1
  272. count_node = parent_node;
  273. }
  274. else
  275. {
  276. count_node = parent_node->createChild("oneOrMore", false);
  277. }
  278. }
  279. return count_node;
  280. }