XmlUtils.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "CrySystem_precompiled.h"
  9. #include <IXml.h>
  10. #include "xml.h"
  11. #include "XmlUtils.h"
  12. #include "../SimpleStringPool.h"
  13. #include "SerializeXMLReader.h"
  14. #include "SerializeXMLWriter.h"
  15. #include <AzCore/Serialization/Locale.h>
  16. #include "XMLBinaryReader.h"
  17. //////////////////////////////////////////////////////////////////////////
  18. #ifdef CRY_COLLECT_XML_NODE_STATS
  19. SXmlNodeStats* g_pCXmlNode_Stats = 0;
  20. #endif
  21. //////////////////////////////////////////////////////////////////////////
  22. CXmlUtils::CXmlUtils(ISystem* pSystem)
  23. {
  24. m_pSystem = pSystem;
  25. #ifdef CRY_COLLECT_XML_NODE_STATS
  26. g_pCXmlNode_Stats = new SXmlNodeStats();
  27. #endif
  28. }
  29. //////////////////////////////////////////////////////////////////////////
  30. CXmlUtils::~CXmlUtils()
  31. {
  32. #ifdef CRY_COLLECT_XML_NODE_STATS
  33. delete g_pCXmlNode_Stats;
  34. #endif
  35. }
  36. //////////////////////////////////////////////////////////////////////////
  37. IXmlParser* CXmlUtils::CreateXmlParser()
  38. {
  39. const bool bReuseStrings = false; //TODO: do we ever want to reuse strings here?
  40. return new XmlParser(bReuseStrings);
  41. }
  42. //////////////////////////////////////////////////////////////////////////
  43. XmlNodeRef CXmlUtils::LoadXmlFromFile(const char* sFilename, bool bReuseStrings)
  44. {
  45. // when saving and loading data files to disk, use the invariant locale
  46. AZ::Locale::ScopedSerializationLocale scopedLocale;
  47. // XmlParser is supposed to log warnings and errors (if any),
  48. // so we don't need to call parser.getErrorString(),
  49. // CryLog() etc here.
  50. XmlParser parser(bReuseStrings);
  51. return parser.ParseFile(sFilename, true);
  52. }
  53. //////////////////////////////////////////////////////////////////////////
  54. XmlNodeRef CXmlUtils::LoadXmlFromBuffer(const char* buffer, size_t size, bool bReuseStrings, bool bSuppressWarnings)
  55. {
  56. // when saving and loading data files to disk, use the invariant locale
  57. AZ::Locale::ScopedSerializationLocale scopedLocale;
  58. XmlParser parser(bReuseStrings);
  59. XmlNodeRef node = parser.ParseBuffer(buffer, static_cast<int>(size), true, bSuppressWarnings);
  60. return node;
  61. }
  62. //////////////////////////////////////////////////////////////////////////
  63. class CXmlSerializer final : public IXmlSerializer
  64. {
  65. public:
  66. CXmlSerializer() = default;
  67. ~CXmlSerializer()
  68. {
  69. ClearAll();
  70. }
  71. void ClearAll()
  72. {
  73. SAFE_DELETE(m_pReaderSer);
  74. SAFE_DELETE(m_pReaderImpl);
  75. SAFE_DELETE(m_pWriterSer);
  76. SAFE_DELETE(m_pWriterImpl);
  77. }
  78. //////////////////////////////////////////////////////////////////////////
  79. void AddRef() override
  80. {
  81. ++m_nRefCount;
  82. }
  83. void Release() override
  84. {
  85. if (--m_nRefCount <= 0)
  86. {
  87. delete this;
  88. }
  89. }
  90. ISerialize* GetWriter(XmlNodeRef& node) override
  91. {
  92. ClearAll();
  93. m_pWriterImpl = new CSerializeXMLWriterImpl(node);
  94. m_pWriterSer = new CSimpleSerializeWithDefaults<CSerializeXMLWriterImpl>(*m_pWriterImpl);
  95. return m_pWriterSer;
  96. }
  97. ISerialize* GetReader(XmlNodeRef& node) override
  98. {
  99. ClearAll();
  100. m_pReaderImpl = new CSerializeXMLReaderImpl(node);
  101. m_pReaderSer = new CSimpleSerializeWithDefaults<CSerializeXMLReaderImpl>(*m_pReaderImpl);
  102. return m_pReaderSer;
  103. }
  104. //////////////////////////////////////////////////////////////////////////
  105. private:
  106. int m_nRefCount = 0;
  107. CSerializeXMLReaderImpl* m_pReaderImpl = nullptr;
  108. CSimpleSerializeWithDefaults<CSerializeXMLReaderImpl>* m_pReaderSer = nullptr;
  109. CSerializeXMLWriterImpl* m_pWriterImpl = nullptr;
  110. CSimpleSerializeWithDefaults<CSerializeXMLWriterImpl>* m_pWriterSer = nullptr;
  111. };
  112. //////////////////////////////////////////////////////////////////////////
  113. IXmlSerializer* CXmlUtils::CreateXmlSerializer()
  114. {
  115. return new CXmlSerializer;
  116. }
  117. //////////////////////////////////////////////////////////////////////////
  118. class CXmlBinaryDataWriterFile final : public XMLBinary::IDataWriter
  119. {
  120. public:
  121. CXmlBinaryDataWriterFile(const char* file)
  122. {
  123. m_fileHandle = gEnv->pCryPak->FOpen(file, "wb");
  124. }
  125. ~CXmlBinaryDataWriterFile()
  126. {
  127. if (m_fileHandle != AZ::IO::InvalidHandle)
  128. {
  129. gEnv->pCryPak->FClose(m_fileHandle);
  130. }
  131. };
  132. virtual bool IsOk()
  133. {
  134. return m_fileHandle != AZ::IO::InvalidHandle;
  135. }
  136. ;
  137. void Write(const void* pData, size_t size) override
  138. {
  139. if (m_fileHandle != AZ::IO::InvalidHandle)
  140. {
  141. gEnv->pCryPak->FWrite(pData, size, m_fileHandle);
  142. }
  143. }
  144. private:
  145. AZ::IO::HandleType m_fileHandle;
  146. };
  147. //////////////////////////////////////////////////////////////////////////
  148. class CXmlTableReader final : public IXmlTableReader
  149. {
  150. public:
  151. CXmlTableReader();
  152. ~CXmlTableReader() override;
  153. void Release() override;
  154. bool Begin(XmlNodeRef rootNode) override;
  155. int GetEstimatedRowCount() override;
  156. bool ReadRow(int& rowIndex) override;
  157. bool ReadCell(int& columnIndex, const char*& pContent, size_t& contentSize) override;
  158. private:
  159. bool m_bExcel;
  160. XmlNodeRef m_tableNode;
  161. XmlNodeRef m_rowNode;
  162. int m_rowNodeIndex;
  163. int m_row;
  164. int m_columnNodeIndex; // used if m_bExcel == true
  165. int m_column;
  166. size_t m_rowTextSize; // used if m_bExcel == false
  167. size_t m_rowTextPos; // used if m_bExcel == false
  168. };
  169. //////////////////////////////////////////////////////////////////////////
  170. CXmlTableReader::CXmlTableReader()
  171. {
  172. }
  173. //////////////////////////////////////////////////////////////////////////
  174. CXmlTableReader::~CXmlTableReader()
  175. {
  176. }
  177. //////////////////////////////////////////////////////////////////////////
  178. void CXmlTableReader::Release()
  179. {
  180. delete this;
  181. }
  182. //////////////////////////////////////////////////////////////////////////
  183. bool CXmlTableReader::Begin(XmlNodeRef rootNode)
  184. {
  185. m_tableNode = nullptr;
  186. if (!rootNode)
  187. {
  188. return false;
  189. }
  190. XmlNodeRef worksheetNode = rootNode->findChild("Worksheet");
  191. if (worksheetNode)
  192. {
  193. m_bExcel = true;
  194. m_tableNode = worksheetNode->findChild("Table");
  195. }
  196. else
  197. {
  198. m_bExcel = false;
  199. m_tableNode = rootNode->findChild("Table");
  200. }
  201. m_rowNode = nullptr;
  202. m_rowNodeIndex = -1;
  203. m_row = -1;
  204. return (m_tableNode != nullptr);
  205. }
  206. //////////////////////////////////////////////////////////////////////////
  207. int CXmlTableReader::GetEstimatedRowCount()
  208. {
  209. if (!m_tableNode)
  210. {
  211. return -1;
  212. }
  213. return m_tableNode->getChildCount();
  214. }
  215. //////////////////////////////////////////////////////////////////////////
  216. bool CXmlTableReader::ReadRow(int& rowIndex)
  217. {
  218. if (!m_tableNode)
  219. {
  220. return false;
  221. }
  222. m_columnNodeIndex = -1;
  223. m_column = -1;
  224. const int rowNodeCount = m_tableNode->getChildCount();
  225. if (m_bExcel)
  226. {
  227. for (;; )
  228. {
  229. if (++m_rowNodeIndex >= rowNodeCount)
  230. {
  231. m_rowNodeIndex = rowNodeCount;
  232. return false;
  233. }
  234. m_rowNode = m_tableNode->getChild(m_rowNodeIndex);
  235. if (!m_rowNode)
  236. {
  237. m_rowNodeIndex = rowNodeCount;
  238. return false;
  239. }
  240. if (!m_rowNode->isTag("Row"))
  241. {
  242. m_rowNode = nullptr;
  243. continue;
  244. }
  245. ++m_row;
  246. int index = 0;
  247. if (m_rowNode->getAttr("ss:Index", index))
  248. {
  249. --index; // one-based -> zero-based
  250. if (index < m_row)
  251. {
  252. m_rowNodeIndex = rowNodeCount;
  253. m_rowNode = nullptr;
  254. return false;
  255. }
  256. m_row = index;
  257. }
  258. rowIndex = m_row;
  259. return true;
  260. }
  261. }
  262. {
  263. m_rowTextSize = 0;
  264. m_rowTextPos = 0;
  265. if (++m_rowNodeIndex >= rowNodeCount)
  266. {
  267. m_rowNodeIndex = rowNodeCount;
  268. return false;
  269. }
  270. m_rowNode = m_tableNode->getChild(m_rowNodeIndex);
  271. if (!m_rowNode)
  272. {
  273. m_rowNodeIndex = rowNodeCount;
  274. return false;
  275. }
  276. const char* const pContent = m_rowNode->getContent();
  277. if (pContent)
  278. {
  279. m_rowTextSize = strlen(pContent);
  280. }
  281. m_row = m_rowNodeIndex;
  282. rowIndex = m_rowNodeIndex;
  283. return true;
  284. }
  285. }
  286. //////////////////////////////////////////////////////////////////////////
  287. bool CXmlTableReader::ReadCell(int& columnIndex, const char*& pContent, size_t& contentSize)
  288. {
  289. pContent = nullptr;
  290. contentSize = 0;
  291. if (!m_tableNode)
  292. {
  293. return false;
  294. }
  295. if (!m_rowNode)
  296. {
  297. return false;
  298. }
  299. if (m_bExcel)
  300. {
  301. const int columnNodeCount = m_rowNode->getChildCount();
  302. for (;; )
  303. {
  304. if (++m_columnNodeIndex >= columnNodeCount)
  305. {
  306. m_columnNodeIndex = columnNodeCount;
  307. return false;
  308. }
  309. XmlNodeRef columnNode = m_rowNode->getChild(m_columnNodeIndex);
  310. if (!columnNode)
  311. {
  312. m_columnNodeIndex = columnNodeCount;
  313. return false;
  314. }
  315. if (!columnNode->isTag("Cell"))
  316. {
  317. continue;
  318. }
  319. ++m_column;
  320. int index = 0;
  321. if (columnNode->getAttr("ss:Index", index))
  322. {
  323. --index; // one-based -> zero-based
  324. if (index < m_column)
  325. {
  326. m_columnNodeIndex = columnNodeCount;
  327. return false;
  328. }
  329. m_column = index;
  330. }
  331. columnIndex = m_column;
  332. XmlNodeRef dataNode = columnNode->findChild("Data");
  333. if (dataNode)
  334. {
  335. pContent = dataNode->getContent();
  336. if (pContent)
  337. {
  338. contentSize = strlen(pContent);
  339. }
  340. }
  341. return true;
  342. }
  343. }
  344. {
  345. if (m_rowTextPos >= m_rowTextSize)
  346. {
  347. return false;
  348. }
  349. const char* const pRowContent = m_rowNode->getContent();
  350. if (!pRowContent)
  351. {
  352. m_rowTextPos = m_rowTextSize;
  353. return false;
  354. }
  355. pContent = &pRowContent[m_rowTextPos];
  356. columnIndex = ++m_column;
  357. for (;; )
  358. {
  359. char c = pRowContent[m_rowTextPos++];
  360. if ((c == '\n') || (c == '\0'))
  361. {
  362. return true;
  363. }
  364. if (c == '\r')
  365. {
  366. // ignore all '\r' chars
  367. for (;; )
  368. {
  369. c = pRowContent[m_rowTextPos++];
  370. if ((c == '\n') || (c == '\0'))
  371. {
  372. return true;
  373. }
  374. if (c != '\r')
  375. {
  376. // broken data. '\r' expected to be followed by '\n' or '\0'.
  377. contentSize = 0;
  378. m_rowTextPos = m_rowTextSize;
  379. return false;
  380. }
  381. }
  382. }
  383. ++contentSize;
  384. }
  385. }
  386. }
  387. //////////////////////////////////////////////////////////////////////////
  388. IXmlTableReader* CXmlUtils::CreateXmlTableReader()
  389. {
  390. return new CXmlTableReader;
  391. }