BsBinarySerializer.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. //__________________________ Banshee Project - A modern game development toolkit _________________________________//
  2. //_____________________________________ www.banshee-project.com __________________________________________________//
  3. //________________________ Copyright (c) 2014 Marko Pintera. All rights reserved. ________________________________//
  4. #pragma once
  5. #include <unordered_map>
  6. #include "BsPrerequisitesUtil.h"
  7. #include "BsRTTIField.h"
  8. namespace BansheeEngine
  9. {
  10. class IReflectable;
  11. struct RTTIReflectableFieldBase;
  12. struct RTTIReflectablePtrFieldBase;
  13. // TODO - Low priority. I will probably want to extract a generalized Serializer class so we can re-use the code
  14. // in text or other serializers
  15. // TODO - Low priority. Encode does a chunk-based encode so that we don't need to know the buffer size in advance,
  16. // and don't have to use a lot of memory for the buffer. Consider doing something similar for decode.
  17. // TODO - Low priority. Add a simple encode method that doesn't require a callback, instead it calls the callback internally
  18. // and creates the buffer internally.
  19. /**
  20. * @brief Encodes all the fields of the provided object into a binary format. Fields are
  21. * encoded using their unique IDs. Encoded data will remain compatible for decoding even
  22. * if you modify the encoded class, as long as you assign new unique field IDs to
  23. * added/modified fields.
  24. *
  25. * Like for any serializable class, fields are defined in RTTIType that each
  26. * IReflectable class must be able to return.
  27. *
  28. * Any data the object or its children are pointing to will also be serialized
  29. * (unless the pointer isn't registered in RTTIType). Upon decoding the pointer
  30. * addresses will be set to proper values.
  31. *
  32. * @note Child elements are guaranteed to be fully deserialized before their parents, except for fields
  33. * marked with WeakRef flag.
  34. */
  35. class BS_UTILITY_EXPORT BinarySerializer
  36. {
  37. public:
  38. BinarySerializer();
  39. /**
  40. * @brief Encodes all serializable fields provided by "object" into a binary format. Data is written in chunks.
  41. * Whenever a chunk is filled a callback is triggered that gives the user opportunity to expand or
  42. * empty the buffer (for example write the chunk to disk)
  43. *
  44. * @param object Object to encode into binary format.
  45. * @param [out] buffer Preallocated buffer where the data will be stored.
  46. * @param bufferLength Length of the buffer, in bytes.
  47. * @param [out] bytesWritten Length of the data that was actually written to the buffer,
  48. * in bytes.
  49. * @param flushBufferCallback This callback will get called whenever the buffer gets full (Be careful to check the provided
  50. * "bytesRead" variable, as buffer might not be full completely). User must then
  51. * either create a new buffer or empty the existing one, and then return it by the callback.
  52. * If the returned buffer address is NULL, encoding is aborted.
  53. */
  54. void encode(IReflectable* object, UINT8* buffer, UINT32 bufferLength, int* bytesWritten,
  55. std::function<UINT8*(UINT8* buffer, int bytesWritten, UINT32& newBufferSize)> flushBufferCallback);
  56. /**
  57. * @brief Decodes an object from binary data.
  58. *
  59. * @param data Binary data to decode.
  60. * @param dataLength Length of the data.
  61. */
  62. std::shared_ptr<IReflectable> decode(UINT8* data, UINT32 dataLength);
  63. private:
  64. struct ObjectToEncode
  65. {
  66. ObjectToEncode(UINT32 _objectId, std::shared_ptr<IReflectable> _object)
  67. :objectId(_objectId), object(_object)
  68. { }
  69. UINT32 objectId;
  70. std::shared_ptr<IReflectable> object;
  71. };
  72. struct ObjectToDecode
  73. {
  74. ObjectToDecode(UINT32 _objectId, std::shared_ptr<IReflectable> _object, UINT8* _locationInBuffer, UINT32 _locationInFile)
  75. :objectId(_objectId), object(_object), locationInBuffer(_locationInBuffer), locationInFile(_locationInFile), isDecoded(false)
  76. { }
  77. UINT32 objectId;
  78. std::shared_ptr<IReflectable> object;
  79. UINT8* locationInBuffer;
  80. UINT32 locationInFile;
  81. bool isDecoded;
  82. };
  83. struct ObjectMetaData
  84. {
  85. UINT32 objectMeta;
  86. UINT32 typeId;
  87. };
  88. UnorderedMap<void*, UINT32> mObjectAddrToId;
  89. UINT32 mLastUsedObjectId;
  90. Vector<ObjectToEncode> mObjectsToEncode;
  91. int mTotalBytesWritten;
  92. Map<UINT32, ObjectToDecode> mObjectMap;
  93. /**
  94. * @brief Parses the entire object and calculates total size required for
  95. * saving the object and all the objects it contains.
  96. */
  97. UINT32 getObjectSize(IReflectable* object);
  98. /**
  99. * @brief Encodes a single IReflectable object.
  100. */
  101. UINT8* encodeInternal(IReflectable* object, UINT32 objectId, UINT8* buffer, UINT32& bufferLength, int* bytesWritten,
  102. std::function<UINT8*(UINT8* buffer, int bytesWritten, UINT32& newBufferSize)> flushBufferCallback);
  103. /**
  104. * @brief Decodes a single IReflectable object.
  105. */
  106. bool decodeInternal(std::shared_ptr<IReflectable> object, UINT8* data, UINT32 dataLength, UINT32& bytesRead);
  107. /**
  108. * @brief Encodes data required for representing a serialized field, into 4 bytes.
  109. */
  110. UINT32 encodeFieldMetaData(UINT16 id, UINT8 size, bool array, SerializableFieldType type, bool hasDynamicSize);
  111. /**
  112. * @brief Decode meta field that was encoded using encodeFieldMetaData.
  113. */
  114. void decodeFieldMetaData(UINT32 encodedData, UINT16& id, UINT8& size, bool& array, SerializableFieldType& type, bool& hasDynamicSize);
  115. /**
  116. * @brief Encodes data required for representing an object identifier, into 8 bytes.
  117. *
  118. * @note Id can be a maximum of 30 bits, as two bits are reserved.
  119. *
  120. * @param objId Unique ID of the object instance.
  121. * @param objTypeId Unique ID of the object type.
  122. * @param isBaseClass true if this object is base class (i.e. just a part of a larger object).
  123. */
  124. ObjectMetaData encodeObjectMetaData(UINT32 objId, UINT32 objTypeId, bool isBaseClass);
  125. /**
  126. * @brief Decode meta field that was encoded using encodeObjectMetaData.
  127. */
  128. void decodeObjectMetaData(ObjectMetaData encodedData, UINT32& objId, UINT32& objTypeId, bool& isBaseClass);
  129. /**
  130. * @brief Returns true if the provided encoded meta data represents object meta data.
  131. */
  132. bool isObjectMetaData(UINT32 encodedData);
  133. /**
  134. * @brief Helper method for encoding a complex object and copying its data to a buffer.
  135. */
  136. UINT8* complexTypeToBuffer(IReflectable* object, UINT8* buffer, UINT32& bufferLength, int* bytesWritten,
  137. std::function<UINT8*(UINT8* buffer, int bytesWritten, UINT32& newBufferSize)> flushBufferCallback);
  138. /**
  139. * @brief Helper method for decoding a complex object from the provided data buffer.
  140. */
  141. std::shared_ptr<IReflectable> complexTypeFromBuffer(RTTIReflectableFieldBase* field, UINT8* data, int* complexTypeSize);
  142. /**
  143. * @brief Finds an existing, or creates a unique unique identifier for the specified object.
  144. */
  145. UINT32 findOrCreatePersistentId(IReflectable* object);
  146. /**
  147. * @brief Finds or creates an id for the provided object and returns it.
  148. * And it adds the object to a list of objects that need to be encoded,
  149. * if it's not already there.
  150. */
  151. UINT32 registerObjectPtr(std::shared_ptr<IReflectable> object);
  152. };
  153. }