CmBinarySerializer.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #pragma once
  2. #include <unordered_map>
  3. #include <boost/function.hpp>
  4. #include "CmPrerequisitesUtil.h"
  5. #include "CmRTTIField.h"
  6. namespace CamelotEngine
  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 (unless the pointer isn't
  27. * registered in RTTIType). Upon decoding the pointer addresses will be set
  28. * to proper values.
  29. */
  30. class CM_UTILITY_EXPORT BinarySerializer
  31. {
  32. public:
  33. BinarySerializer();
  34. /**
  35. * @brief Encodes all serializable fields provided by "object" into a binary format. Data is written in chunks.
  36. * Whenever a chunk is filled a callback is triggered that gives the user opportunity to expand or
  37. * empty the buffer (for example write the chunk to disk)
  38. *
  39. * @param [in] object Object to encode into binary format.
  40. * @param [out] buffer Preallocated buffer where the data will be stored.
  41. * @param bufferLength Length of the buffer, in bytes.
  42. * @param [out] bytesWritten Length of the data that was actually written to the buffer,
  43. * in bytes.
  44. * @param flushBufferCallback This callback will get called whenever the buffer gets full (Be careful to check the provided
  45. * "bytesRead" variable, as buffer might not be full completely). User must then
  46. * either create a new buffer or empty the existing one, and then return it by the callback.
  47. * If the returned buffer address is NULL, encoding is aborted.
  48. */
  49. void encode(IReflectable* object, UINT8* buffer, UINT32 bufferLength, int* bytesWritten,
  50. boost::function<UINT8*(UINT8* buffer, int bytesWritten, UINT32& newBufferSize)> flushBufferCallback);
  51. /**
  52. * @brief Decodes an object from a binary format.
  53. *
  54. * @param [in] data Binary data to decode.
  55. * @param dataLength Length of the data.
  56. */
  57. std::shared_ptr<IReflectable> decode(UINT8* data, UINT32 dataLength);
  58. private:
  59. struct ObjectToEncode
  60. {
  61. ObjectToEncode(UINT32 _objectId, std::shared_ptr<IReflectable> _object)
  62. :objectId(_objectId), object(_object)
  63. { }
  64. UINT32 objectId;
  65. std::shared_ptr<IReflectable> object;
  66. };
  67. /**
  68. * @brief Pointer fields get resolved after everything is loaded. Store their
  69. * temporary data here until then.
  70. */
  71. struct PtrToResolve
  72. {
  73. PtrToResolve()
  74. :field(nullptr), object(nullptr), id(0)
  75. { }
  76. PtrToResolve(RTTIReflectablePtrFieldBase* _field, std::shared_ptr<IReflectable> _object, UINT32 _id)
  77. :field(_field), object(_object), id(_id), arrIdx(0)
  78. { }
  79. PtrToResolve(RTTIReflectablePtrFieldBase* _field, std::shared_ptr<IReflectable> _object, UINT32 _id, UINT32 _arrIdx)
  80. :field(_field), object(_object), id(_id), arrIdx(_arrIdx)
  81. { }
  82. RTTIReflectablePtrFieldBase* field;
  83. UINT32 arrIdx;
  84. std::shared_ptr<IReflectable> object;
  85. UINT32 id;
  86. };
  87. struct ObjectMetaData
  88. {
  89. UINT32 objectMeta;
  90. UINT32 typeId;
  91. };
  92. std::unordered_map<UINT32, UINT32> mObjectAddrToId;
  93. UINT32 mLastUsedObjectId;
  94. std::vector<ObjectToEncode> mObjectsToEncode;
  95. int mTotalBytesWritten;
  96. std::vector<PtrToResolve> mPtrsToResolve;
  97. std::unordered_map<UINT32, std::shared_ptr<IReflectable>> mDecodedObjects;
  98. UINT32 getObjectSize(IReflectable* object);
  99. /**
  100. * @brief Encodes a single IReflectable object.
  101. */
  102. UINT8* encodeInternal(IReflectable* object, UINT32 objectId, UINT8* buffer, UINT32& bufferLength, int* bytesWritten,
  103. boost::function<UINT8*(UINT8* buffer, int bytesWritten, UINT32& newBufferSize)> flushBufferCallback);
  104. /**
  105. * @brief Decodes a single IReflectable object.
  106. */
  107. bool decodeInternal(std::shared_ptr<IReflectable> object, UINT8* data, UINT32 dataLength, UINT32& bytesRead);
  108. /**
  109. * @brief Encodes data required for representing a serialized field, into 4 bytes.
  110. */
  111. UINT32 encodeFieldMetaData(UINT16 id, UINT8 size, bool array, SerializableFieldType type, bool hasDynamicSize);
  112. /**
  113. * @brief Decode meta field that was encoded using encodeFieldMetaData.
  114. */
  115. void decodeFieldMetaData(UINT32 encodedData, UINT16& id, UINT8& size, bool& array, SerializableFieldType& type, bool& hasDynamicSize);
  116. /**
  117. * @brief Encodes data required for representing an object identifier, into 8 bytes.
  118. *
  119. * @note Id can be a maximum of 30 bits, as two bits are reserved.
  120. *
  121. * @param objId Unique ID of the object instance.
  122. * @param objTypeId Unique ID of the object type.
  123. * @param isBaseClass true if this object is base class (i.e. just a part of a larger object).
  124. */
  125. ObjectMetaData encodeObjectMetaData(UINT32 objId, UINT32 objTypeId, bool isBaseClass);
  126. /**
  127. * @brief Decode meta field that was encoded using encodeObjectMetaData.
  128. */
  129. void decodeObjectMetaData(ObjectMetaData encodedData, UINT32& objId, UINT32& objTypeId, bool& isBaseClass);
  130. /**
  131. * @brief Returns true if the provided encoded meta data represents object meta data.
  132. */
  133. bool isObjectMetaData(UINT32 encodedData);
  134. /**
  135. * @brief Helper method for encoding a complex object and copying its data to a buffer.
  136. */
  137. UINT8* complexTypeToBuffer(IReflectable* object, UINT8* buffer, UINT32& bufferLength, int* bytesWritten,
  138. boost::function<UINT8*(UINT8* buffer, int bytesWritten, UINT32& newBufferSize)> flushBufferCallback);
  139. /**
  140. * @brief Helper method for decoding a complex object from the provided data buffer.
  141. */
  142. std::shared_ptr<IReflectable> complexTypeFromBuffer(RTTIReflectableFieldBase* field, UINT8* data, int* complexTypeSize);
  143. /**
  144. * @brief Finds an existing, or creates a unique unique identifier for the specified object.
  145. */
  146. UINT32 findOrCreatePersistentId(IReflectable* object);
  147. /**
  148. * @brief Finds or creates an id for the provided object and returns it.
  149. * And it adds the object to a list of objects that need to be encoded,
  150. * if it's not already there.
  151. */
  152. UINT32 registerObjectPtr(std::shared_ptr<IReflectable> object);
  153. };
  154. }