3
0

XmlUtils.cpp 11 KB

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