BsBinarySerializer.h 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #pragma once
  2. #include <unordered_map>
  3. #include "BsPrerequisitesUtil.h"
  4. #include "BsSerializedObject.h"
  5. #include "BsRTTIField.h"
  6. namespace BansheeEngine
  7. {
  8. class IReflectable;
  9. struct RTTIReflectableFieldBase;
  10. struct RTTIReflectablePtrFieldBase;
  11. // TODO - Low priority. I will probably want to extract a generalized Serializer class so we can re-use the code
  12. // in text or other serializers
  13. // TODO - Low priority. Encode does a chunk-based encode so that we don't need to know the buffer size in advance,
  14. // and don't have to use a lot of memory for the buffer. Consider doing something similar for decode.
  15. // TODO - Low priority. Add a simple encode method that doesn't require a callback, instead it calls the callback internally
  16. // and creates the buffer internally.
  17. /**
  18. * @brief Encodes all the fields of the provided object into a binary format. Fields are
  19. * encoded using their unique IDs. Encoded data will remain compatible for decoding even
  20. * if you modify the encoded class, as long as you assign new unique field IDs to
  21. * added/modified fields.
  22. *
  23. * Like for any serializable class, fields are defined in RTTIType that each
  24. * IReflectable class must be able to return.
  25. *
  26. * Any data the object or its children are pointing to will also be serialized
  27. * (unless the pointer isn't registered in RTTIType). Upon decoding the pointer
  28. * addresses will be set to proper values.
  29. *
  30. * @note Child elements are guaranteed to be fully deserialized before their parents, except for fields
  31. * marked with WeakRef flag.
  32. */
  33. class BS_UTILITY_EXPORT BinarySerializer
  34. {
  35. public:
  36. BinarySerializer();
  37. /**
  38. * @brief Encodes all serializable fields provided by "object" into a binary format. Data is written in chunks.
  39. * Whenever a chunk is filled a callback is triggered that gives the user opportunity to expand or
  40. * empty the buffer (for example write the chunk to disk)
  41. *
  42. * @param object Object to encode into binary format.
  43. * @param [out] buffer Preallocated buffer where the data will be stored.
  44. * @param bufferLength Length of the buffer, in bytes.
  45. * @param [out] bytesWritten Length of the data that was actually written to the buffer,
  46. * in bytes.
  47. * @param flushBufferCallback This callback will get called whenever the buffer gets full (Be careful to check the provided
  48. * "bytesRead" variable, as buffer might not be full completely). User must then
  49. * either create a new buffer or empty the existing one, and then return it by the callback.
  50. * If the returned buffer address is NULL, encoding is aborted.
  51. * @param shallow Determines how to handle referenced objects. If true then references will not be encoded
  52. * and will be set to null. If false then references will be encoded as well and restored
  53. * upon decoding.
  54. */
  55. void encode(IReflectable* object, UINT8* buffer, UINT32 bufferLength, UINT32* bytesWritten,
  56. std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback,
  57. bool shallow = false);
  58. /**
  59. * @brief Decodes an object from binary data.
  60. *
  61. * @param data Binary data to decode.
  62. * @param dataLength Length of the data in bytes.
  63. */
  64. SPtr<IReflectable> decode(UINT8* data, UINT32 dataLength);
  65. /**
  66. * @brief Encodes an object into an intermediate representation.
  67. *
  68. * @param object Object to encode.
  69. * @param shallow Determines how to handle referenced objects. If true then references will not be encoded
  70. * and will be set to null. If false then references will be encoded as well and restored
  71. * upon decoding.
  72. */
  73. SPtr<SerializedObject> _encodeIntermediate(IReflectable* object, bool shallow = false);
  74. /**
  75. * @brief Decodes an object in memory into an intermediate representation for easier parsing.
  76. *
  77. * @param data Binary data to decode.
  78. * @param dataLength Length of the data in bytes.
  79. * @param copyData Determines should the data be copied or just referenced. If referenced
  80. * then the returned serialized object will be invalid as soon as the original
  81. * data buffer is destroyed. Referencing is faster than copying.
  82. *
  83. * @note Internal method.
  84. * References to field data will point to the original buffer and will become invalid
  85. * when it is destroyed.
  86. */
  87. SPtr<SerializedObject> _decodeIntermediate(UINT8* data, UINT32 dataLength, bool copyData = false);
  88. /**
  89. * @brief Decodes an intermediate representation of a serialized object into the actual object.
  90. *
  91. * @note Internal method.
  92. */
  93. SPtr<IReflectable> _decodeIntermediate(const SPtr<SerializedObject>& serializedObject);
  94. private:
  95. struct ObjectMetaData
  96. {
  97. UINT32 objectMeta;
  98. UINT32 typeId;
  99. };
  100. struct ObjectToEncode
  101. {
  102. ObjectToEncode(UINT32 _objectId, std::shared_ptr<IReflectable> _object)
  103. :objectId(_objectId), object(_object)
  104. { }
  105. UINT32 objectId;
  106. std::shared_ptr<IReflectable> object;
  107. };
  108. struct ObjectToDecode
  109. {
  110. ObjectToDecode(const SPtr<IReflectable>& _object, const SPtr<SerializedObject>& serializedObject)
  111. :object(_object), serializedObject(serializedObject), isDecoded(false)
  112. { }
  113. SPtr<IReflectable> object;
  114. SPtr<SerializedObject> serializedObject;
  115. bool isDecoded;
  116. };
  117. /**
  118. * @brief Parses the entire object and calculates total size required for
  119. * saving the object and all the objects it contains.
  120. */
  121. UINT32 getObjectSize(IReflectable* object);
  122. /**
  123. * @brief Encodes a single IReflectable object.
  124. */
  125. UINT8* encodeInternal(IReflectable* object, UINT32 objectId, UINT8* buffer, UINT32& bufferLength, UINT32* bytesWritten,
  126. std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback, bool shallow);
  127. /**
  128. * @brief Decodes a single IReflectable object.
  129. */
  130. void decodeInternal(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& serializableObject);
  131. /**
  132. * @brief Decodes an object in memory into an intermediate representation for easier parsing.
  133. */
  134. bool decodeIntermediateInternal(UINT8* data, UINT32 dataLength, UINT32& bytesRead, SPtr<SerializedObject>& output, bool copyData);
  135. /**
  136. * @brief Helper method for encoding a complex object and copying its data to a buffer.
  137. */
  138. UINT8* complexTypeToBuffer(IReflectable* object, UINT8* buffer, UINT32& bufferLength, UINT32* bytesWritten,
  139. std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback, bool shallow);
  140. /**
  141. * @brief Helper method for encoding a data block to a buffer.
  142. */
  143. UINT8* dataBlockToBuffer(UINT8* data, UINT32 size, UINT8* buffer, UINT32& bufferLength, UINT32* bytesWritten,
  144. std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback);
  145. /**
  146. * @brief Finds an existing, or creates a unique unique identifier for the specified object.
  147. */
  148. UINT32 findOrCreatePersistentId(IReflectable* object);
  149. /**
  150. * @brief Finds or creates an id for the provided object and returns it.
  151. * And it adds the object to a list of objects that need to be encoded,
  152. * if it's not already there.
  153. */
  154. UINT32 registerObjectPtr(std::shared_ptr<IReflectable> object);
  155. /**
  156. * @brief Encodes data required for representing a serialized field, into 4 bytes.
  157. */
  158. static UINT32 encodeFieldMetaData(UINT16 id, UINT8 size, bool array, SerializableFieldType type, bool hasDynamicSize);
  159. /**
  160. * @brief Decode meta field that was encoded using encodeFieldMetaData.
  161. */
  162. static void decodeFieldMetaData(UINT32 encodedData, UINT16& id, UINT8& size, bool& array, SerializableFieldType& type, bool& hasDynamicSize);
  163. /**
  164. * @brief Encodes data required for representing an object identifier, into 8 bytes.
  165. *
  166. * @note Id can be a maximum of 30 bits, as two bits are reserved.
  167. *
  168. * @param objId Unique ID of the object instance.
  169. * @param objTypeId Unique ID of the object type.
  170. * @param isBaseClass true if this object is base class (i.e. just a part of a larger object).
  171. */
  172. static ObjectMetaData encodeObjectMetaData(UINT32 objId, UINT32 objTypeId, bool isBaseClass);
  173. /**
  174. * @brief Decode meta field that was encoded using encodeObjectMetaData.
  175. */
  176. static void decodeObjectMetaData(ObjectMetaData encodedData, UINT32& objId, UINT32& objTypeId, bool& isBaseClass);
  177. /**
  178. * @brief Returns true if the provided encoded meta data represents object meta data.
  179. */
  180. static bool isObjectMetaData(UINT32 encodedData);
  181. UnorderedMap<void*, UINT32> mObjectAddrToId;
  182. UINT32 mLastUsedObjectId;
  183. Vector<ObjectToEncode> mObjectsToEncode;
  184. UINT32 mTotalBytesWritten;
  185. UnorderedMap<SPtr<SerializedObject>, ObjectToDecode> mObjectMap;
  186. UnorderedMap<UINT32, SPtr<SerializedObject>> mInterimObjectMap;
  187. static const int META_SIZE = 4; // Meta field size
  188. static const int NUM_ELEM_FIELD_SIZE = 4; // Size of the field storing number of array elements
  189. static const int COMPLEX_TYPE_FIELD_SIZE = 4; // Size of the field storing the size of a child complex type
  190. static const int DATA_BLOCK_TYPE_FIELD_SIZE = 4;
  191. };
  192. }