XMLBinaryReader.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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 <platform.h>
  9. #include "XMLBinaryReader.h"
  10. #include "XMLBinaryNode.h"
  11. #include "CryPath.h"
  12. XMLBinary::XMLBinaryReader::XMLBinaryReader()
  13. {
  14. m_errorDescription[0] = 0;
  15. }
  16. XMLBinary::XMLBinaryReader::~XMLBinaryReader()
  17. {
  18. }
  19. const char* XMLBinary::XMLBinaryReader::GetErrorDescription() const
  20. {
  21. return &m_errorDescription[0];
  22. }
  23. void XMLBinary::XMLBinaryReader::SetErrorDescription(const char* text)
  24. {
  25. azstrcpy(m_errorDescription, AZ_ARRAY_SIZE(m_errorDescription), text);
  26. }
  27. XmlNodeRef XMLBinary::XMLBinaryReader::LoadFromFile(
  28. const char* filename,
  29. XMLBinary::XMLBinaryReader::EResult& result)
  30. {
  31. m_errorDescription[0] = 0;
  32. result = eResult_Error;
  33. CCryFile xmlFile;
  34. if (!xmlFile.Open(filename, "rb"))
  35. {
  36. SetErrorDescription("Can't open file.");
  37. return 0;
  38. }
  39. const size_t fileSize = xmlFile.GetLength();
  40. if (fileSize < sizeof(BinaryFileHeader))
  41. {
  42. result = eResult_NotBinXml;
  43. SetErrorDescription("File is not a binary XML file (file size is too small).");
  44. return 0;
  45. }
  46. // Read in the entire file - this buffer will not be deallocated immediately, since the nodes
  47. // will contain pointers directly into it. It will be deleted once the reference count on the
  48. // CBinaryXmlData object reaches 0 again.
  49. char* const pFileContents = new char[fileSize];
  50. if (!pFileContents)
  51. {
  52. SetErrorDescription("Can't allocate memory for binary XML file contents.");
  53. return 0;
  54. }
  55. if (xmlFile.ReadRaw(pFileContents, fileSize) != fileSize)
  56. {
  57. delete [] pFileContents;
  58. SetErrorDescription("Failed to read binary XML file, the file is corrupt.");
  59. return 0;
  60. }
  61. Check(pFileContents, fileSize, result);
  62. if (result != eResult_Success)
  63. {
  64. delete [] pFileContents;
  65. return 0;
  66. }
  67. CBinaryXmlData* const pData = Create(pFileContents, fileSize, result);
  68. if (result != eResult_Success)
  69. {
  70. assert(pData == 0);
  71. delete [] pFileContents;
  72. return 0;
  73. }
  74. assert(pData);
  75. pData->bOwnsFileContentsMemory = true;
  76. // Return first node
  77. return &pData->pBinaryNodes[0];
  78. }
  79. XmlNodeRef XMLBinary::XMLBinaryReader::LoadFromBuffer(
  80. EBufferMemoryHandling bufferMemoryHandling,
  81. const char* buffer,
  82. size_t size,
  83. XMLBinary::XMLBinaryReader::EResult& result)
  84. {
  85. m_errorDescription[0] = 0;
  86. result = eResult_Error;
  87. Check(buffer, size, result);
  88. if (result != eResult_Success)
  89. {
  90. return 0;
  91. }
  92. CBinaryXmlData* pData = 0;
  93. if (bufferMemoryHandling == eBufferMemoryHandling_MakeCopy)
  94. {
  95. char* ownBuffer = new char[size];
  96. if (!ownBuffer)
  97. {
  98. SetErrorDescription("Can't allocate memory for binary XML data.");
  99. return 0;
  100. }
  101. memcpy(ownBuffer, buffer, size);
  102. pData = Create(ownBuffer, size, result);
  103. if (result != eResult_Success)
  104. {
  105. assert(pData == 0);
  106. delete [] ownBuffer;
  107. return 0;
  108. }
  109. }
  110. else
  111. {
  112. assert(bufferMemoryHandling == eBufferMemoryHandling_TakeOwnership);
  113. pData = Create(buffer, size, result);
  114. if (result != eResult_Success)
  115. {
  116. assert(pData == 0);
  117. return 0;
  118. }
  119. }
  120. assert(pData);
  121. pData->bOwnsFileContentsMemory = true;
  122. // Return first node
  123. return &pData->pBinaryNodes[0];
  124. }
  125. void XMLBinary::XMLBinaryReader::Check(const char* buffer, size_t size, EResult& result)
  126. {
  127. m_errorDescription[0] = 0;
  128. result = eResult_Error;
  129. if (buffer == 0)
  130. {
  131. SetErrorDescription("Buffer is null.");
  132. return;
  133. }
  134. if (size < sizeof(BinaryFileHeader))
  135. {
  136. result = eResult_NotBinXml;
  137. SetErrorDescription("Not a binary XML - data size is too small.");
  138. return;
  139. }
  140. const BinaryFileHeader& header = *(reinterpret_cast<const BinaryFileHeader*>(buffer));
  141. CheckHeader(header, size, result);
  142. }
  143. void XMLBinary::XMLBinaryReader::CheckHeader(const BinaryFileHeader& header, size_t size, EResult& result)
  144. {
  145. assert(size >= sizeof(BinaryFileHeader));
  146. m_errorDescription[0] = 0;
  147. // Check the signature of the file to make sure that it is a binary XML file.
  148. {
  149. static const char signature[] = "CryXmlB";
  150. static_assert(sizeof(signature) == sizeof(header.szSignature));
  151. if (memcmp(header.szSignature, signature, sizeof(header.szSignature)) != 0)
  152. {
  153. result = eResult_NotBinXml;
  154. SetErrorDescription("Not a binary XML - has no signature.");
  155. return;
  156. }
  157. }
  158. // Check contents of the file header.
  159. const uint32 nNodeTableEnd = header.nNodeTablePosition + header.nNodeCount * sizeof(Node);
  160. const uint32 nChildTableEnd = header.nChildTablePosition + header.nChildCount * sizeof(NodeIndex);
  161. const uint32 nAttributeTableEnd = header.nAttributeTablePosition + header.nAttributeCount * sizeof(Attribute);
  162. const uint32 nStringDataEnd = header.nStringDataPosition + header.nStringDataSize;
  163. bool bCorrupt = false;
  164. bCorrupt = bCorrupt || header.nXMLSize > size;
  165. bCorrupt = bCorrupt || nNodeTableEnd > header.nChildTablePosition;
  166. bCorrupt = bCorrupt || nChildTableEnd > header.nAttributeTablePosition;
  167. bCorrupt = bCorrupt || nAttributeTableEnd > header.nStringDataPosition;
  168. bCorrupt = bCorrupt || nStringDataEnd > header.nXMLSize;
  169. if (bCorrupt)
  170. {
  171. result = eResult_Error;
  172. SetErrorDescription("Binary XML data is corrupt.");
  173. return;
  174. }
  175. result = eResult_Success;
  176. }
  177. CBinaryXmlData* XMLBinary::XMLBinaryReader::Create(const char* buffer, size_t size, EResult& result)
  178. {
  179. assert((buffer != 0) && (size >= sizeof(BinaryFileHeader)));
  180. m_errorDescription[0] = 0;
  181. result = eResult_Error;
  182. CBinaryXmlData* const pData = new CBinaryXmlData;
  183. if (!pData)
  184. {
  185. SetErrorDescription("Can't allocate memory for binary XML object.");
  186. return 0;
  187. }
  188. pData->pFileContents = buffer;
  189. pData->nFileSize = size;
  190. pData->bOwnsFileContentsMemory = false;
  191. const BinaryFileHeader& header = *(reinterpret_cast<const BinaryFileHeader*>(buffer));
  192. // Create nodes
  193. pData->pBinaryNodes = new CBinaryXmlNode[header.nNodeCount];
  194. if (!pData->pBinaryNodes)
  195. {
  196. delete pData;
  197. SetErrorDescription("Can't allocate memory for binary XML nodes.");
  198. return 0;
  199. }
  200. pData->pAttributes = reinterpret_cast<const Attribute*>(buffer + header.nAttributeTablePosition);
  201. pData->pChildIndices = reinterpret_cast<const NodeIndex*>(buffer + header.nChildTablePosition);
  202. pData->pNodes = reinterpret_cast<const Node*>(buffer + header.nNodeTablePosition);
  203. pData->pStringData = buffer + header.nStringDataPosition;
  204. for (uint32 nNode = 0; nNode < header.nNodeCount; ++nNode)
  205. {
  206. CBinaryXmlNode* const pNode = &pData->pBinaryNodes[nNode];
  207. pNode->m_nRefCount = 0;
  208. pNode->m_pData = pData;
  209. }
  210. result = eResult_Success;
  211. return pData;
  212. }