Serializer.inl.h 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Util/Serializer.h>
  6. namespace anki
  7. {
  8. namespace detail
  9. {
  10. class alignas(ANKI_SAFE_ALIGNMENT) BinarySerializerHeader
  11. {
  12. public:
  13. Array<U8, 8> m_magic;
  14. PtrSize m_dataSize;
  15. PtrSize m_pointerArrayFilePosition; ///< Points to an array of file positions that contain pointers.
  16. PtrSize m_pointerCount; ///< The size of the above.
  17. };
  18. static constexpr const char* BINARY_SERIALIZER_MAGIC = "ANKIBIN1";
  19. } // end namespace detail
  20. template<typename T>
  21. Error BinarySerializer::serializeInternal(const T& x, GenericMemoryPoolAllocator<U8> tmpAllocator, File& file)
  22. {
  23. checkStruct<T>();
  24. // Misc
  25. m_file = &file;
  26. ANKI_ASSERT(m_file->tell() == 0);
  27. m_err = Error::NONE;
  28. m_alloc = tmpAllocator;
  29. // Write the empty header (will be filled later)
  30. detail::BinarySerializerHeader header = {};
  31. const PtrSize headerFilePos = m_file->tell();
  32. ANKI_CHECK(m_file->write(&header, sizeof(header)));
  33. // Set EOF file pos
  34. const PtrSize dataFilePos = headerFilePos + sizeof(header);
  35. ANKI_ASSERT(isAligned(ANKI_SAFE_ALIGNMENT, dataFilePos));
  36. m_eofPos = dataFilePos + sizeof(T);
  37. m_beginOfDataFilePos = dataFilePos;
  38. // Finaly, serialize
  39. ANKI_CHECK(m_file->write(&x, sizeof(T)));
  40. m_structureFilePos.emplaceBack(m_alloc, dataFilePos);
  41. doValue("root", 0, x);
  42. m_structureFilePos.popBack(m_alloc);
  43. if(m_err)
  44. {
  45. return m_err;
  46. }
  47. // Write all pointers. Do that now and not while writing the actual shader in order to avoid the file seeks
  48. DynamicArrayAuto<PtrSize> pointerFilePositions(m_alloc);
  49. for(const PointerInfo& pointer : m_pointerFilePositions)
  50. {
  51. ANKI_CHECK(m_file->seek(pointer.m_filePos, FileSeekOrigin::BEGINNING));
  52. ANKI_CHECK(m_file->write(&pointer.m_value, sizeof(pointer.m_value)));
  53. const PtrSize offsetAfterHeader = pointer.m_filePos - m_beginOfDataFilePos;
  54. ANKI_ASSERT(offsetAfterHeader + sizeof(void*) <= m_eofPos - m_beginOfDataFilePos);
  55. pointerFilePositions.emplaceBack(offsetAfterHeader);
  56. }
  57. // Write the pointer offsets
  58. if(pointerFilePositions.getSize() > 0)
  59. {
  60. ANKI_CHECK(m_file->seek(m_eofPos, FileSeekOrigin::BEGINNING));
  61. ANKI_CHECK(m_file->write(&pointerFilePositions[0], pointerFilePositions.getSizeInBytes()));
  62. header.m_pointerCount = pointerFilePositions.getSize();
  63. header.m_pointerArrayFilePosition = m_eofPos;
  64. }
  65. // Write the header
  66. memcpy(&header.m_magic[0], detail::BINARY_SERIALIZER_MAGIC, sizeof(header.m_magic));
  67. header.m_dataSize = m_eofPos - dataFilePos;
  68. ANKI_CHECK(m_file->seek(headerFilePos, FileSeekOrigin::BEGINNING));
  69. ANKI_CHECK(m_file->write(&header, sizeof(header)));
  70. // Done
  71. m_file = nullptr;
  72. m_pointerFilePositions.destroy(m_alloc);
  73. m_alloc = GenericMemoryPoolAllocator<U8>();
  74. return Error::NONE;
  75. }
  76. template<typename T>
  77. Error BinarySerializer::doArrayComplexType(const T* arr, PtrSize size, PtrSize memberOffset)
  78. {
  79. ANKI_ASSERT(arr && size > 0);
  80. check();
  81. checkStruct<T>();
  82. // Serialize pointers
  83. PtrSize structFilePos = m_structureFilePos.getBack() + memberOffset;
  84. for(PtrSize i = 0; i < size; ++i)
  85. {
  86. m_structureFilePos.emplaceBack(m_alloc, structFilePos);
  87. // Serialize the pointers
  88. SerializeFunctor<T>()(arr[i], *this);
  89. ANKI_CHECK(m_err);
  90. // Advance file pos
  91. m_structureFilePos.popBack(m_alloc);
  92. structFilePos += sizeof(T);
  93. }
  94. check();
  95. return Error::NONE;
  96. }
  97. template<typename T>
  98. Error BinarySerializer::doDynamicArrayComplexType(const T* arr, PtrSize size, PtrSize memberOffset)
  99. {
  100. check();
  101. checkStruct<T>();
  102. if(size == 0)
  103. {
  104. ANKI_ASSERT(arr == nullptr);
  105. // Do nothing
  106. }
  107. else
  108. {
  109. ANKI_ASSERT(arr);
  110. // Move file pos to the end of the file (allocate space)
  111. PtrSize arrayFilePos = getAlignedRoundUp(alignof(T), m_eofPos);
  112. m_eofPos = arrayFilePos + size * sizeof(T);
  113. // Store the pointer for later
  114. const PtrSize structFilePos = m_structureFilePos.getBack();
  115. PointerInfo pinfo;
  116. pinfo.m_filePos = structFilePos + memberOffset;
  117. pinfo.m_value = arrayFilePos - m_beginOfDataFilePos;
  118. m_pointerFilePositions.emplaceBack(m_alloc, pinfo);
  119. // Write the structures
  120. ANKI_CHECK(m_file->seek(arrayFilePos, FileSeekOrigin::BEGINNING));
  121. ANKI_CHECK(m_file->write(&arr[0], sizeof(T) * size));
  122. // Basically serialize pointers
  123. for(PtrSize i = 0; i < size && !m_err; ++i)
  124. {
  125. m_structureFilePos.emplaceBack(m_alloc, arrayFilePos);
  126. SerializeFunctor<T>()(arr[i], *this);
  127. m_structureFilePos.popBack(m_alloc);
  128. arrayFilePos += sizeof(T);
  129. }
  130. ANKI_CHECK(m_err);
  131. }
  132. check();
  133. return Error::NONE;
  134. }
  135. template<typename T>
  136. Error BinaryDeserializer::deserialize(T*& x, GenericMemoryPoolAllocator<U8> allocator, File& file)
  137. {
  138. x = nullptr;
  139. detail::BinarySerializerHeader header;
  140. ANKI_CHECK(file.read(&header, sizeof(header)));
  141. const PtrSize dataFilePos = file.tell();
  142. // Sanity checks
  143. {
  144. if(memcmp(&header.m_magic[0], detail::BINARY_SERIALIZER_MAGIC, 8) != 0)
  145. {
  146. ANKI_UTIL_LOGE("Wrong magic work in header");
  147. return Error::USER_DATA;
  148. }
  149. if(header.m_dataSize < sizeof(T))
  150. {
  151. ANKI_UTIL_LOGE("Wrong data size");
  152. return Error::USER_DATA;
  153. }
  154. const PtrSize expectedSizeAfterHeader = header.m_dataSize + header.m_pointerCount * sizeof(void*);
  155. const PtrSize actualSizeAfterHeader = file.getSize() - dataFilePos;
  156. if(expectedSizeAfterHeader > actualSizeAfterHeader)
  157. {
  158. ANKI_UTIL_LOGE("File size doesn't match expectations");
  159. return Error::USER_DATA;
  160. }
  161. }
  162. // Allocate & read data
  163. U8* const baseAddress =
  164. static_cast<U8*>(allocator.getMemoryPool().allocate(header.m_dataSize, ANKI_SAFE_ALIGNMENT));
  165. ANKI_CHECK(file.read(baseAddress, header.m_dataSize));
  166. // Fix pointers
  167. if(header.m_pointerCount)
  168. {
  169. ANKI_CHECK(file.seek(header.m_pointerArrayFilePosition, FileSeekOrigin::BEGINNING));
  170. for(PtrSize i = 0; i < header.m_pointerCount; ++i)
  171. {
  172. // Read the location of the pointer
  173. PtrSize offsetFromBeginOfData;
  174. ANKI_CHECK(file.read(&offsetFromBeginOfData, sizeof(offsetFromBeginOfData)));
  175. if(offsetFromBeginOfData >= header.m_dataSize)
  176. {
  177. ANKI_UTIL_LOGE("Corrupt pointer");
  178. return Error::USER_DATA;
  179. }
  180. // Add to the location the actual base address
  181. U8* ptrLocation = baseAddress + offsetFromBeginOfData;
  182. PtrSize& ptrValue = *reinterpret_cast<PtrSize*>(ptrLocation);
  183. if(ptrValue >= header.m_dataSize)
  184. {
  185. ANKI_UTIL_LOGE("Corrupt pointer");
  186. return Error::USER_DATA;
  187. }
  188. ptrValue += ptrToNumber(baseAddress);
  189. }
  190. }
  191. // Done
  192. x = reinterpret_cast<T*>(baseAddress);
  193. return Error::NONE;
  194. }
  195. } // end namespace anki