Serializer.inl.h 6.5 KB

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