XMLElement.cpp 32 KB

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