XMLElement.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035
  1. //
  2. // Copyright (c) 2008-2013 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Context.h"
  24. #include "Log.h"
  25. #include "StringUtils.h"
  26. #include "XMLFile.h"
  27. #include <pugixml.hpp>
  28. #include "DebugNew.h"
  29. namespace Urho3D
  30. {
  31. const XMLElement XMLElement::EMPTY;
  32. XMLElement::XMLElement() :
  33. node_(0),
  34. xpathResultSet_(0),
  35. xpathNode_(0),
  36. xpathResultIndex_(0)
  37. {
  38. }
  39. XMLElement::XMLElement(XMLFile* file, pugi::xml_node_struct* node) :
  40. file_(file),
  41. node_(node),
  42. xpathResultSet_(0),
  43. xpathNode_(0),
  44. xpathResultIndex_(0)
  45. {
  46. }
  47. XMLElement::XMLElement(XMLFile* file, const XPathResultSet* resultSet, const pugi::xpath_node* xpathNode, unsigned xpathResultIndex) :
  48. file_(file),
  49. node_(0),
  50. xpathResultSet_(resultSet),
  51. xpathNode_(resultSet ? xpathNode : (xpathNode ? new pugi::xpath_node(*xpathNode) : 0)),
  52. xpathResultIndex_(xpathResultIndex)
  53. {
  54. }
  55. XMLElement::XMLElement(const XMLElement& rhs) :
  56. file_(rhs.file_),
  57. node_(rhs.node_),
  58. xpathResultSet_(rhs.xpathResultSet_),
  59. xpathNode_(rhs.xpathResultSet_ ? rhs.xpathNode_ : (rhs.xpathNode_ ? new pugi::xpath_node(*rhs.xpathNode_) : 0)),
  60. xpathResultIndex_(rhs.xpathResultIndex_)
  61. {
  62. }
  63. XMLElement::~XMLElement()
  64. {
  65. // XMLElement class takes the ownership of a single xpath_node object, so destruct it now
  66. if (!xpathResultSet_ && xpathNode_)
  67. {
  68. delete xpathNode_;
  69. xpathNode_ = 0;
  70. }
  71. }
  72. XMLElement& XMLElement::operator = (const XMLElement& rhs)
  73. {
  74. file_ = rhs.file_;
  75. node_ = rhs.node_;
  76. xpathResultSet_ = rhs.xpathResultSet_;
  77. xpathNode_ = rhs.xpathResultSet_ ? rhs.xpathNode_ : (rhs.xpathNode_ ? new pugi::xpath_node(*rhs.xpathNode_) : 0);
  78. xpathResultIndex_ = rhs.xpathResultIndex_;
  79. return *this;
  80. }
  81. XMLElement XMLElement::CreateChild(const String& name)
  82. {
  83. return CreateChild(name.CString());
  84. }
  85. XMLElement XMLElement::CreateChild(const char* name)
  86. {
  87. if (!file_ || (!node_ && !xpathNode_))
  88. return XMLElement();
  89. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node(): pugi::xml_node(node_);
  90. pugi::xml_node child = const_cast<pugi::xml_node&>(node).append_child(name);
  91. return XMLElement(file_, child.internal_object());
  92. }
  93. bool XMLElement::RemoveChild(const XMLElement& element)
  94. {
  95. if (!element.file_ || (!element.node_ && !element.xpathNode_) || !file_ || (!node_ && !xpathNode_))
  96. return false;
  97. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node(): pugi::xml_node(node_);
  98. const pugi::xml_node& child = element.xpathNode_ ? element.xpathNode_->node(): pugi::xml_node(element.node_);
  99. return const_cast<pugi::xml_node&>(node).remove_child(child);
  100. }
  101. bool XMLElement::RemoveChild(const String& name)
  102. {
  103. return RemoveChild(name.CString());
  104. }
  105. bool XMLElement::RemoveChild(const char* name)
  106. {
  107. if (!file_ || (!node_ && !xpathNode_))
  108. return false;
  109. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node(): pugi::xml_node(node_);
  110. return const_cast<pugi::xml_node&>(node).remove_child(name);
  111. }
  112. bool XMLElement::RemoveChildren(const String& name)
  113. {
  114. return RemoveChildren(name.CString());
  115. }
  116. bool XMLElement::RemoveChildren(const char* name)
  117. {
  118. if ((!file_ || !node_) && !xpathNode_)
  119. return false;
  120. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node(): pugi::xml_node(node_);
  121. if (!String::CStringLength(name))
  122. {
  123. for (;;)
  124. {
  125. pugi::xml_node child = node.last_child();
  126. if (child.empty())
  127. break;
  128. const_cast<pugi::xml_node&>(node).remove_child(child);
  129. }
  130. }
  131. else
  132. {
  133. for (;;)
  134. {
  135. pugi::xml_node child = node.child(name);
  136. if (child.empty())
  137. break;
  138. const_cast<pugi::xml_node&>(node).remove_child(child);
  139. }
  140. }
  141. return true;
  142. }
  143. bool XMLElement::RemoveAttribute(const String& name)
  144. {
  145. return RemoveAttribute(name.CString());
  146. }
  147. bool XMLElement::RemoveAttribute(const char* name)
  148. {
  149. if (!file_ || (!node_ && !xpathNode_))
  150. return false;
  151. // If xpath_node contains just attribute, remove it regardless of the specified name
  152. if (xpathNode_ && xpathNode_->attribute())
  153. return xpathNode_->parent().remove_attribute(xpathNode_->attribute()); // In attribute context, xpath_node's parent is the parent node of the attribute itself
  154. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node(): pugi::xml_node(node_);
  155. return const_cast<pugi::xml_node&>(node).remove_attribute(node.attribute(name));
  156. }
  157. XMLElement XMLElement::SelectSingle(const String& query, pugi::xpath_variable_set* variables) const
  158. {
  159. if (!file_ || (!node_ && !xpathNode_))
  160. return XMLElement();
  161. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node(): pugi::xml_node(node_);
  162. pugi::xpath_node result = node.select_single_node(query.CString(), variables);
  163. return XMLElement(file_, 0, &result, 0);
  164. }
  165. XMLElement XMLElement::SelectSinglePrepared(const XPathQuery& query) const
  166. {
  167. if (!file_ || (!node_ && !xpathNode_ && !query.GetXPathQuery()))
  168. return XMLElement();
  169. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node(): pugi::xml_node(node_);
  170. pugi::xpath_node result = node.select_single_node(*query.GetXPathQuery());
  171. return XMLElement(file_, 0, &result, 0);
  172. }
  173. XPathResultSet XMLElement::Select(const String& query, pugi::xpath_variable_set* variables) const
  174. {
  175. if (!file_ || (!node_ && !xpathNode_))
  176. return XPathResultSet();
  177. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node(): pugi::xml_node(node_);
  178. pugi::xpath_node_set result = node.select_nodes(query.CString(), variables);
  179. return XPathResultSet(file_, &result);
  180. }
  181. XPathResultSet XMLElement::SelectPrepared(const XPathQuery& query) const
  182. {
  183. if (!file_ || (!node_ && !xpathNode_ && query.GetXPathQuery()))
  184. return XPathResultSet();
  185. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node(): pugi::xml_node(node_);
  186. pugi::xpath_node_set result = node.select_nodes(*query.GetXPathQuery());
  187. return XPathResultSet(file_, &result);
  188. }
  189. bool XMLElement::SetAttribute(const String& name, const String& value)
  190. {
  191. return SetAttribute(name.CString(), value.CString());
  192. }
  193. bool XMLElement::SetAttribute(const char* name, const char* value)
  194. {
  195. if (!file_ || (!node_ && !xpathNode_))
  196. return false;
  197. // If xpath_node contains just attribute, set its value regardless of the specified name
  198. if (xpathNode_ && xpathNode_->attribute())
  199. return xpathNode_->attribute().set_value(value);
  200. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node(): pugi::xml_node(node_);
  201. pugi::xml_attribute attr = node.attribute(name);
  202. if (attr.empty())
  203. attr = const_cast<pugi::xml_node&>(node).append_attribute(name);
  204. return attr.set_value(value);
  205. }
  206. bool XMLElement::SetAttribute(const String& value)
  207. {
  208. return SetAttribute(value.CString());
  209. }
  210. bool XMLElement::SetAttribute(const char* value)
  211. {
  212. // If xpath_node contains just attribute, set its value
  213. return xpathNode_ && xpathNode_->attribute() && xpathNode_->attribute().set_value(value);
  214. }
  215. bool XMLElement::SetBool(const String& name, bool value)
  216. {
  217. return SetAttribute(name, String(value));
  218. }
  219. bool XMLElement::SetBoundingBox(const BoundingBox& value)
  220. {
  221. if (!SetVector3("min", value.min_))
  222. return false;
  223. return SetVector3("max", value.max_);
  224. }
  225. bool XMLElement::SetBuffer(const String& name, const void* data, unsigned size)
  226. {
  227. String dataStr;
  228. BufferToString(dataStr, data, size);
  229. return SetAttribute(name, dataStr);
  230. }
  231. bool XMLElement::SetBuffer(const String& name, const PODVector<unsigned char>& value)
  232. {
  233. if (!value.Size())
  234. return SetAttribute(name, String::EMPTY);
  235. else
  236. return SetBuffer(name, &value[0], value.Size());
  237. }
  238. bool XMLElement::SetColor(const String& name, const Color& value)
  239. {
  240. return SetAttribute(name, value.ToString());
  241. }
  242. bool XMLElement::SetFloat(const String& name, float value)
  243. {
  244. return SetAttribute(name, String(value));
  245. }
  246. bool XMLElement::SetUInt(const String& name, unsigned value)
  247. {
  248. return SetAttribute(name, String(value));
  249. }
  250. bool XMLElement::SetInt(const String& name, int value)
  251. {
  252. return SetAttribute(name, String(value));
  253. }
  254. bool XMLElement::SetIntRect(const String& name, const IntRect& value)
  255. {
  256. return SetAttribute(name, value.ToString());
  257. }
  258. bool XMLElement::SetIntVector2(const String& name, const IntVector2& value)
  259. {
  260. return SetAttribute(name, value.ToString());
  261. }
  262. bool XMLElement::SetRect(const String& name, const Rect& value)
  263. {
  264. return SetAttribute(name, value.ToString());
  265. }
  266. bool XMLElement::SetQuaternion(const String& name, const Quaternion& value)
  267. {
  268. return SetAttribute(name, value.ToString());
  269. }
  270. bool XMLElement::SetString(const String& name, const String& value)
  271. {
  272. return SetAttribute(name, value);
  273. }
  274. bool XMLElement::SetVariant(const Variant& value)
  275. {
  276. if (!SetAttribute("type", value.GetTypeName()))
  277. return false;
  278. return SetVariantValue(value);
  279. }
  280. bool XMLElement::SetVariantValue(const Variant& value)
  281. {
  282. switch (value.GetType())
  283. {
  284. case VAR_RESOURCEREF:
  285. return SetResourceRef(value.GetResourceRef());
  286. case VAR_RESOURCEREFLIST:
  287. return SetResourceRefList(value.GetResourceRefList());
  288. case VAR_VARIANTVECTOR:
  289. return SetVariantVector(value.GetVariantVector());
  290. case VAR_VARIANTMAP:
  291. return SetVariantMap(value.GetVariantMap());
  292. default:
  293. return SetAttribute("value", value.ToString().CString());
  294. }
  295. }
  296. bool XMLElement::SetResourceRef(const ResourceRef& value)
  297. {
  298. if (!file_ || (!node_ && !xpathNode_))
  299. return false;
  300. // Need the context to query for the type
  301. Context* context = file_->GetContext();
  302. return SetAttribute("value", String(context->GetTypeName(value.type_)) + ";" + value.name_);
  303. }
  304. bool XMLElement::SetResourceRefList(const ResourceRefList& value)
  305. {
  306. if (!file_ || (!node_ && !xpathNode_))
  307. return false;
  308. // Need the context to query for the type
  309. Context* context = file_->GetContext();
  310. String str(context->GetTypeName(value.type_));
  311. for (unsigned i = 0; i < value.names_.Size(); ++i)
  312. {
  313. str += ";";
  314. str += value.names_[i];
  315. }
  316. return SetAttribute("value", str.CString());
  317. }
  318. bool XMLElement::SetVariantVector(const VariantVector& value)
  319. {
  320. // Must remove all existing variant child elements (if they exist) to not cause confusion
  321. if (!RemoveChildren("variant"))
  322. return false;
  323. for (VariantVector::ConstIterator i = value.Begin(); i != value.End(); ++i)
  324. {
  325. XMLElement variantElem = CreateChild("variant");
  326. if (!variantElem)
  327. return false;
  328. variantElem.SetVariant(*i);
  329. }
  330. return true;
  331. }
  332. bool XMLElement::SetVariantMap(const VariantMap& value)
  333. {
  334. if (!RemoveChildren("variant"))
  335. return false;
  336. for (VariantMap::ConstIterator i = value.Begin(); i != value.End(); ++i)
  337. {
  338. XMLElement variantElem = CreateChild("variant");
  339. if (!variantElem)
  340. return false;
  341. variantElem.SetInt("hash", i->first_.Value());
  342. variantElem.SetVariant(i->second_);
  343. }
  344. return true;
  345. }
  346. bool XMLElement::SetVector2(const String& name, const Vector2& value)
  347. {
  348. return SetAttribute(name, value.ToString());
  349. }
  350. bool XMLElement::SetVector3(const String& name, const Vector3& value)
  351. {
  352. return SetAttribute(name, value.ToString());
  353. }
  354. bool XMLElement::SetVector4(const String& name, const Vector4& value)
  355. {
  356. return SetAttribute(name, value.ToString());
  357. }
  358. bool XMLElement::SetVectorVariant(const String& name, const Variant& value)
  359. {
  360. VariantType type = value.GetType();
  361. if (type == VAR_FLOAT || type == VAR_VECTOR2 || type == VAR_VECTOR3 || type == VAR_VECTOR4)
  362. return SetAttribute(name, value.ToString());
  363. else
  364. return false;
  365. }
  366. bool XMLElement::IsNull() const
  367. {
  368. return !NotNull();
  369. }
  370. bool XMLElement::NotNull() const
  371. {
  372. return node_ || (xpathNode_ && !xpathNode_->operator !());
  373. }
  374. XMLElement::operator bool () const
  375. {
  376. return NotNull();
  377. }
  378. String XMLElement::GetName() const
  379. {
  380. if ((!file_ || !node_) && !xpathNode_)
  381. return String();
  382. // If xpath_node contains just attribute, return its name instead
  383. if (xpathNode_ && xpathNode_->attribute())
  384. return String(xpathNode_->attribute().name());
  385. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  386. return String(node.name());
  387. }
  388. bool XMLElement::HasChild(const String& name) const
  389. {
  390. return HasChild(name.CString());
  391. }
  392. bool XMLElement::HasChild(const char* name) const
  393. {
  394. if (!file_ || (!node_ && !xpathNode_))
  395. return false;
  396. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  397. return !node.child(name).empty();
  398. }
  399. XMLElement XMLElement::GetChild(const String& name) const
  400. {
  401. return GetChild(name.CString());
  402. }
  403. XMLElement XMLElement::GetChild(const char* name) const
  404. {
  405. if (!file_ || (!node_ && !xpathNode_))
  406. return XMLElement();
  407. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  408. if (!String::CStringLength(name))
  409. return XMLElement(file_, node.first_child().internal_object());
  410. else
  411. return XMLElement(file_, node.child(name).internal_object());
  412. }
  413. XMLElement XMLElement::GetNext(const String& name) const
  414. {
  415. return GetNext(name.CString());
  416. }
  417. XMLElement XMLElement::GetNext(const char* name) const
  418. {
  419. if (!file_ || (!node_ && !xpathNode_))
  420. return XMLElement();
  421. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  422. if (!String::CStringLength(name))
  423. return XMLElement(file_, node.next_sibling().internal_object());
  424. else
  425. return XMLElement(file_, node.next_sibling(name).internal_object());
  426. }
  427. XMLElement XMLElement::GetParent() const
  428. {
  429. if (!file_ || (!node_ && !xpathNode_))
  430. return XMLElement();
  431. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  432. return XMLElement(file_, node.parent().internal_object());
  433. }
  434. unsigned XMLElement::GetNumAttributes() const
  435. {
  436. if (!file_ || (!node_ && !xpathNode_))
  437. return 0;
  438. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  439. unsigned ret = 0;
  440. pugi::xml_attribute attr = node.first_attribute();
  441. while (!attr.empty())
  442. {
  443. ++ret;
  444. attr = attr.next_attribute();
  445. }
  446. return ret;
  447. }
  448. bool XMLElement::HasAttribute(const String& name) const
  449. {
  450. return HasAttribute(name.CString());
  451. }
  452. bool XMLElement::HasAttribute(const char* name) const
  453. {
  454. if (!file_ || (!node_ && !xpathNode_))
  455. return false;
  456. // If xpath_node contains just attribute, check against it
  457. if (xpathNode_ && xpathNode_->attribute())
  458. return String(xpathNode_->attribute().name()) == name;
  459. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  460. return !node.attribute(name).empty();
  461. }
  462. String XMLElement::GetAttribute(const String& name) const
  463. {
  464. return String(GetAttributeCString(name.CString()));
  465. }
  466. String XMLElement::GetAttribute(const char* name) const
  467. {
  468. return String(GetAttributeCString(name));
  469. }
  470. const char* XMLElement::GetAttributeCString(const char* name) const
  471. {
  472. if (!file_ || (!node_ && !xpathNode_))
  473. return 0;
  474. // If xpath_node contains just attribute, return it regardless of the specified name
  475. if (xpathNode_ && xpathNode_->attribute())
  476. return xpathNode_->attribute().value();
  477. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  478. return node.attribute(name).value();
  479. }
  480. String XMLElement::GetAttributeLower(const String& name) const
  481. {
  482. return GetAttribute(name).ToLower();
  483. }
  484. String XMLElement::GetAttributeLower(const char* name) const
  485. {
  486. return String(GetAttribute(name)).ToLower();
  487. }
  488. String XMLElement::GetAttributeUpper(const String& name) const
  489. {
  490. return GetAttribute(name).ToUpper();
  491. }
  492. String XMLElement::GetAttributeUpper(const char* name) const
  493. {
  494. return String(GetAttribute(name)).ToUpper();
  495. }
  496. Vector<String> XMLElement::GetAttributeNames() const
  497. {
  498. if (!file_ || (!node_ && !xpathNode_))
  499. return Vector<String>();
  500. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  501. Vector<String> ret;
  502. pugi::xml_attribute attr = node.first_attribute();
  503. while (!attr.empty())
  504. {
  505. ret.Push(String(attr.name()));
  506. attr = attr.next_attribute();
  507. }
  508. return ret;
  509. }
  510. bool XMLElement::GetBool(const String& name) const
  511. {
  512. return ToBool(GetAttribute(name));
  513. }
  514. BoundingBox XMLElement::GetBoundingBox() const
  515. {
  516. BoundingBox ret;
  517. ret.min_ = GetVector3("min");
  518. ret.max_ = GetVector3("max");
  519. ret.defined_ = true;
  520. return ret;
  521. }
  522. PODVector<unsigned char> XMLElement::GetBuffer(const String& name) const
  523. {
  524. PODVector<unsigned char> ret;
  525. StringToBuffer(ret, GetAttribute(name));
  526. return ret;
  527. }
  528. bool XMLElement::GetBuffer(const String& name, void* dest, unsigned size) const
  529. {
  530. PODVector<unsigned char> ret;
  531. Vector<String> bytes = GetAttribute(name).Split(' ');
  532. unsigned char* destBytes = (unsigned char*)dest;
  533. if (size < bytes.Size())
  534. return false;
  535. for (unsigned i = 0; i < bytes.Size(); ++i)
  536. destBytes[i] = ToInt(bytes[i]);
  537. return true;
  538. }
  539. Color XMLElement::GetColor(const String& name) const
  540. {
  541. return ToColor(GetAttribute(name));
  542. }
  543. float XMLElement::GetFloat(const String& name) const
  544. {
  545. return ToFloat(GetAttribute(name));
  546. }
  547. unsigned XMLElement::GetUInt(const String& name) const
  548. {
  549. return ToUInt(GetAttribute(name));
  550. }
  551. int XMLElement::GetInt(const String& name) const
  552. {
  553. return ToInt(GetAttribute(name));
  554. }
  555. IntRect XMLElement::GetIntRect(const String& name) const
  556. {
  557. return ToIntRect(GetAttribute(name));
  558. }
  559. IntVector2 XMLElement::GetIntVector2(const String& name) const
  560. {
  561. return ToIntVector2(GetAttribute(name));
  562. }
  563. Quaternion XMLElement::GetQuaternion(const String& name) const
  564. {
  565. return ToQuaternion(GetAttribute(name));
  566. }
  567. Rect XMLElement::GetRect(const String& name) const
  568. {
  569. return ToRect(GetAttribute(name));
  570. }
  571. Variant XMLElement::GetVariant() const
  572. {
  573. VariantType type = Variant::GetTypeFromName(GetAttribute("type"));
  574. return GetVariantValue(type);
  575. }
  576. Variant XMLElement::GetVariantValue(VariantType type) const
  577. {
  578. Variant ret;
  579. if (type == VAR_RESOURCEREF)
  580. ret = GetResourceRef();
  581. else if (type == VAR_RESOURCEREFLIST)
  582. ret = GetResourceRefList();
  583. else if (type == VAR_VARIANTVECTOR)
  584. ret = GetVariantVector();
  585. else if (type == VAR_VARIANTMAP)
  586. ret = GetVariantMap();
  587. else
  588. ret.FromString(type, GetAttributeCString("value"));
  589. return ret;
  590. }
  591. ResourceRef XMLElement::GetResourceRef() const
  592. {
  593. ResourceRef ret;
  594. Vector<String> values = GetAttribute("value").Split(';');
  595. if (values.Size() == 2)
  596. {
  597. ret.type_ = values[0];
  598. ret.name_ = values[1];
  599. }
  600. return ret;
  601. }
  602. ResourceRefList XMLElement::GetResourceRefList() const
  603. {
  604. ResourceRefList ret;
  605. Vector<String> values = GetAttribute("value").Split(';');
  606. if (values.Size() >= 1)
  607. {
  608. ret.type_ = values[0];
  609. ret.names_.Resize(values.Size() - 1);
  610. for (unsigned i = 1; i < values.Size(); ++i)
  611. ret.names_[i - 1] = values[i];
  612. }
  613. return ret;
  614. }
  615. VariantVector XMLElement::GetVariantVector() const
  616. {
  617. VariantVector ret;
  618. XMLElement variantElem = GetChild("variant");
  619. while (variantElem)
  620. {
  621. ret.Push(variantElem.GetVariant());
  622. variantElem = variantElem.GetNext("variant");
  623. }
  624. return ret;
  625. }
  626. VariantMap XMLElement::GetVariantMap() const
  627. {
  628. VariantMap ret;
  629. XMLElement variantElem = GetChild("variant");
  630. while (variantElem)
  631. {
  632. ShortStringHash key(variantElem.GetInt("hash"));
  633. ret[key] = variantElem.GetVariant();
  634. variantElem = variantElem.GetNext("variant");
  635. }
  636. return ret;
  637. }
  638. Vector2 XMLElement::GetVector2(const String& name) const
  639. {
  640. return ToVector2(GetAttribute(name));
  641. }
  642. Vector3 XMLElement::GetVector3(const String& name) const
  643. {
  644. return ToVector3(GetAttribute(name));
  645. }
  646. Vector4 XMLElement::GetVector4(const String& name) const
  647. {
  648. return ToVector4(GetAttribute(name));
  649. }
  650. Vector4 XMLElement::GetVector(const String& name) const
  651. {
  652. return ToVector4(GetAttribute(name), true);
  653. }
  654. Variant XMLElement::GetVectorVariant(const String& name) const
  655. {
  656. return ToVectorVariant(GetAttribute(name));
  657. }
  658. XMLFile* XMLElement::GetFile() const
  659. {
  660. return file_;
  661. }
  662. XMLElement XMLElement::NextResult() const
  663. {
  664. if (!xpathResultSet_ || !xpathNode_)
  665. return XMLElement();
  666. return xpathResultSet_->operator [](++xpathResultIndex_);
  667. }
  668. XPathResultSet::XPathResultSet() :
  669. resultSet_(0)
  670. {
  671. }
  672. XPathResultSet::XPathResultSet(XMLFile* file, pugi::xpath_node_set* resultSet) :
  673. file_(file),
  674. resultSet_(resultSet ? new pugi::xpath_node_set(resultSet->begin(), resultSet->end()) : 0)
  675. {
  676. // Sort the node set in forward document order
  677. if (resultSet_)
  678. resultSet_->sort();
  679. }
  680. XPathResultSet::XPathResultSet(const XPathResultSet& rhs) :
  681. file_(rhs.file_),
  682. resultSet_(rhs.resultSet_ ? new pugi::xpath_node_set(rhs.resultSet_->begin(), rhs.resultSet_->end()) : 0)
  683. {
  684. }
  685. XPathResultSet::~XPathResultSet()
  686. {
  687. delete resultSet_;
  688. resultSet_ = 0;
  689. }
  690. XPathResultSet& XPathResultSet::operator = (const XPathResultSet& rhs)
  691. {
  692. file_ = rhs.file_;
  693. resultSet_ = rhs.resultSet_ ? new pugi::xpath_node_set(rhs.resultSet_->begin(), rhs.resultSet_->end()) : 0;
  694. return *this;
  695. }
  696. XMLElement XPathResultSet::operator[](unsigned index) const
  697. {
  698. if (!resultSet_)
  699. LOGERROR(ToString("Could not return result at index: %u. Most probably this is caused by the XPathResultSet not being stored in a lhs variable.", index));
  700. return resultSet_ && index < Size() ? XMLElement(file_, this, &resultSet_->operator [](index), index) : XMLElement();
  701. }
  702. XMLElement XPathResultSet::FirstResult()
  703. {
  704. return operator [](0);
  705. }
  706. unsigned XPathResultSet::Size() const
  707. {
  708. return resultSet_ ? resultSet_->size() : 0;
  709. }
  710. bool XPathResultSet::Empty() const
  711. {
  712. return resultSet_ ? resultSet_->empty() : true;
  713. }
  714. XPathQuery::XPathQuery() :
  715. query_(0),
  716. variables_(0)
  717. {
  718. }
  719. XPathQuery::XPathQuery(const String& queryString, const String& variableString) :
  720. query_(0),
  721. variables_(0)
  722. {
  723. SetQuery(queryString, variableString);
  724. }
  725. XPathQuery::~XPathQuery()
  726. {
  727. delete variables_;
  728. variables_ = 0;
  729. delete query_;
  730. query_ = 0;
  731. }
  732. void XPathQuery::Bind()
  733. {
  734. // Delete previous query object and create a new one binding it with variable set
  735. delete query_;
  736. query_ = new pugi::xpath_query(queryString_.CString(), variables_);
  737. }
  738. bool XPathQuery::SetVariable(const String& name, bool value)
  739. {
  740. if (!variables_)
  741. variables_ = new pugi::xpath_variable_set();
  742. return variables_->set(name.CString(), value);
  743. }
  744. bool XPathQuery::SetVariable(const String& name, float value)
  745. {
  746. if (!variables_)
  747. variables_ = new pugi::xpath_variable_set();
  748. return variables_->set(name.CString(), value);
  749. }
  750. bool XPathQuery::SetVariable(const String& name, const String& value)
  751. {
  752. return SetVariable(name.CString(), value.CString());
  753. }
  754. bool XPathQuery::SetVariable(const char* name, const char* value)
  755. {
  756. if (!variables_)
  757. variables_ = new pugi::xpath_variable_set();
  758. return variables_->set(name, value);
  759. }
  760. bool XPathQuery::SetVariable(const String& name, const XPathResultSet& value)
  761. {
  762. if (!variables_)
  763. variables_ = new pugi::xpath_variable_set();
  764. pugi::xpath_node_set* nodeSet = value.GetXPathNodeSet();
  765. if (!nodeSet)
  766. return false;
  767. return variables_->set(name.CString(), *nodeSet);
  768. }
  769. bool XPathQuery::SetQuery(const String& queryString, const String& variableString, bool bind)
  770. {
  771. if (!variableString.Empty())
  772. {
  773. Clear();
  774. variables_ = new pugi::xpath_variable_set();
  775. // Parse the variable string having format "name1:type1,name2:type2,..." where type is one of "Bool", "Float", "String", "ResultSet"
  776. Vector<String> vars = variableString.Split(',');
  777. for (Vector<String>::ConstIterator i = vars.Begin(); i != vars.End(); ++i)
  778. {
  779. Vector<String> tokens = i->Trimmed().Split(':');
  780. if (tokens.Size() != 2)
  781. continue;
  782. pugi::xpath_value_type type;
  783. if (tokens[1] == "Bool")
  784. type = pugi::xpath_type_boolean;
  785. else if (tokens[1] == "Float")
  786. type = pugi::xpath_type_number;
  787. else if (tokens[1] == "String")
  788. type = pugi::xpath_type_string;
  789. else if (tokens[1] == "ResultSet")
  790. type = pugi::xpath_type_node_set;
  791. else
  792. return false;
  793. if (!variables_->add(tokens[0].CString(), type))
  794. return false;
  795. }
  796. }
  797. queryString_ = queryString;
  798. if (bind)
  799. Bind();
  800. return true;
  801. }
  802. void XPathQuery::Clear()
  803. {
  804. queryString_.Clear();
  805. delete variables_;
  806. variables_ = 0;
  807. delete query_;
  808. query_ = 0;
  809. }
  810. bool XPathQuery::EvaluateToBool(XMLElement element) const
  811. {
  812. if (!query_ || ((!element.GetFile() || !element.GetNode()) && !element.GetXPathNode()))
  813. return false;
  814. const pugi::xml_node& node = element.GetXPathNode() ? element.GetXPathNode()->node(): pugi::xml_node(element.GetNode());
  815. return query_->evaluate_boolean(node);
  816. }
  817. float XPathQuery::EvaluateToFloat(XMLElement element) const
  818. {
  819. if (!query_ || ((!element.GetFile() || !element.GetNode()) && !element.GetXPathNode()))
  820. return 0.0f;
  821. const pugi::xml_node& node = element.GetXPathNode() ? element.GetXPathNode()->node(): pugi::xml_node(element.GetNode());
  822. return (float)query_->evaluate_number(node);
  823. }
  824. String XPathQuery::EvaluateToString(XMLElement element) const
  825. {
  826. if (!query_ || ((!element.GetFile() || !element.GetNode()) && !element.GetXPathNode()))
  827. return String::EMPTY;
  828. const pugi::xml_node& node = element.GetXPathNode() ? element.GetXPathNode()->node(): pugi::xml_node(element.GetNode());
  829. String result;
  830. result.Reserve(query_->evaluate_string(0, 0, node)); // First call get the size
  831. query_->evaluate_string(const_cast<pugi::char_t*>(result.CString()), result.Capacity(), node); // Second call get the actual string
  832. return result;
  833. }
  834. XPathResultSet XPathQuery::Evaluate(XMLElement element) const
  835. {
  836. if (!query_ || ((!element.GetFile() || !element.GetNode()) && !element.GetXPathNode()))
  837. return XPathResultSet();
  838. const pugi::xml_node& node = element.GetXPathNode() ? element.GetXPathNode()->node(): pugi::xml_node(element.GetNode());
  839. pugi::xpath_node_set result = query_->evaluate_node_set(node);
  840. return XPathResultSet(element.GetFile(), &result);
  841. }
  842. }