BsBinarySerializer.h 9.7 KB

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