2023-02-25 17:39:39 +08:00
|
|
|
#pragma once
|
|
|
|
|
2024-08-17 20:43:27 +08:00
|
|
|
#include "../VTInternal.hpp"
|
2023-09-11 22:20:45 +08:00
|
|
|
#include <memory>
|
|
|
|
#include <functional>
|
2023-09-30 11:51:04 +08:00
|
|
|
#include <type_traits>
|
2023-02-25 17:39:39 +08:00
|
|
|
|
2023-02-26 21:48:03 +08:00
|
|
|
namespace LibCmo::CK2 {
|
2023-02-25 17:39:39 +08:00
|
|
|
|
2023-09-24 12:21:33 +08:00
|
|
|
/**
|
|
|
|
* @remark
|
|
|
|
* + We make sure m_BindContext and m_BindFile always are not nullptr. So some code of BindFile check and write different data struct has been removed.
|
|
|
|
* + Calling StartRead multiple times is illegal.
|
|
|
|
* - The solution is that use StartRead and StopRead to warp the real CKStateChunk consumer. And just calling read functions in real consumer directly.
|
|
|
|
* - See CKFileReader for more infomation.
|
|
|
|
* + Same as StartRead, calling StartWrite multiple times also is illegal. We also remove CKStateChunk merge function, AddChunkAndDelete and AddChunk.
|
|
|
|
* - The solution is same as StartRead solution. Use StartWrite and StopWrite warp the real CKStateChunk writer. Call write function in consumer directly.
|
|
|
|
* - Every inherited CKObject::Save must call SetClassId at the end of function if they have data to write.
|
|
|
|
* - See CKFileWrite for more infomation.
|
|
|
|
*/
|
2023-02-25 17:39:39 +08:00
|
|
|
class CKStateChunk {
|
|
|
|
public:
|
2023-08-25 21:57:22 +08:00
|
|
|
CKStateChunk(CKFileVisitor* visitor, CKContext* ctx);
|
2023-02-26 13:57:32 +08:00
|
|
|
CKStateChunk(const CKStateChunk&);
|
2023-08-25 21:57:22 +08:00
|
|
|
CKStateChunk(CKStateChunk&&);
|
2023-02-26 13:57:32 +08:00
|
|
|
CKStateChunk& operator=(const CKStateChunk&);
|
2023-08-26 16:37:26 +08:00
|
|
|
CKStateChunk& operator=(CKStateChunk&&);
|
2023-02-25 17:39:39 +08:00
|
|
|
~CKStateChunk();
|
|
|
|
|
2023-09-17 23:48:18 +08:00
|
|
|
#pragma region Self Used Data Struct
|
|
|
|
|
|
|
|
public:
|
|
|
|
struct ProfileStateChunk_t {
|
|
|
|
CK_CLASSID m_ClassId;
|
|
|
|
CKDWORD m_DataDwSize;
|
|
|
|
CKDWORD* m_pData;
|
|
|
|
|
|
|
|
CK_STATECHUNK_DATAVERSION m_DataVersion;
|
|
|
|
CK_STATECHUNK_CHUNKVERSION m_ChunkVersion;
|
|
|
|
|
|
|
|
size_t m_ObjectListSize, m_ChunkListSize, m_ManagerListSize;
|
|
|
|
|
|
|
|
CKFileVisitor* m_BindFile;
|
|
|
|
CKContext* m_BindContext;
|
|
|
|
};
|
|
|
|
struct ProfileIdentifier_t {
|
|
|
|
CKDWORD m_Identifier;
|
|
|
|
void* m_DataPtr;
|
|
|
|
CKDWORD m_AreaSize;
|
|
|
|
};
|
2023-09-18 16:37:05 +08:00
|
|
|
|
|
|
|
class LockedReadBufferDeleter {
|
|
|
|
public:
|
|
|
|
LockedReadBufferDeleter() : m_Host(nullptr), m_ConsumedSize(0) {}
|
|
|
|
LockedReadBufferDeleter(CKStateChunk* host, CKDWORD init_size) :
|
|
|
|
m_Host(host), m_ConsumedSize(init_size) {}
|
2024-08-17 20:43:27 +08:00
|
|
|
YYCC_DEF_CLS_COPY_MOVE(LockedReadBufferDeleter);
|
2023-09-18 16:37:05 +08:00
|
|
|
|
2024-08-17 23:29:08 +08:00
|
|
|
void operator()(const void* /*buf*/);
|
2023-09-18 16:37:05 +08:00
|
|
|
void SetConsumedSize(CKDWORD newsize);
|
|
|
|
private:
|
|
|
|
CKStateChunk* m_Host;
|
|
|
|
CKDWORD m_ConsumedSize;
|
|
|
|
};
|
2023-09-24 12:21:33 +08:00
|
|
|
|
2023-09-18 16:37:05 +08:00
|
|
|
class LockedWriteBufferDeleter {
|
|
|
|
public:
|
|
|
|
LockedWriteBufferDeleter() : m_Host(nullptr), m_ConsumedSize(0) {}
|
|
|
|
LockedWriteBufferDeleter(CKStateChunk* host, CKDWORD init_size) :
|
|
|
|
m_Host(host), m_ConsumedSize(init_size) {}
|
2024-08-17 20:43:27 +08:00
|
|
|
YYCC_DEF_CLS_COPY_MOVE(LockedWriteBufferDeleter);
|
2023-09-18 16:37:05 +08:00
|
|
|
|
2024-08-17 23:29:08 +08:00
|
|
|
void operator()(const void* /*buf*/);
|
2023-09-18 16:37:05 +08:00
|
|
|
void SetConsumedSize(CKDWORD newsize);
|
|
|
|
private:
|
|
|
|
CKStateChunk* m_Host;
|
|
|
|
CKDWORD m_ConsumedSize;
|
|
|
|
};
|
2023-09-24 12:21:33 +08:00
|
|
|
|
2023-09-18 16:37:05 +08:00
|
|
|
class BufferDeleter {
|
2023-09-17 23:48:18 +08:00
|
|
|
public:
|
2023-09-18 16:37:05 +08:00
|
|
|
BufferDeleter() : m_Host(nullptr), m_BufSize(0) {}
|
2023-09-24 12:21:33 +08:00
|
|
|
BufferDeleter(CKStateChunk* host, CKDWORD bufsize) :
|
2023-09-18 16:37:05 +08:00
|
|
|
m_Host(host), m_BufSize(bufsize) {}
|
2024-08-17 20:43:27 +08:00
|
|
|
YYCC_DEF_CLS_COPY_MOVE(BufferDeleter);
|
2023-09-18 16:37:05 +08:00
|
|
|
|
|
|
|
void operator()(const void* buf);
|
|
|
|
CKDWORD GetBufferSize() const;
|
2023-09-17 23:48:18 +08:00
|
|
|
private:
|
2023-09-18 16:37:05 +08:00
|
|
|
CKStateChunk* m_Host;
|
|
|
|
CKDWORD m_BufSize;
|
2023-09-17 23:48:18 +08:00
|
|
|
};
|
|
|
|
|
2023-09-18 16:37:05 +08:00
|
|
|
using LockedReadBuffer_t = std::unique_ptr<const void, LockedReadBufferDeleter>;
|
|
|
|
using LockedWriteBuffer_t = std::unique_ptr<void, LockedWriteBufferDeleter>;
|
|
|
|
using Buffer_t = std::unique_ptr<void, BufferDeleter>;
|
|
|
|
|
2023-02-25 17:39:39 +08:00
|
|
|
private:
|
2023-09-17 10:38:46 +08:00
|
|
|
enum class CKStateChunkStatus : CKDWORD {
|
2023-02-26 13:57:32 +08:00
|
|
|
IDLE,
|
|
|
|
READ,
|
|
|
|
WRITE
|
|
|
|
};
|
2023-08-26 16:37:26 +08:00
|
|
|
struct ChunkParser {
|
|
|
|
CKStateChunkStatus m_Status;
|
|
|
|
CKDWORD m_CurrentPos;
|
2023-09-30 16:01:39 +08:00
|
|
|
/**
|
|
|
|
* @brief The runtime size of CKStateChunk internal buf in DWORD unit.
|
|
|
|
* Usually be used and changed when resizing buffer in writing mode.
|
|
|
|
*/
|
2023-08-26 16:37:26 +08:00
|
|
|
CKDWORD m_DataSize;
|
|
|
|
CKDWORD m_PrevIdentifierPos;
|
|
|
|
};
|
2023-02-26 13:57:32 +08:00
|
|
|
|
2023-09-17 23:48:18 +08:00
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
#pragma region Member Decl
|
|
|
|
|
2023-02-25 17:39:39 +08:00
|
|
|
CK_CLASSID m_ClassId;
|
|
|
|
CKDWORD m_DataDwSize;
|
|
|
|
CKDWORD* m_pData;
|
|
|
|
|
|
|
|
CK_STATECHUNK_DATAVERSION m_DataVersion;
|
|
|
|
CK_STATECHUNK_CHUNKVERSION m_ChunkVersion;
|
|
|
|
|
2023-08-26 16:37:26 +08:00
|
|
|
ChunkParser m_Parser;
|
2023-02-25 17:39:39 +08:00
|
|
|
|
2023-08-29 14:00:34 +08:00
|
|
|
XContainer::XArray<CKDWORD> m_ObjectList;
|
|
|
|
XContainer::XArray<CKDWORD> m_ChunkList;
|
|
|
|
XContainer::XArray<CKDWORD> m_ManagerList;
|
2023-02-25 17:39:39 +08:00
|
|
|
|
2023-08-25 21:57:22 +08:00
|
|
|
CKFileVisitor* m_BindFile;
|
|
|
|
CKContext* m_BindContext;
|
2023-03-08 15:45:06 +08:00
|
|
|
|
2023-09-17 23:48:18 +08:00
|
|
|
#pragma endregion
|
|
|
|
|
2023-03-05 22:31:11 +08:00
|
|
|
#pragma region Buffer Related
|
2023-02-27 15:16:04 +08:00
|
|
|
|
|
|
|
public:
|
2023-08-29 14:00:34 +08:00
|
|
|
bool ConvertFromBuffer(const void* buf);
|
2023-02-27 15:16:04 +08:00
|
|
|
CKDWORD ConvertToBuffer(void* buf);
|
|
|
|
|
2023-03-05 22:31:11 +08:00
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
#pragma region Misc Functions
|
|
|
|
|
|
|
|
public:
|
2023-09-17 23:48:18 +08:00
|
|
|
// ===== 2 Profiles Getter used by Unvirt =====
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get basic info of this CKStateChunk.
|
|
|
|
* @return The struct describing this CKStateChunk.
|
|
|
|
*/
|
|
|
|
const ProfileStateChunk_t GetStateChunkProfile();
|
|
|
|
/**
|
2023-09-24 12:21:33 +08:00
|
|
|
* @brief Get all indentifier infos of this CKStateChunk,
|
2023-09-17 23:48:18 +08:00
|
|
|
* including identifier self, data area size and address.
|
|
|
|
* @return A arrary, each item describe a single identifier's info.
|
|
|
|
* @remark The detail of implement can be seen in SeekIdentifierAndReturnSize()
|
|
|
|
* @see SeekIdentifierAndReturnSize
|
|
|
|
*/
|
|
|
|
const XContainer::XArray<ProfileIdentifier_t> GetIdentifiersProfile();
|
2023-08-29 10:42:13 +08:00
|
|
|
|
2023-09-17 23:48:18 +08:00
|
|
|
/**
|
|
|
|
* @brief Clear this CKStateChunk, restore it to original status for other using.
|
|
|
|
*/
|
|
|
|
void Clear();
|
|
|
|
/**
|
|
|
|
* @brief Get the size of data buffer in this CKStateChunk.
|
|
|
|
* @return The data buffer's size in CKBYTE.
|
|
|
|
*/
|
|
|
|
CKDWORD GetDataSize() const;
|
|
|
|
/**
|
|
|
|
* @brief Get data version in this CKStateChunk.
|
|
|
|
* @remark Data version is frequently used by calling of CKStateChunk to distinguish different data layout due to compatibility reason.
|
|
|
|
* @return The data version.
|
|
|
|
*/
|
|
|
|
CK_STATECHUNK_DATAVERSION GetDataVersion() const;
|
|
|
|
/**
|
|
|
|
* @brief Set data version of this CKStateChunk.
|
|
|
|
* @param version The set data version
|
|
|
|
* @remark Frequently used when saving someing in CKStateChunk.
|
|
|
|
*/
|
2023-02-27 15:16:04 +08:00
|
|
|
void SetDataVersion(CK_STATECHUNK_DATAVERSION version);
|
2023-09-17 23:48:18 +08:00
|
|
|
/**
|
|
|
|
* @brief Get associated CK_CLASSID of this CKStateChunk
|
|
|
|
* @return Associated CK_CLASSID
|
|
|
|
*/
|
|
|
|
CK_CLASSID GetClassId() const;
|
|
|
|
/**
|
|
|
|
* @brief Set associated CK_CLASSID of this CKStateChunk.
|
|
|
|
* @param cid The set CK_CLASSID
|
|
|
|
* @remark Frequently used at the end of CKObject::Save() override.
|
|
|
|
*/
|
|
|
|
void SetClassId(CK_CLASSID cid);
|
|
|
|
|
|
|
|
|
2023-02-27 15:16:04 +08:00
|
|
|
bool Skip(CKDWORD DwordCount);
|
|
|
|
|
2023-03-05 22:31:11 +08:00
|
|
|
private:
|
2023-09-22 14:48:45 +08:00
|
|
|
/**
|
|
|
|
* @brief Convert byte based size to DWORD based size.
|
2023-09-24 12:21:33 +08:00
|
|
|
*
|
2023-09-22 14:48:45 +08:00
|
|
|
* Becase CKStateChunk use DWORD based buffer, so all data should be aligned to DWORD boundary.
|
|
|
|
* This function can convert byte based size to DWORD based size while keeping its size aligned with DWORD boundary.
|
|
|
|
* For example, caller want to allocate 3 bytes for data storing, this function will first align it to DWORD boundary, 4 bytes.
|
|
|
|
* Then convert it in DWORD size, 1 DWORD.
|
2023-09-24 12:21:33 +08:00
|
|
|
*
|
2023-09-22 14:48:45 +08:00
|
|
|
* @param char_size[in] The size in byte unit.
|
|
|
|
* @return The size in DWORD unit.
|
|
|
|
*/
|
2023-08-29 14:00:34 +08:00
|
|
|
CKDWORD GetCeilDwordSize(size_t char_size);
|
2023-03-05 22:31:11 +08:00
|
|
|
bool ResizeBuffer(CKDWORD new_dwsize);
|
2023-09-22 14:48:45 +08:00
|
|
|
/**
|
|
|
|
* @brief Check whether there are enough buffer to read.
|
2023-09-24 12:21:33 +08:00
|
|
|
*
|
|
|
|
* This function will check whether current CKStateChunk is in read mode and
|
2023-09-22 14:48:45 +08:00
|
|
|
* whether data area is enough to write.
|
|
|
|
* However, it is different with EnsureReadSpace. If no space to write, this function will
|
2023-09-24 12:21:33 +08:00
|
|
|
* try calling ResizeBuffer to get a enough buffer. Only when resize failed,
|
2023-09-22 14:48:45 +08:00
|
|
|
* this function will return false.
|
2023-09-24 12:21:33 +08:00
|
|
|
*
|
2023-09-22 14:48:45 +08:00
|
|
|
* @param dwsize[in] Required buffer size in DWORD unit.
|
|
|
|
* @return True if have enough space to write.
|
|
|
|
* @see EnsureReadSpace
|
|
|
|
*/
|
2023-03-05 22:31:11 +08:00
|
|
|
bool EnsureWriteSpace(CKDWORD dwsize);
|
2023-09-22 14:48:45 +08:00
|
|
|
/**
|
|
|
|
* @brief Check whether there are enough buffer to read.
|
2023-09-24 12:21:33 +08:00
|
|
|
*
|
|
|
|
* This function will check whether current CKStateChunk is in read mode and
|
2023-09-22 14:48:45 +08:00
|
|
|
* whether data area is enough to read.
|
2023-09-24 12:21:33 +08:00
|
|
|
*
|
2023-09-22 14:48:45 +08:00
|
|
|
* @param dword_required[in] Required buffer size in DWORD unit.
|
|
|
|
* @return True if have enough space to read.
|
|
|
|
* @see EnsureWriteSpace
|
|
|
|
*/
|
2023-03-05 22:31:11 +08:00
|
|
|
bool EnsureReadSpace(CKDWORD dword_required);
|
|
|
|
|
2023-09-24 13:55:41 +08:00
|
|
|
/**
|
|
|
|
* @brief The helper writer of m_ObjectList, m_ManagerList and m_ChunkList.
|
|
|
|
*
|
|
|
|
* Add a position indicator into list which represent a single data.
|
|
|
|
*
|
|
|
|
* @param entry_ls[in] The list to be written.
|
|
|
|
* @param pos[int] The written position data.
|
|
|
|
* @remark:
|
|
|
|
* + IntList::AddEntry() redirect to this.
|
|
|
|
*/
|
|
|
|
void AddEntry(XContainer::XArray<CKDWORD>& entry_ls, CKDWORD pos);
|
|
|
|
/**
|
|
|
|
* @brief The helper writer of m_ObjectList, m_ManagerList and m_ChunkList.
|
|
|
|
*
|
|
|
|
* Add a position indicator into list which represent a series of data.
|
|
|
|
*
|
|
|
|
* @param entry_ls[in] The list to be written.
|
|
|
|
* @param pos[int] The written position data.
|
|
|
|
* @remark:
|
|
|
|
* + IntList::AddEntries() redirect to this.
|
|
|
|
*/
|
|
|
|
void AddEntries(XContainer::XArray<CKDWORD>& entry_ls, CKDWORD pos);
|
|
|
|
|
2023-03-05 22:31:11 +08:00
|
|
|
#pragma endregion
|
|
|
|
|
2023-02-27 15:16:04 +08:00
|
|
|
#pragma region Read Function
|
|
|
|
|
|
|
|
public:
|
|
|
|
void StartRead(void);
|
2023-03-05 22:31:11 +08:00
|
|
|
void StopRead(void);
|
|
|
|
|
|
|
|
/* ========== Identifier Functions ==========*/
|
|
|
|
|
2023-09-24 12:21:33 +08:00
|
|
|
public:
|
2023-02-28 14:04:38 +08:00
|
|
|
bool SeekIdentifierDword(CKDWORD identifier);
|
|
|
|
bool SeekIdentifierDwordAndReturnSize(CKDWORD identifier, CKDWORD* out_size);
|
2023-09-30 11:51:04 +08:00
|
|
|
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
2023-02-28 14:04:38 +08:00
|
|
|
inline bool SeekIdentifier(TEnum enum_v) {
|
|
|
|
return SeekIdentifierDword(static_cast<CKDWORD>(enum_v));
|
|
|
|
}
|
2023-09-30 11:51:04 +08:00
|
|
|
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
2023-02-28 14:04:38 +08:00
|
|
|
inline bool SeekIdentifierAndReturnSize(TEnum enum_v, CKDWORD* out_size) {
|
|
|
|
return SeekIdentifierDwordAndReturnSize(static_cast<CKDWORD>(enum_v), out_size);
|
|
|
|
}
|
|
|
|
|
2023-09-18 16:37:05 +08:00
|
|
|
/* ========== Read Buffer Controller ==========*/
|
|
|
|
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* @brief Lock read buffer and make sure it has at least some bytes to read.
|
|
|
|
* @param ppData[out] The pointer to pointer receiving data address.
|
|
|
|
* @param size_in_byte[in] The number of bytes present in the read buffer needs to be ensured.
|
|
|
|
* @return Treu if success (can read)
|
|
|
|
* @remark
|
|
|
|
* + It actually not lock the buffer, just make sure that the read area is okey.
|
|
|
|
* + Do not forget calling UnLockReadBuffer after all read work done.
|
|
|
|
* @see UnLockReadBuffer, ReadBufferLocker
|
|
|
|
*/
|
|
|
|
bool LockReadBuffer(const void** ppData, CKDWORD size_in_byte);
|
|
|
|
/**
|
|
|
|
* @brief Unlock read buffer and move forward with specified bytes.
|
|
|
|
* @param size_in_byte[in] The number of bytes you wish to move forward.
|
|
|
|
* This value can be different with the value passed to LockReadBuffer but should not greater than it.
|
|
|
|
* @return True if success (have enough space to move forward)
|
|
|
|
* @remark
|
|
|
|
* + It actually not unlock the buffer, just move forward reading pointer.
|
|
|
|
* + Used together with LockReadBuffer.
|
|
|
|
* @see LockReadBuffer
|
|
|
|
*/
|
|
|
|
bool UnLockReadBuffer(CKDWORD size_in_byte);
|
|
|
|
/**
|
|
|
|
* @brief A RAII wrapper for LockReadBuffer and UnLockReadBuffer.
|
|
|
|
* @param size_in_byte[in] The value passed to LockReadBuffer.
|
2023-09-22 14:48:45 +08:00
|
|
|
* @return LockedReadBuffer_t (actually is a std::unique_ptr with custom deleter)
|
2023-09-18 16:37:05 +08:00
|
|
|
* @remark
|
2023-09-22 14:48:45 +08:00
|
|
|
* + The return value is just a std::unique_ptr but its deleter have more features.
|
|
|
|
* + If return value contained data is nullptr, it mean that this function is failed.
|
|
|
|
* + If you only use the pointer provided by the return value, the final moving forward byte count is the value passed in this function.
|
|
|
|
* + You also can use LockedReadBuffer_t.get_deleter().SetConsumedSize() to set the final moving forward byte count before the return value free itself.
|
|
|
|
* + The value passed to LockedReadBuffer_t..get_deleter().SetConsumedSize() will finally be passed to UnLockReadBuffer.
|
|
|
|
* + You can use LockedReadBuffer_t.reset() to force free the return value.
|
|
|
|
* @remark Here is a example.
|
2023-09-18 16:37:05 +08:00
|
|
|
* ```
|
2023-09-22 14:48:45 +08:00
|
|
|
* auto buf = chunk->LockReadBufferWrapper(1919810);
|
2023-09-24 12:21:33 +08:00
|
|
|
* if (buf) {
|
2023-09-22 14:48:45 +08:00
|
|
|
* stuff(buf.get()); // do some operation...
|
|
|
|
* buf.get_deleter().SetConsumedSize(114514); // i only consume these bytes.
|
|
|
|
* buf.reset(); // immediately free it.
|
2023-09-18 16:37:05 +08:00
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
* @see LockReadBuffer, UnLockReadBuffer, LockedReadBuffer_t
|
|
|
|
*/
|
|
|
|
LockedReadBuffer_t LockReadBufferWrapper(CKDWORD size_in_byte);
|
2023-09-24 12:21:33 +08:00
|
|
|
|
2023-03-05 22:31:11 +08:00
|
|
|
/* ========== Basic Data Read Functions ==========*/
|
2023-02-27 15:16:04 +08:00
|
|
|
|
2023-03-05 22:31:11 +08:00
|
|
|
private:
|
2023-09-01 13:27:46 +08:00
|
|
|
/**
|
2023-09-18 16:37:05 +08:00
|
|
|
* @brief A struct-read-friendly wrapper for LockReadBuffer and UnLockReadBuffer.
|
|
|
|
* All following struct reading function use this function as a underlaying calling.
|
2023-09-01 13:27:46 +08:00
|
|
|
* @param data_ptr[out] the pointer to data. must be allocated first.
|
|
|
|
* @param size_in_byte[in] the size of data in byte.
|
|
|
|
* @return True if success.
|
|
|
|
*/
|
2023-03-05 22:31:11 +08:00
|
|
|
bool ReadByteData(void* data_ptr, CKDWORD size_in_byte);
|
|
|
|
public:
|
2023-09-18 16:37:05 +08:00
|
|
|
/**
|
|
|
|
* @brief Read Struct
|
|
|
|
* @tparam T The reading type.
|
|
|
|
* @param data Data pointer for reading. Can not be bullptr
|
|
|
|
* @return True if reading success.
|
|
|
|
* @remark
|
|
|
|
* + This function is a reinterpter of a bunch of original Virtools SDK reading functions, including:
|
|
|
|
* - Primitive type: ReadInt, ReadByte, ReadWord, ReadDword, ReadFloat, etc...
|
|
|
|
* - Struct type: ReadGuid, ReadVector, ReadMatrix, etc...
|
|
|
|
* @see ReadStruct(T&)
|
|
|
|
*/
|
2023-03-05 22:31:11 +08:00
|
|
|
template<typename T>
|
|
|
|
bool ReadStruct(T* data) {
|
2023-08-29 14:00:34 +08:00
|
|
|
return ReadByteData(data, CKSizeof(T));
|
2023-02-27 15:16:04 +08:00
|
|
|
}
|
2023-09-18 16:37:05 +08:00
|
|
|
/**
|
|
|
|
* @brief Read Struct (Reference Type)
|
|
|
|
* @tparam T The reading type.
|
|
|
|
* @param data Data reference for reading.
|
|
|
|
* @return True if reading success.
|
|
|
|
* @see ReadStruct(T*)
|
|
|
|
*/
|
2023-02-27 15:16:04 +08:00
|
|
|
template<typename T>
|
2023-03-05 22:31:11 +08:00
|
|
|
inline bool ReadStruct(T& data) {
|
2023-08-29 14:00:34 +08:00
|
|
|
return ReadByteData(&data, CKSizeof(T));
|
2023-03-05 22:31:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
2023-09-10 21:33:43 +08:00
|
|
|
/// Read string. The content of string will automatically converted into UTF8 format.
|
2023-03-05 22:31:11 +08:00
|
|
|
/// </summary>
|
|
|
|
/// <param name="strl"></param>
|
|
|
|
/// <returns></returns>
|
2023-09-16 18:31:25 +08:00
|
|
|
bool ReadString(XContainer::XString* strl);
|
|
|
|
inline bool ReadString(XContainer::XString& strl) {
|
2023-03-05 22:31:11 +08:00
|
|
|
return ReadString(&strl);
|
2023-02-26 13:57:32 +08:00
|
|
|
}
|
2023-02-28 14:04:38 +08:00
|
|
|
|
2023-03-08 10:56:43 +08:00
|
|
|
/* ========== Complex Data Read Functions ==========*/
|
|
|
|
|
|
|
|
bool ReadObjectID(CK_ID* id);
|
2023-09-20 14:42:44 +08:00
|
|
|
bool ReadObjectPointer(ObjImpls::CKObject** obj);
|
2023-03-08 10:56:43 +08:00
|
|
|
inline bool ReadObjectID(CK_ID& id) {
|
|
|
|
return ReadObjectID(&id);
|
|
|
|
}
|
2023-09-20 14:42:44 +08:00
|
|
|
inline bool ReadObjectPointer(ObjImpls::CKObject*& id) {
|
|
|
|
return ReadObjectPointer(&id);
|
|
|
|
}
|
2023-03-08 10:56:43 +08:00
|
|
|
|
|
|
|
bool ReadManagerInt(CKGUID* guid, CKINT* intval);
|
|
|
|
inline bool ReadManagerInt(CKGUID& guid, CKINT& intval) {
|
|
|
|
return ReadManagerInt(&guid, &intval);
|
|
|
|
}
|
|
|
|
|
2023-09-24 13:55:41 +08:00
|
|
|
///**
|
|
|
|
// * @brief Read sub chunk
|
|
|
|
// * @return Returned a new created of CKStateChunk if success, otherwise nullptr.
|
|
|
|
// * Returned CKStateChunk should be manually released!
|
|
|
|
//*/
|
|
|
|
//CKStateChunk* ReadSubChunk();
|
2023-03-08 10:56:43 +08:00
|
|
|
|
2023-03-05 22:31:11 +08:00
|
|
|
/* ========== Buffer Functions ==========*/
|
2023-02-27 15:16:04 +08:00
|
|
|
|
2023-03-05 22:31:11 +08:00
|
|
|
/*
|
|
|
|
Buffer related function implements:
|
|
|
|
|
2023-09-30 11:51:04 +08:00
|
|
|
ReadBuffer(void**) Read Byte based size. -> ReadBuffer(void**, CKDWORD*)
|
|
|
|
ReadAndFillBuffer(int, void*) User give Byte based size. -> ReadAndFillBuffer(const void*, CKDWORD)
|
|
|
|
ReadAndFillBuffer(void*) Read Byte based size. -> ReadAndFillBuffer(const void*)
|
|
|
|
ReadAndFillBuffer_LEndian(int, void*) User give Byte based size. -> ReadAndFillBuffer(const void*, CKDWORD)
|
|
|
|
ReadAndFillBuffer_LEndian(void*) Read Byte based size. -> ReadAndFillBuffer(const void*)
|
|
|
|
ReadAndFillBuffer_LEndian16(int, void*) User give Byte based size. -> ReadAndFillBuffer(const void*, CKDWORD)
|
|
|
|
ReadAndFillBuffer_LEndian16(void*) Read Byte based size. -> ReadAndFillBuffer(const void*)
|
2023-03-05 22:31:11 +08:00
|
|
|
*/
|
|
|
|
|
2023-09-11 22:20:45 +08:00
|
|
|
/**
|
2023-09-18 23:11:33 +08:00
|
|
|
* @brief Read buffer and copy it.
|
2023-09-24 12:21:33 +08:00
|
|
|
*
|
2023-09-30 11:51:04 +08:00
|
|
|
* The size of buffer will be read from CKStateChunk internally.
|
|
|
|
* It mean the read buffer must be written by WriteBuffer().
|
|
|
|
*
|
2023-09-18 23:11:33 +08:00
|
|
|
* The copied buffer and the size of buffer will be returned to caller.
|
|
|
|
* Caller should free the buffer by calling CKStateChunk::DeleteBuffer(void*).
|
2023-09-24 12:21:33 +08:00
|
|
|
*
|
2023-09-18 23:11:33 +08:00
|
|
|
* @param ppData[out] The pointer to pointer holding the new copied data.
|
|
|
|
* @param size_in_byte[out] Set to the size of buffer when success.
|
|
|
|
* @return True if success.
|
2023-09-22 14:48:45 +08:00
|
|
|
* @remark Following original Virtools functions can use this function to implement:
|
|
|
|
* + ReadBuffer(void**)
|
2023-09-11 22:20:45 +08:00
|
|
|
*/
|
2023-09-18 23:11:33 +08:00
|
|
|
bool ReadBuffer(void** ppData, CKDWORD* size_in_byte);
|
2023-09-11 22:20:45 +08:00
|
|
|
/**
|
|
|
|
* @brief Free the buffer allocated by CKStateChunk reading functions.
|
2023-09-18 16:37:05 +08:00
|
|
|
* @param buf[in] The buffer need to be free.
|
|
|
|
* @see ReadBuffer
|
2023-09-11 22:20:45 +08:00
|
|
|
*/
|
|
|
|
void DeleteBuffer(const void* buf);
|
2023-09-18 23:11:33 +08:00
|
|
|
/**
|
2023-09-22 14:48:45 +08:00
|
|
|
* @brief A RAII wrapper for ReadAndCopyBuffer(void**, CKDWORD*)
|
|
|
|
* @return Buffer_t (actually is a std::unique_ptr with custom deleter)
|
|
|
|
* @remark
|
|
|
|
* + The return value is std::unique_ptr but its deleter have more features.
|
|
|
|
* + If return value containing value is nullptr, it mean this function is failed.
|
|
|
|
* + Use Buffer_t.get_deleter().GetBufferSize() to get the size of buffer.
|
|
|
|
* + You can use Buffer_t.reset() to force free the return value.
|
|
|
|
* @remark Here is a exmaple about how to use this function
|
|
|
|
* ```
|
|
|
|
* Buffer_t buf = chunk->ReadBufferWrapper(114);
|
2023-09-24 12:21:33 +08:00
|
|
|
* if (buf) {
|
2023-09-22 14:48:45 +08:00
|
|
|
* stuff(buf.get(), buf.get_deleter().GetBufferSize()); // do some operation...
|
|
|
|
* buf.reset(); // immediately free it.
|
|
|
|
* }
|
|
|
|
* ```
|
2023-09-18 23:11:33 +08:00
|
|
|
*/
|
|
|
|
Buffer_t ReadBufferWrapper();
|
2023-03-05 22:31:11 +08:00
|
|
|
|
2023-09-18 16:37:05 +08:00
|
|
|
/**
|
2023-09-18 23:11:33 +08:00
|
|
|
* @brief Read buffer and fill user struct.
|
2023-09-24 12:21:33 +08:00
|
|
|
*
|
2023-09-18 23:11:33 +08:00
|
|
|
* The size of buffer will be read from CKStateChunk internally and return to caller.
|
2023-09-30 11:51:04 +08:00
|
|
|
* It mean the read buffer must be written by WriteBuffer().
|
2023-09-24 12:21:33 +08:00
|
|
|
*
|
2023-09-18 23:11:33 +08:00
|
|
|
* @param pData[out] The pointer holding the data.
|
|
|
|
* @return True if success.
|
2023-09-22 14:48:45 +08:00
|
|
|
* @remark Following original Virtools functions can use this function to implement:
|
|
|
|
* + ReadAndFillBuffer(void*)
|
|
|
|
* + ReadAndFillBuffer_LEndian(void*)
|
|
|
|
* + ReadAndFillBuffer_LEndian16(void*)
|
2023-09-18 16:37:05 +08:00
|
|
|
*/
|
2023-09-18 23:11:33 +08:00
|
|
|
bool ReadAndFillBuffer(void* pData);
|
|
|
|
/**
|
|
|
|
* @brief Read buffer and fill user struct.
|
2023-09-24 12:21:33 +08:00
|
|
|
*
|
2023-09-18 23:11:33 +08:00
|
|
|
* The size of buffer is provided by user.
|
2023-09-30 11:51:04 +08:00
|
|
|
* It mean the read buffer must be written by WriteBufferNoSize().
|
2023-09-24 12:21:33 +08:00
|
|
|
*
|
2023-09-18 23:11:33 +08:00
|
|
|
* @param pData[out] The pointer holding the data.
|
|
|
|
* @param size_in_byte[in] The size of data which you want to read in byte unit
|
|
|
|
* @return True if success.
|
2023-09-22 14:48:45 +08:00
|
|
|
* @remark Following original Virtools functions can use this function to implement:
|
|
|
|
* + ReadAndFillBuffer(int, void*)
|
|
|
|
* + ReadAndFillBuffer_LEndian(int, void*)
|
|
|
|
* + ReadAndFillBuffer_LEndian16(int, void*)
|
2023-09-18 23:11:33 +08:00
|
|
|
*/
|
|
|
|
bool ReadAndFillBuffer(void* pData, CKDWORD size_in_byte);
|
|
|
|
|
2023-03-05 22:31:11 +08:00
|
|
|
/* ========== Sequence Functions ==========*/
|
2023-02-27 15:16:04 +08:00
|
|
|
|
2023-03-08 10:56:43 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Read Object ID Sequence
|
|
|
|
/// <para>The combination using of StartReadSequence(), ReadObjectID(), and ReadObject() redirect to this.</para>
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="ls"></param>
|
|
|
|
/// <returns></returns>
|
2023-09-20 14:42:44 +08:00
|
|
|
bool ReadObjectIDSequence(XContainer::XObjectArray* ls);
|
|
|
|
inline bool ReadObjectIDSequence(XContainer::XObjectArray& ls) {
|
2023-03-08 10:56:43 +08:00
|
|
|
return ReadObjectIDSequence(&ls);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Read Manager Sequence
|
|
|
|
/// <para>The combination using of StartManagerReadSequence() and ReadManagerIntSequence() redirect to this.</para>
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="guid"></param>
|
|
|
|
/// <param name="ls"></param>
|
|
|
|
/// <returns></returns>
|
2023-09-01 13:27:46 +08:00
|
|
|
bool ReadManagerIntSequence(CKGUID* guid, XContainer::XArray<CKINT>* ls);
|
|
|
|
inline bool ReadManagerIntSequence(CKGUID& guid, XContainer::XArray<CKINT>& ls) {
|
2023-03-08 10:56:43 +08:00
|
|
|
return ReadManagerIntSequence(&guid, &ls);
|
|
|
|
}
|
|
|
|
|
2023-09-24 13:55:41 +08:00
|
|
|
///// <summary>
|
|
|
|
///// Read Sub Chunk Sequence
|
|
|
|
///// <para>The combination using of StartReadSequence() and ReadSubChunk() redirect to this.</para>
|
|
|
|
///// <para>The item of returned CKStateChunk* list should be manually released!</para>
|
|
|
|
///// </summary>
|
|
|
|
///// <param name="ls"></param>
|
|
|
|
///// <returns></returns>
|
|
|
|
//bool ReadSubChunkSequence(XContainer::XArray<CKStateChunk*>* ls);
|
|
|
|
//inline bool ReadSubChunkSequence(XContainer::XArray<CKStateChunk*>& ls) {
|
|
|
|
// return ReadSubChunkSequence(&ls);
|
|
|
|
//}
|
2023-03-08 10:56:43 +08:00
|
|
|
|
2023-09-01 13:27:46 +08:00
|
|
|
/**
|
|
|
|
* @brief Read Object Array (actually still is CK_ID)
|
|
|
|
* @remark ReadObjectArray() and XObjectArray::Load redirect to this.
|
|
|
|
* @param ls The list
|
|
|
|
* @return True if success.
|
|
|
|
*/
|
|
|
|
bool ReadXObjectArray(XContainer::XObjectArray* ls);
|
|
|
|
inline bool ReadXObjectArray(XContainer::XObjectArray& ls) {
|
|
|
|
return ReadXObjectArray(&ls);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Read Object Array (actually is CKObject*)
|
|
|
|
* @remark ReadXObjectArray() and XObjectPointerArray::Load redirect to this.
|
|
|
|
* @param ls The list
|
|
|
|
* @return True if success
|
|
|
|
*/
|
|
|
|
bool ReadXObjectPointerArray(XContainer::XObjectPointerArray* ls);
|
|
|
|
inline bool ReadXObjectPointerArray(XContainer::XObjectPointerArray& ls) {
|
|
|
|
return ReadXObjectPointerArray(&ls);
|
2023-03-08 10:56:43 +08:00
|
|
|
}
|
|
|
|
|
2023-02-27 15:16:04 +08:00
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
#pragma region Write Function
|
|
|
|
|
|
|
|
public:
|
|
|
|
void StartWrite();
|
|
|
|
/*
|
2023-09-24 12:21:33 +08:00
|
|
|
* Actually this function mix various functions, including CloseChunk(), UpdateSize() and etc.
|
2023-02-27 15:16:04 +08:00
|
|
|
*/
|
|
|
|
void StopWrite(void);
|
|
|
|
|
2023-09-24 12:21:33 +08:00
|
|
|
|
|
|
|
/* ========== Identifier Functions ==========*/
|
|
|
|
|
|
|
|
public:
|
|
|
|
bool WriteIdentifierDword(CKDWORD identifier);
|
2023-09-30 11:51:04 +08:00
|
|
|
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
2023-09-24 12:21:33 +08:00
|
|
|
inline bool WriteIdentifier(TEnum enum_v) {
|
|
|
|
return WriteIdentifierDword(static_cast<CKDWORD>(enum_v));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ========== Write Buffer Controller ==========*/
|
|
|
|
|
|
|
|
public:
|
|
|
|
bool LockWriteBuffer(void** ppData, CKDWORD size_in_byte);
|
2023-09-18 16:37:05 +08:00
|
|
|
bool UnLockWriteBuffer(CKDWORD size_in_byte);
|
|
|
|
LockedWriteBuffer_t LockWriteBufferWrapper(CKDWORD size_in_byte);
|
|
|
|
|
2023-09-24 12:21:33 +08:00
|
|
|
/* ========== Basic Data Write Functions ==========*/
|
2023-02-27 15:16:04 +08:00
|
|
|
|
2023-09-24 12:21:33 +08:00
|
|
|
private:
|
|
|
|
bool WriteByteData(const void* data_ptr, CKDWORD size_in_byte);
|
2023-02-27 15:16:04 +08:00
|
|
|
|
2023-09-24 12:21:33 +08:00
|
|
|
public:
|
|
|
|
template<typename T>
|
|
|
|
bool WriteStruct(const T* data) {
|
|
|
|
return WriteByteData(data, CKSizeof(T));
|
|
|
|
}
|
|
|
|
template<typename T>
|
|
|
|
inline bool WriteStruct(const T& data) {
|
|
|
|
return WriteByteData(&data, CKSizeof(T));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WriteString(const XContainer::XString* strl);
|
|
|
|
inline bool WriteString(const XContainer::XString& strl) {
|
|
|
|
return WriteString(&strl);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ========== Complex Data Read Functions ==========*/
|
|
|
|
|
|
|
|
public:
|
|
|
|
bool WriteObjectID(const CK_ID* id);
|
|
|
|
bool WriteObjectPointer(ObjImpls::CKObject* obj);
|
|
|
|
inline bool WriteObjectID(const CK_ID& id) {
|
|
|
|
return WriteObjectID(&id);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WriteManagerInt(const CKGUID* guid, CKINT intval);
|
|
|
|
inline bool WriteManagerInt(const CKGUID& guid, CKINT intval) {
|
|
|
|
return WriteManagerInt(&guid, intval);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sub Chunk not support now.
|
|
|
|
// Too complex and I even don't use it in my code.
|
|
|
|
//CKStateChunk* ReadSubChunk();
|
|
|
|
|
|
|
|
/* ========== Buffer Functions ==========*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
Buffer related function implements:
|
|
|
|
|
|
|
|
WriteBuffer(int, void*) Write buffer with size. -> WriteBuffer(const void*, CKDWORD)
|
|
|
|
WriteBufferNoSize(int, void*) Write buffer without size. -> WriteBufferNoSize(const void*, CKDWORD)
|
|
|
|
WriteBuffer_LEndian(int, void*) Write buffer with size. -> WriteBuffer(const void*, CKDWORD)
|
|
|
|
WriteBuffer_LEndian16(int, void*) Write buffer with size. -> WriteBuffer(const void*, CKDWORD)
|
|
|
|
WriteBufferNoSize_LEndian(int, void*) Write buffer without size. -> WriteBufferNoSize(const void*, CKDWORD)
|
|
|
|
WriteBufferNoSize_LEndian16(int, void*) Write buffer without size. -> WriteBufferNoSize(const void*, CKDWORD)
|
|
|
|
*/
|
|
|
|
|
2023-09-29 23:09:01 +08:00
|
|
|
// MARK: buf can be nullptr, but buf size must is 0. and WriteBuffer will only write a zero to indicate there is a zero buffer.
|
|
|
|
|
2023-09-24 12:21:33 +08:00
|
|
|
bool WriteBuffer(const void* buf, CKDWORD size_in_byte);
|
|
|
|
bool WriteBufferNoSize(const void* buf, CKDWORD size_in_byte);
|
|
|
|
|
|
|
|
/* ========== Sequence Functions ==========*/
|
|
|
|
|
|
|
|
public:
|
|
|
|
bool WriteObjectIDSequence(const XContainer::XObjectArray* ls);
|
2023-09-24 13:55:41 +08:00
|
|
|
inline bool WriteObjectIDSequence(const XContainer::XObjectArray& ls) {
|
2023-09-24 12:21:33 +08:00
|
|
|
return WriteObjectIDSequence(&ls);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WriteManagerIntSequence(const CKGUID* guid, const XContainer::XArray<CKINT>* ls);
|
|
|
|
inline bool WriteManagerIntSequence(const CKGUID& guid, const XContainer::XArray<CKINT>& ls) {
|
|
|
|
return WriteManagerIntSequence(&guid, &ls);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sub chunk is not available now
|
|
|
|
// Because my code never use it and it is too complex.
|
|
|
|
//bool ReadSubChunkSequence(XContainer::XArray<CKStateChunk*>* ls);
|
|
|
|
//inline bool ReadSubChunkSequence(XContainer::XArray<CKStateChunk*>& ls) {
|
|
|
|
// return ReadSubChunkSequence(&ls);
|
|
|
|
//}
|
|
|
|
|
|
|
|
bool WriteXObjectArray(const XContainer::XObjectArray* ls);
|
|
|
|
inline bool WriteXObjectArray(const XContainer::XObjectArray& ls) {
|
|
|
|
return WriteXObjectArray(&ls);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WriteXObjectPointerArray(const XContainer::XObjectPointerArray* ls);
|
|
|
|
inline bool WriteXObjectPointerArray(const XContainer::XObjectPointerArray& ls) {
|
|
|
|
return WriteXObjectPointerArray(&ls);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma endregion
|
2023-02-27 15:16:04 +08:00
|
|
|
|
2023-02-25 17:39:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|