XMLElement.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2012 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "Context.h"
  25. #include "ResourceCache.h"
  26. #include "StringUtils.h"
  27. #include "XMLFile.h"
  28. #include <pugixml.hpp>
  29. #include "DebugNew.h"
  30. XMLElement::XMLElement() :
  31. node_(0)
  32. {
  33. }
  34. XMLElement::XMLElement(XMLFile* file, pugi::xml_node_struct* node) :
  35. file_(file),
  36. node_(node)
  37. {
  38. }
  39. XMLElement::XMLElement(const XMLElement& rhs) :
  40. file_(rhs.file_),
  41. node_(rhs.file_ ? rhs.node_ : 0)
  42. {
  43. }
  44. XMLElement::~XMLElement()
  45. {
  46. }
  47. XMLElement XMLElement::CreateChild(const String& name)
  48. {
  49. return CreateChild(name.CString());
  50. }
  51. XMLElement XMLElement::CreateChild(const char* name)
  52. {
  53. if (!file_ || !node_)
  54. return XMLElement();
  55. pugi::xml_node node(node_);
  56. pugi::xml_node child = node.append_child(name);
  57. return XMLElement(file_, child.internal_object());
  58. }
  59. bool XMLElement::RemoveChild(const XMLElement& element)
  60. {
  61. if (!file_ || !node_ || element.node_)
  62. return false;
  63. pugi::xml_node node(node_);
  64. pugi::xml_node child(element.node_);
  65. return node.remove_child(child);
  66. }
  67. bool XMLElement::RemoveChild(const String& name)
  68. {
  69. return RemoveChild(name.CString());
  70. }
  71. bool XMLElement::RemoveChild(const char* name)
  72. {
  73. if (!file_ || !node_)
  74. return false;
  75. pugi::xml_node node(node_);
  76. return node.remove_child(name);
  77. }
  78. bool XMLElement::RemoveChildren(const String& name)
  79. {
  80. return RemoveChildren(name.CString());
  81. }
  82. bool XMLElement::RemoveChildren(const char* name)
  83. {
  84. if (!file_ || !node_)
  85. return false;
  86. pugi::xml_node node(node_);
  87. if (!String::CStringLength(name))
  88. {
  89. for (;;)
  90. {
  91. pugi::xml_node child = node.last_child();
  92. if (child.empty())
  93. break;
  94. node.remove_child(child);
  95. }
  96. }
  97. else
  98. {
  99. for (;;)
  100. {
  101. pugi::xml_node child = node.child(name);
  102. if (child.empty())
  103. break;
  104. node.remove_child(child);
  105. }
  106. }
  107. return true;
  108. }
  109. bool XMLElement::SetAttribute(const String& name, const String& value)
  110. {
  111. return SetAttribute(name.CString(), value.CString());
  112. }
  113. bool XMLElement::SetAttribute(const char* name, const char* value)
  114. {
  115. if (!file_ || !node_)
  116. return false;
  117. pugi::xml_node node(node_);
  118. pugi::xml_attribute attr = node.attribute(name);
  119. if (attr.empty())
  120. attr = node.append_attribute(name);
  121. attr.set_value(value);
  122. return true;
  123. }
  124. bool XMLElement::SetBool(const String& name, bool value)
  125. {
  126. return SetAttribute(name, String(value));
  127. }
  128. bool XMLElement::SetBoundingBox(const BoundingBox& value)
  129. {
  130. if (!SetVector3("min", value.min_))
  131. return false;
  132. return SetVector3("max", value.max_);
  133. }
  134. bool XMLElement::SetBuffer(const String& name, const void* data, unsigned size)
  135. {
  136. String dataStr;
  137. const unsigned char* bytes = (const unsigned char*)data;
  138. for (unsigned i = 0; i < size; ++i)
  139. dataStr += String((unsigned)bytes[i]) + " ";
  140. return SetAttribute(name, dataStr);
  141. }
  142. bool XMLElement::SetBuffer(const String& name, const PODVector<unsigned char>& value)
  143. {
  144. if (!value.Size())
  145. return SetAttribute(name, String());
  146. else
  147. return SetBuffer(name, &value[0], value.Size());
  148. }
  149. bool XMLElement::SetColor(const String& name, const Color& value)
  150. {
  151. return SetAttribute(name, value.ToString());
  152. }
  153. bool XMLElement::SetFloat(const String& name, float value)
  154. {
  155. return SetAttribute(name, String(value));
  156. }
  157. bool XMLElement::SetInt(const String& name, int value)
  158. {
  159. return SetAttribute(name, String(value));
  160. }
  161. bool XMLElement::SetIntRect(const String& name, const IntRect& value)
  162. {
  163. return SetAttribute(name, value.ToString());
  164. }
  165. bool XMLElement::SetIntVector2(const String& name, const IntVector2& value)
  166. {
  167. return SetAttribute(name, value.ToString());
  168. }
  169. bool XMLElement::SetRect(const String& name, const Rect& value)
  170. {
  171. return SetAttribute(name, value.ToString());
  172. }
  173. bool XMLElement::SetQuaternion(const String& name, const Quaternion& value)
  174. {
  175. return XMLElement::SetAttribute(name, value.ToString());
  176. }
  177. bool XMLElement::SetString(const String& name, const String& value)
  178. {
  179. return SetAttribute(name, value);
  180. }
  181. bool XMLElement::SetVariant(const Variant& value)
  182. {
  183. if (!SetAttribute("type", value.GetTypeName()))
  184. return false;
  185. return SetVariantValue(value);
  186. }
  187. bool XMLElement::SetVariantValue(const Variant& value)
  188. {
  189. switch (value.GetType())
  190. {
  191. case VAR_RESOURCEREF:
  192. return SetResourceRef(value.GetResourceRef());
  193. case VAR_RESOURCEREFLIST:
  194. return SetResourceRefList(value.GetResourceRefList());
  195. case VAR_VARIANTVECTOR:
  196. return SetVariantVector(value.GetVariantVector());
  197. case VAR_VARIANTMAP:
  198. return SetVariantMap(value.GetVariantMap());
  199. default:
  200. return SetAttribute("value", value.ToString().CString());
  201. }
  202. }
  203. bool XMLElement::SetResourceRef(const ResourceRef& value)
  204. {
  205. if (!file_ || !node_)
  206. return false;
  207. // Need the context & resource cache to query for reverse hash mappings
  208. Context* context = file_->GetContext();
  209. ResourceCache* cache = file_->GetSubsystem<ResourceCache>();
  210. SetAttribute("value", String(context->GetTypeName(value.type_)) + ";" + cache->GetResourceName(value.id_));
  211. return true;
  212. }
  213. bool XMLElement::SetResourceRefList(const ResourceRefList& value)
  214. {
  215. if (!file_ || !node_)
  216. return false;
  217. // Need the context & resource cache to query for reverse hash mappings
  218. Context* context = file_->GetContext();
  219. ResourceCache* cache = file_->GetSubsystem<ResourceCache>();
  220. String str(context->GetTypeName(value.type_));
  221. for (unsigned i = 0; i < value.ids_.Size(); ++i)
  222. {
  223. str += ";";
  224. str += cache->GetResourceName(value.ids_[i]);
  225. }
  226. SetAttribute("value", str.CString());
  227. return true;
  228. }
  229. bool XMLElement::SetVariantVector(const VariantVector& value)
  230. {
  231. // Must remove all existing variant child elements (if they exist) to not cause confusion
  232. if (!RemoveChildren("variant"))
  233. return false;
  234. for (VariantVector::ConstIterator i = value.Begin(); i != value.End(); ++i)
  235. {
  236. XMLElement variantElem = CreateChild("variant");
  237. if (!variantElem)
  238. return false;
  239. variantElem.SetVariant(*i);
  240. }
  241. return true;
  242. }
  243. bool XMLElement::SetVariantMap(const VariantMap& value)
  244. {
  245. if (!RemoveChildren("variant"))
  246. return false;
  247. for (VariantMap::ConstIterator i = value.Begin(); i != value.End(); ++i)
  248. {
  249. XMLElement variantElem = CreateChild("variant");
  250. if (!variantElem)
  251. return false;
  252. variantElem.SetInt("hash", i->first_.GetValue());
  253. variantElem.SetVariant(i->second_);
  254. }
  255. return true;
  256. }
  257. bool XMLElement::SetVector2(const String& name, const Vector2& value)
  258. {
  259. return SetAttribute(name, value.ToString());
  260. }
  261. bool XMLElement::SetVector3(const String& name, const Vector3& value)
  262. {
  263. return SetAttribute(name, value.ToString());
  264. }
  265. bool XMLElement::SetVector4(const String& name, const Vector4& value)
  266. {
  267. return SetAttribute(name, value.ToString());
  268. }
  269. String XMLElement::GetName() const
  270. {
  271. if (!file_ || !node_)
  272. return String();
  273. pugi::xml_node node(node_);
  274. return String(node.name());
  275. }
  276. bool XMLElement::HasChild(const String& name) const
  277. {
  278. return HasChild(name.CString());
  279. }
  280. bool XMLElement::HasChild(const char* name) const
  281. {
  282. if (!file_ || !node_)
  283. return false;
  284. pugi::xml_node node(node_);
  285. return !node.child(name).empty();
  286. }
  287. XMLElement XMLElement::GetChild(const String& name) const
  288. {
  289. return GetChild(name.CString());
  290. }
  291. XMLElement XMLElement::GetChild(const char* name) const
  292. {
  293. if (!file_ || !node_)
  294. return XMLElement();
  295. pugi::xml_node node(node_);
  296. if (!String::CStringLength(name))
  297. return XMLElement(file_, node.first_child().internal_object());
  298. else
  299. return XMLElement(file_, node.child(name).internal_object());
  300. }
  301. XMLElement XMLElement::GetNext(const String& name) const
  302. {
  303. return GetNext(name.CString());
  304. }
  305. XMLElement XMLElement::GetNext(const char* name) const
  306. {
  307. if (!file_ || !node_)
  308. return XMLElement();
  309. pugi::xml_node node(node_);
  310. if (!String::CStringLength(name))
  311. return XMLElement(file_, node.next_sibling().internal_object());
  312. else
  313. return XMLElement(file_, node.next_sibling(name).internal_object());
  314. }
  315. XMLElement XMLElement::GetParent() const
  316. {
  317. if (!file_ || !node_)
  318. return XMLElement();
  319. pugi::xml_node node(node_);
  320. return XMLElement(file_, node.parent().internal_object());
  321. }
  322. unsigned XMLElement::GetNumAttributes() const
  323. {
  324. if (!file_ || !node_)
  325. return 0;
  326. pugi::xml_node node(node_);
  327. unsigned ret = 0;
  328. pugi::xml_attribute attr = node.first_attribute();
  329. while (!attr.empty())
  330. {
  331. ++ret;
  332. attr = attr.next_attribute();
  333. }
  334. return ret;
  335. }
  336. bool XMLElement::HasAttribute(const String& name) const
  337. {
  338. return HasAttribute(name.CString());
  339. }
  340. bool XMLElement::HasAttribute(const char* name) const
  341. {
  342. if (!file_ || !node_)
  343. return false;
  344. pugi::xml_node node(node_);
  345. return !node.attribute(name).empty();
  346. }
  347. String XMLElement::GetAttribute(const String& name) const
  348. {
  349. if (!file_ || !node_)
  350. return String();
  351. pugi::xml_node node(node_);
  352. return String(node.attribute(name.CString()).value());
  353. }
  354. const char* XMLElement::GetAttribute(const char* name) const
  355. {
  356. if (!file_ || !node_)
  357. return 0;
  358. pugi::xml_node node(node_);
  359. return node.attribute(name).value();
  360. }
  361. String XMLElement::GetAttributeLower(const String& name) const
  362. {
  363. return GetAttribute(name).ToLower();
  364. }
  365. String XMLElement::GetAttributeLower(const char* name) const
  366. {
  367. return String(GetAttribute(name)).ToLower();
  368. }
  369. String XMLElement::GetAttributeUpper(const String& name) const
  370. {
  371. return GetAttribute(name).ToUpper();
  372. }
  373. String XMLElement::GetAttributeUpper(const char* name) const
  374. {
  375. return String(GetAttribute(name)).ToUpper();
  376. }
  377. Vector<String> XMLElement::GetAttributeNames() const
  378. {
  379. if (!file_ || !node_)
  380. return Vector<String>();
  381. pugi::xml_node node(node_);
  382. Vector<String> ret;
  383. pugi::xml_attribute attr = node.first_attribute();
  384. while (!attr.empty())
  385. {
  386. ret.Push(String(attr.name()));
  387. attr = attr.next_attribute();
  388. }
  389. return ret;
  390. }
  391. bool XMLElement::GetBool(const String& name) const
  392. {
  393. return ToBool(GetAttribute(name));
  394. }
  395. BoundingBox XMLElement::GetBoundingBox() const
  396. {
  397. BoundingBox ret;
  398. ret.min_ = GetVector3("min");
  399. ret.max_ = GetVector3("max");
  400. ret.defined_ = true;
  401. return ret;
  402. }
  403. PODVector<unsigned char> XMLElement::GetBuffer(const String& name) const
  404. {
  405. PODVector<unsigned char> ret;
  406. Vector<String> bytes = GetAttribute(name).Split(' ');
  407. ret.Resize(bytes.Size());
  408. for (unsigned i = 0; i < bytes.Size(); ++i)
  409. ret[i] = ToInt(bytes[i]);
  410. return ret;
  411. }
  412. bool XMLElement::GetBuffer(const String& name, void* dest, unsigned size) const
  413. {
  414. PODVector<unsigned char> ret;
  415. Vector<String> bytes = GetAttribute(name).Split(' ');
  416. unsigned char* destBytes = (unsigned char*)dest;
  417. if (size < bytes.Size())
  418. return false;
  419. for (unsigned i = 0; i < bytes.Size(); ++i)
  420. destBytes[i] = ToInt(bytes[i]);
  421. return true;
  422. }
  423. Color XMLElement::GetColor(const String& name) const
  424. {
  425. return ToColor(GetAttribute(name));
  426. }
  427. float XMLElement::GetFloat(const String& name) const
  428. {
  429. return ToFloat(GetAttribute(name));
  430. }
  431. int XMLElement::GetInt(const String& name) const
  432. {
  433. return ToInt(GetAttribute(name));
  434. }
  435. IntRect XMLElement::GetIntRect(const String& name) const
  436. {
  437. return ToIntRect(GetAttribute(name));
  438. }
  439. IntVector2 XMLElement::GetIntVector2(const String& name) const
  440. {
  441. return ToIntVector2(GetAttribute(name));
  442. }
  443. Quaternion XMLElement::GetQuaternion(const String& name) const
  444. {
  445. return ToQuaternion(GetAttribute(name));
  446. }
  447. Rect XMLElement::GetRect(const String& name) const
  448. {
  449. return ToRect(GetAttribute(name));
  450. }
  451. Variant XMLElement::GetVariant() const
  452. {
  453. VariantType type = Variant::GetTypeFromName(GetAttribute("type"));
  454. return GetVariantValue(type);
  455. }
  456. Variant XMLElement::GetVariantValue(VariantType type) const
  457. {
  458. Variant ret;
  459. if (type == VAR_RESOURCEREF)
  460. ret = GetResourceRef();
  461. else if (type == VAR_RESOURCEREFLIST)
  462. ret = GetResourceRefList();
  463. else if (type == VAR_VARIANTVECTOR)
  464. ret = GetVariantVector();
  465. else if (type == VAR_VARIANTMAP)
  466. ret = GetVariantMap();
  467. else
  468. ret.FromString(type, GetAttribute("value"));
  469. return ret;
  470. }
  471. ResourceRef XMLElement::GetResourceRef() const
  472. {
  473. ResourceRef ret;
  474. Vector<String> values = String::Split(GetAttribute("value"), ';');
  475. if (values.Size() == 2)
  476. {
  477. ret.type_ = ShortStringHash(values[0]);
  478. ret.id_ = StringHash(values[1]);
  479. // Whenever we encounter a resource name read from a ResourceRef XML element, store the reverse mapping to
  480. // ResourceCache if possible. We will probably use the hash to request a resource shortly afterward
  481. if (file_)
  482. file_->GetSubsystem<ResourceCache>()->StoreNameHash(values[1]);
  483. }
  484. return ret;
  485. }
  486. ResourceRefList XMLElement::GetResourceRefList() const
  487. {
  488. ResourceRefList ret;
  489. Vector<String> values = String::Split(GetAttribute("value"), ';');
  490. if (values.Size() >= 1)
  491. {
  492. // Whenever we encounter resource names read from a ResourceRefList XML element, store the reverse mapping to
  493. // ResourceCache if possible. We will probably use the hashes to request resources shortly afterward
  494. ResourceCache* cache = file_ ? file_->GetSubsystem<ResourceCache>() : 0;
  495. ret.type_ = ShortStringHash(values[0]);
  496. ret.ids_.Resize(values.Size() - 1);
  497. for (unsigned i = 1; i < values.Size(); ++i)
  498. {
  499. ret.ids_[i - 1] = StringHash(values[i]);
  500. if (cache)
  501. cache->StoreNameHash(values[i]);
  502. }
  503. }
  504. return ret;
  505. }
  506. VariantVector XMLElement::GetVariantVector() const
  507. {
  508. VariantVector ret;
  509. XMLElement variantElem = GetChild("variant");
  510. while (variantElem)
  511. {
  512. ret.Push(variantElem.GetVariant());
  513. variantElem = variantElem.GetNext("variant");
  514. }
  515. return ret;
  516. }
  517. VariantMap XMLElement::GetVariantMap() const
  518. {
  519. VariantMap ret;
  520. XMLElement variantElem = GetChild("variant");
  521. while (variantElem)
  522. {
  523. ShortStringHash key(variantElem.GetInt("hash"));
  524. ret[key] = variantElem.GetVariant();
  525. variantElem = variantElem.GetNext("variant");
  526. }
  527. return ret;
  528. }
  529. Vector2 XMLElement::GetVector2(const String& name) const
  530. {
  531. return ToVector2(GetAttribute(name));
  532. }
  533. Vector3 XMLElement::GetVector3(const String& name) const
  534. {
  535. return ToVector3(GetAttribute(name));
  536. }
  537. Vector4 XMLElement::GetVector4(const String& name) const
  538. {
  539. return ToVector4(GetAttribute(name));
  540. }
  541. Vector4 XMLElement::GetVector(const String& name) const
  542. {
  543. return ToVector4(GetAttribute(name), true);
  544. }
  545. XMLFile* XMLElement::GetFile() const
  546. {
  547. return file_;
  548. }