write some funcs for CKStateChunk writer
This commit is contained in:
parent
a17b9deb4c
commit
3e265cdf1d
|
@ -173,6 +173,7 @@ namespace LibCmo::CK2 {
|
||||||
CKFileVisitor& operator=(CKFileVisitor&&);
|
CKFileVisitor& operator=(CKFileVisitor&&);
|
||||||
|
|
||||||
const CKFileObject* GetFileObjectByIndex(size_t index);
|
const CKFileObject* GetFileObjectByIndex(size_t index);
|
||||||
|
CKDWORD GetIndexByObjectID(CK_ID objid);
|
||||||
protected:
|
protected:
|
||||||
bool m_IsReader;
|
bool m_IsReader;
|
||||||
CKFileReader* m_Reader;
|
CKFileReader* m_Reader;
|
||||||
|
@ -226,7 +227,7 @@ namespace LibCmo::CK2 {
|
||||||
|
|
||||||
// ========== Saving Preparing ==========
|
// ========== Saving Preparing ==========
|
||||||
bool AddSavedObject(ObjImpls::CKObject* obj, CKDWORD flags = CK_STATESAVE_ALL);
|
bool AddSavedObject(ObjImpls::CKObject* obj, CKDWORD flags = CK_STATESAVE_ALL);
|
||||||
bool AddSavedObjects(CKObjectArray* objarray, CKDWORD flags = CK_STATESAVE_ALL);
|
bool AddSavedObjects(const XContainer::XObjectPointerArray& objarray, CKDWORD flags = CK_STATESAVE_ALL);
|
||||||
bool AddSavedFile(CKSTRING u8FileName);
|
bool AddSavedFile(CKSTRING u8FileName);
|
||||||
|
|
||||||
// ========== Saving ==========
|
// ========== Saving ==========
|
||||||
|
@ -248,6 +249,8 @@ namespace LibCmo::CK2 {
|
||||||
XContainer::XArray<CKFileManagerData> m_ManagersData; /**< Manager Data loaded */
|
XContainer::XArray<CKFileManagerData> m_ManagersData; /**< Manager Data loaded */
|
||||||
XContainer::XArray<CKFilePluginDependencies> m_PluginsDep; /**< Plugins dependencies for this file */
|
XContainer::XArray<CKFilePluginDependencies> m_PluginsDep; /**< Plugins dependencies for this file */
|
||||||
XContainer::XArray<XContainer::XString> m_IncludedFiles; /**< List of files that should be inserted in the CMO file. */
|
XContainer::XArray<XContainer::XString> m_IncludedFiles; /**< List of files that should be inserted in the CMO file. */
|
||||||
|
XContainer::XHashTable<CK_ID, CKDWORD> m_ObjectsHashTable; /**< A Object ID to save index hash table. */
|
||||||
|
XContainer::XBitArray m_AlreadySavedMask; /**< Field recording saved object id. If this object is saved, set m_AlreadySavedMask[id] to true. Also used to check whether object already is in save list. */
|
||||||
CKFileInfo m_FileInfo; /**< Headers summary */
|
CKFileInfo m_FileInfo; /**< Headers summary */
|
||||||
|
|
||||||
CKERROR PrepareFile(CKSTRING filename);
|
CKERROR PrepareFile(CKSTRING filename);
|
||||||
|
|
|
@ -234,17 +234,47 @@ namespace LibCmo::CK2 {
|
||||||
|
|
||||||
bool CKFileWriter::AddSavedObject(ObjImpls::CKObject* obj, CKDWORD flags) {
|
bool CKFileWriter::AddSavedObject(ObjImpls::CKObject* obj, CKDWORD flags) {
|
||||||
if (m_Done || m_IsCopyFromReader) return false;
|
if (m_Done || m_IsCopyFromReader) return false;
|
||||||
return false;
|
if (obj == nullptr) return false;
|
||||||
|
|
||||||
|
// check whether is saved.
|
||||||
|
CK_ID objid = obj->GetID();
|
||||||
|
if (XContainer::NSXBitArray::IsSet(m_AlreadySavedMask, static_cast<CKDWORD>(objid))) return false;
|
||||||
|
|
||||||
|
// ok, insert this value
|
||||||
|
m_ObjectsHashTable.try_emplace(objid, static_cast<CKDWORD>(m_FileObjects.size()));
|
||||||
|
|
||||||
|
XContainer::NSXBitArray::Set(m_AlreadySavedMask, static_cast<CKDWORD>(objid));
|
||||||
|
|
||||||
|
CKFileObject fobj;
|
||||||
|
fobj.ObjectId = objid;
|
||||||
|
fobj.ObjPtr = obj;
|
||||||
|
fobj.ObjectCid = obj->GetClassID();
|
||||||
|
fobj.SaveFlags = flags;
|
||||||
|
XContainer::NSXString::FromCKSTRING(fobj.Name, obj->GetName());
|
||||||
|
m_FileObjects.emplace_back(std::move(fobj));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CKFileWriter::AddSavedObjects(CKObjectArray* objarray, CKDWORD flags) {
|
bool CKFileWriter::AddSavedObjects(const XContainer::XObjectPointerArray& objarray, CKDWORD flags) {
|
||||||
if (m_Done || m_IsCopyFromReader) return false;
|
if (m_Done || m_IsCopyFromReader) return false;
|
||||||
return false;
|
|
||||||
|
bool ret = true;
|
||||||
|
for (auto obj : objarray) {
|
||||||
|
if (!AddSavedObject(obj, flags)) {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CKFileWriter::AddSavedFile(CKSTRING u8FileName) {
|
bool CKFileWriter::AddSavedFile(CKSTRING u8FileName) {
|
||||||
if (m_Done || m_IsCopyFromReader) return false;
|
if (m_Done || m_IsCopyFromReader) return false;
|
||||||
return false;
|
if (u8FileName == nullptr) return false;
|
||||||
|
|
||||||
|
m_IncludedFiles.emplace_back(u8FileName);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
@ -294,6 +324,16 @@ namespace LibCmo::CK2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CKDWORD CKFileVisitor::GetIndexByObjectID(CK_ID objid) {
|
||||||
|
// see CKFile::SaveFindObjectIndex in IDA
|
||||||
|
CKDWORD idx = -1;
|
||||||
|
if (m_IsReader) return idx;
|
||||||
|
|
||||||
|
auto finder = m_Writer->m_ObjectsHashTable.find(objid);
|
||||||
|
if (finder == m_Writer->m_ObjectsHashTable.end()) return idx;
|
||||||
|
return finder->second;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,17 @@
|
||||||
|
|
||||||
namespace LibCmo::CK2 {
|
namespace LibCmo::CK2 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
class CKStateChunk {
|
class CKStateChunk {
|
||||||
public:
|
public:
|
||||||
CKStateChunk(CKFileVisitor* visitor, CKContext* ctx);
|
CKStateChunk(CKFileVisitor* visitor, CKContext* ctx);
|
||||||
|
@ -50,7 +61,7 @@ namespace LibCmo::CK2 {
|
||||||
CKStateChunk* m_Host;
|
CKStateChunk* m_Host;
|
||||||
CKDWORD m_ConsumedSize;
|
CKDWORD m_ConsumedSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LockedWriteBufferDeleter {
|
class LockedWriteBufferDeleter {
|
||||||
public:
|
public:
|
||||||
LockedWriteBufferDeleter() : m_Host(nullptr), m_ConsumedSize(0) {}
|
LockedWriteBufferDeleter() : m_Host(nullptr), m_ConsumedSize(0) {}
|
||||||
|
@ -64,11 +75,11 @@ namespace LibCmo::CK2 {
|
||||||
CKStateChunk* m_Host;
|
CKStateChunk* m_Host;
|
||||||
CKDWORD m_ConsumedSize;
|
CKDWORD m_ConsumedSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BufferDeleter {
|
class BufferDeleter {
|
||||||
public:
|
public:
|
||||||
BufferDeleter() : m_Host(nullptr), m_BufSize(0) {}
|
BufferDeleter() : m_Host(nullptr), m_BufSize(0) {}
|
||||||
BufferDeleter(CKStateChunk* host, CKDWORD bufsize) :
|
BufferDeleter(CKStateChunk* host, CKDWORD bufsize) :
|
||||||
m_Host(host), m_BufSize(bufsize) {}
|
m_Host(host), m_BufSize(bufsize) {}
|
||||||
LIBCMO_DEFAULT_COPY_MOVE(BufferDeleter);
|
LIBCMO_DEFAULT_COPY_MOVE(BufferDeleter);
|
||||||
|
|
||||||
|
@ -137,7 +148,7 @@ namespace LibCmo::CK2 {
|
||||||
*/
|
*/
|
||||||
const ProfileStateChunk_t GetStateChunkProfile();
|
const ProfileStateChunk_t GetStateChunkProfile();
|
||||||
/**
|
/**
|
||||||
* @brief Get all indentifier infos of this CKStateChunk,
|
* @brief Get all indentifier infos of this CKStateChunk,
|
||||||
* including identifier self, data area size and address.
|
* including identifier self, data area size and address.
|
||||||
* @return A arrary, each item describe a single identifier's info.
|
* @return A arrary, each item describe a single identifier's info.
|
||||||
* @remark The detail of implement can be seen in SeekIdentifierAndReturnSize()
|
* @remark The detail of implement can be seen in SeekIdentifierAndReturnSize()
|
||||||
|
@ -184,12 +195,12 @@ namespace LibCmo::CK2 {
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief Convert byte based size to DWORD based size.
|
* @brief Convert byte based size to DWORD based size.
|
||||||
*
|
*
|
||||||
* Becase CKStateChunk use DWORD based buffer, so all data should be aligned to DWORD boundary.
|
* 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.
|
* 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.
|
* 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.
|
* Then convert it in DWORD size, 1 DWORD.
|
||||||
*
|
*
|
||||||
* @param char_size[in] The size in byte unit.
|
* @param char_size[in] The size in byte unit.
|
||||||
* @return The size in DWORD unit.
|
* @return The size in DWORD unit.
|
||||||
*/
|
*/
|
||||||
|
@ -197,13 +208,13 @@ namespace LibCmo::CK2 {
|
||||||
bool ResizeBuffer(CKDWORD new_dwsize);
|
bool ResizeBuffer(CKDWORD new_dwsize);
|
||||||
/**
|
/**
|
||||||
* @brief Check whether there are enough buffer to read.
|
* @brief Check whether there are enough buffer to read.
|
||||||
*
|
*
|
||||||
* This function will check whether current CKStateChunk is in read mode and
|
* This function will check whether current CKStateChunk is in read mode and
|
||||||
* whether data area is enough to write.
|
* whether data area is enough to write.
|
||||||
* However, it is different with EnsureReadSpace. If no space to write, this function will
|
* However, it is different with EnsureReadSpace. If no space to write, this function will
|
||||||
* try calling ResizeBuffer to get a enough buffer. Only when resize failed,
|
* try calling ResizeBuffer to get a enough buffer. Only when resize failed,
|
||||||
* this function will return false.
|
* this function will return false.
|
||||||
*
|
*
|
||||||
* @param dwsize[in] Required buffer size in DWORD unit.
|
* @param dwsize[in] Required buffer size in DWORD unit.
|
||||||
* @return True if have enough space to write.
|
* @return True if have enough space to write.
|
||||||
* @see EnsureReadSpace
|
* @see EnsureReadSpace
|
||||||
|
@ -211,10 +222,10 @@ namespace LibCmo::CK2 {
|
||||||
bool EnsureWriteSpace(CKDWORD dwsize);
|
bool EnsureWriteSpace(CKDWORD dwsize);
|
||||||
/**
|
/**
|
||||||
* @brief Check whether there are enough buffer to read.
|
* @brief Check whether there are enough buffer to read.
|
||||||
*
|
*
|
||||||
* This function will check whether current CKStateChunk is in read mode and
|
* This function will check whether current CKStateChunk is in read mode and
|
||||||
* whether data area is enough to read.
|
* whether data area is enough to read.
|
||||||
*
|
*
|
||||||
* @param dword_required[in] Required buffer size in DWORD unit.
|
* @param dword_required[in] Required buffer size in DWORD unit.
|
||||||
* @return True if have enough space to read.
|
* @return True if have enough space to read.
|
||||||
* @see EnsureWriteSpace
|
* @see EnsureWriteSpace
|
||||||
|
@ -231,6 +242,7 @@ namespace LibCmo::CK2 {
|
||||||
|
|
||||||
/* ========== Identifier Functions ==========*/
|
/* ========== Identifier Functions ==========*/
|
||||||
|
|
||||||
|
public:
|
||||||
bool SeekIdentifierDword(CKDWORD identifier);
|
bool SeekIdentifierDword(CKDWORD identifier);
|
||||||
bool SeekIdentifierDwordAndReturnSize(CKDWORD identifier, CKDWORD* out_size);
|
bool SeekIdentifierDwordAndReturnSize(CKDWORD identifier, CKDWORD* out_size);
|
||||||
template<typename TEnum>
|
template<typename TEnum>
|
||||||
|
@ -281,7 +293,7 @@ namespace LibCmo::CK2 {
|
||||||
* @remark Here is a example.
|
* @remark Here is a example.
|
||||||
* ```
|
* ```
|
||||||
* auto buf = chunk->LockReadBufferWrapper(1919810);
|
* auto buf = chunk->LockReadBufferWrapper(1919810);
|
||||||
* if (buf) {
|
* if (buf) {
|
||||||
* stuff(buf.get()); // do some operation...
|
* stuff(buf.get()); // do some operation...
|
||||||
* buf.get_deleter().SetConsumedSize(114514); // i only consume these bytes.
|
* buf.get_deleter().SetConsumedSize(114514); // i only consume these bytes.
|
||||||
* buf.reset(); // immediately free it.
|
* buf.reset(); // immediately free it.
|
||||||
|
@ -290,7 +302,7 @@ namespace LibCmo::CK2 {
|
||||||
* @see LockReadBuffer, UnLockReadBuffer, LockedReadBuffer_t
|
* @see LockReadBuffer, UnLockReadBuffer, LockedReadBuffer_t
|
||||||
*/
|
*/
|
||||||
LockedReadBuffer_t LockReadBufferWrapper(CKDWORD size_in_byte);
|
LockedReadBuffer_t LockReadBufferWrapper(CKDWORD size_in_byte);
|
||||||
|
|
||||||
/* ========== Basic Data Read Functions ==========*/
|
/* ========== Basic Data Read Functions ==========*/
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -379,10 +391,10 @@ namespace LibCmo::CK2 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read buffer and copy it.
|
* @brief Read buffer and copy it.
|
||||||
*
|
*
|
||||||
* The copied buffer and the size of buffer will be returned to caller.
|
* The copied buffer and the size of buffer will be returned to caller.
|
||||||
* Caller should free the buffer by calling CKStateChunk::DeleteBuffer(void*).
|
* Caller should free the buffer by calling CKStateChunk::DeleteBuffer(void*).
|
||||||
*
|
*
|
||||||
* @param ppData[out] The pointer to pointer holding the new copied data.
|
* @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.
|
* @param size_in_byte[out] Set to the size of buffer when success.
|
||||||
* @return True if success.
|
* @return True if success.
|
||||||
|
@ -407,7 +419,7 @@ namespace LibCmo::CK2 {
|
||||||
* @remark Here is a exmaple about how to use this function
|
* @remark Here is a exmaple about how to use this function
|
||||||
* ```
|
* ```
|
||||||
* Buffer_t buf = chunk->ReadBufferWrapper(114);
|
* Buffer_t buf = chunk->ReadBufferWrapper(114);
|
||||||
* if (buf) {
|
* if (buf) {
|
||||||
* stuff(buf.get(), buf.get_deleter().GetBufferSize()); // do some operation...
|
* stuff(buf.get(), buf.get_deleter().GetBufferSize()); // do some operation...
|
||||||
* buf.reset(); // immediately free it.
|
* buf.reset(); // immediately free it.
|
||||||
* }
|
* }
|
||||||
|
@ -417,9 +429,9 @@ namespace LibCmo::CK2 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read buffer and fill user struct.
|
* @brief Read buffer and fill user struct.
|
||||||
*
|
*
|
||||||
* The size of buffer will be read from CKStateChunk internally and return to caller.
|
* The size of buffer will be read from CKStateChunk internally and return to caller.
|
||||||
*
|
*
|
||||||
* @param pData[out] The pointer holding the data.
|
* @param pData[out] The pointer holding the data.
|
||||||
* @return True if success.
|
* @return True if success.
|
||||||
* @remark Following original Virtools functions can use this function to implement:
|
* @remark Following original Virtools functions can use this function to implement:
|
||||||
|
@ -430,9 +442,9 @@ namespace LibCmo::CK2 {
|
||||||
bool ReadAndFillBuffer(void* pData);
|
bool ReadAndFillBuffer(void* pData);
|
||||||
/**
|
/**
|
||||||
* @brief Read buffer and fill user struct.
|
* @brief Read buffer and fill user struct.
|
||||||
*
|
*
|
||||||
* The size of buffer is provided by user.
|
* The size of buffer is provided by user.
|
||||||
*
|
*
|
||||||
* @param pData[out] The pointer holding the data.
|
* @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
|
* @param size_in_byte[in] The size of data which you want to read in byte unit
|
||||||
* @return True if success.
|
* @return True if success.
|
||||||
|
@ -502,61 +514,122 @@ namespace LibCmo::CK2 {
|
||||||
return ReadXObjectPointerArray(&ls);
|
return ReadXObjectPointerArray(&ls);
|
||||||
}
|
}
|
||||||
|
|
||||||
//int ReadInt();
|
|
||||||
//int StartReadSequence();
|
|
||||||
//CK_ID ReadObjectID();
|
|
||||||
//CKStateChunk* ReadSubChunk();
|
|
||||||
//int StartManagerReadSequence(CKGUID* guid);
|
|
||||||
//CKGUID ReadGuid();
|
|
||||||
//void ReadAndFillBuffer_LEndian(void* buffer);
|
|
||||||
//void ReadAndFillBuffer_LEndian16(void* buffer);
|
|
||||||
//float ReadFloat();
|
|
||||||
//CKWORD ReadWord();
|
|
||||||
//CKDWORD ReadDword();
|
|
||||||
//CKDWORD ReadDwordAsWords();
|
|
||||||
//void ReadVector(VxMath::VxVector* v);
|
|
||||||
//void ReadMatrix(VxMath::VxMatrix& mat);
|
|
||||||
//CKObjectImplements::CKObject* ReadObject(CKMinContext*);
|
|
||||||
//void ReadAndFillBuffer(void* buffer);
|
|
||||||
//CKBYTE* ReadRawBitmap(VxMath::VxImageDescEx& desc);
|
|
||||||
//XObjectArray ReadXObjectArray(void);
|
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region Write Function
|
#pragma region Write Function
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void StartWrite();
|
void StartWrite();
|
||||||
//void WriteIdentifier(CKDWORD id);
|
|
||||||
//void AddChunkAndDelete(CKStateChunk*);
|
|
||||||
//void StartObjectIDSequence(int count);
|
|
||||||
//void WriteObjectSequence(CKObjectImplements::CKObject* obj);
|
|
||||||
//void WriteInt(int data);
|
|
||||||
//void WriteFloat(float data);
|
|
||||||
//void WriteDword(CKDWORD data);
|
|
||||||
//void WriteDwordAsWords(CKDWORD data);
|
|
||||||
//void WriteVector(const VxMath::VxVector* v);
|
|
||||||
//void WriteMatrix(const VxMath::VxMatrix& mat);
|
|
||||||
//void WriteObject(CKObjectImplements::CKObject* obj);
|
|
||||||
//void WriteBuffer_LEndian(int size, void* buf);
|
|
||||||
//void WriteBuffer_LEndian16(int size, void* buf);
|
|
||||||
//void WriteBufferNoSize_LEndian(int size, void* buf);
|
|
||||||
///*void UpdateDataSize();*/
|
|
||||||
//void* LockWriteBuffer(int DwordCount);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Old Name: CloseChunk();
|
* Actually this function mix various functions, including CloseChunk(), UpdateSize() and etc.
|
||||||
*/
|
*/
|
||||||
void StopWrite(void);
|
void StopWrite(void);
|
||||||
|
|
||||||
bool LockWriteBuffer(const void** ppData, CKDWORD size_in_byte);
|
|
||||||
|
/* ========== Identifier Functions ==========*/
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool WriteIdentifierDword(CKDWORD identifier);
|
||||||
|
template<typename TEnum>
|
||||||
|
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);
|
||||||
bool UnLockWriteBuffer(CKDWORD size_in_byte);
|
bool UnLockWriteBuffer(CKDWORD size_in_byte);
|
||||||
LockedWriteBuffer_t LockWriteBufferWrapper(CKDWORD size_in_byte);
|
LockedWriteBuffer_t LockWriteBufferWrapper(CKDWORD size_in_byte);
|
||||||
|
|
||||||
|
/* ========== Basic Data Write Functions ==========*/
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool WriteByteData(const void* data_ptr, CKDWORD size_in_byte);
|
||||||
|
|
||||||
|
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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
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);
|
||||||
|
inline bool ReadObjectIDSequence(const XContainer::XObjectArray& ls) {
|
||||||
|
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
|
#pragma endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,9 +209,9 @@ namespace LibCmo::CK2 {
|
||||||
CKStateChunk* subchunk = nullptr;
|
CKStateChunk* subchunk = nullptr;
|
||||||
|
|
||||||
// get size and do a enough space check
|
// get size and do a enough space check
|
||||||
CKDWORD subChunkSize;
|
CKDWORD subDwordChunkSize;
|
||||||
if (!this->ReadStruct(subChunkSize)) goto subchunk_defer;
|
if (!this->ReadStruct(subDwordChunkSize)) goto subchunk_defer;
|
||||||
if (!this->EnsureReadSpace(subChunkSize)) goto subchunk_defer;
|
if (!this->EnsureReadSpace(subDwordChunkSize)) goto subchunk_defer;
|
||||||
|
|
||||||
// create statechunk
|
// create statechunk
|
||||||
subchunk = new CKStateChunk(this->m_BindFile, this->m_BindContext);
|
subchunk = new CKStateChunk(this->m_BindFile, this->m_BindContext);
|
||||||
|
@ -502,6 +502,7 @@ namespace LibCmo::CK2 {
|
||||||
|
|
||||||
bool CKStateChunk::ReadXObjectPointerArray(XContainer::XObjectPointerArray* ls) {
|
bool CKStateChunk::ReadXObjectPointerArray(XContainer::XObjectPointerArray* ls) {
|
||||||
if (ls == nullptr) return false;
|
if (ls == nullptr) return false;
|
||||||
|
ls->clear();
|
||||||
|
|
||||||
// very very similar to ReadXObjectArray
|
// very very similar to ReadXObjectArray
|
||||||
// we execute it first.
|
// we execute it first.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "CKStateChunk.hpp"
|
#include "CKStateChunk.hpp"
|
||||||
#include "CKFile.hpp"
|
#include "CKFile.hpp"
|
||||||
#include "CKContext.hpp"
|
#include "CKContext.hpp"
|
||||||
|
#include "ObjImpls/CKObject.hpp"
|
||||||
|
|
||||||
namespace LibCmo::CK2 {
|
namespace LibCmo::CK2 {
|
||||||
|
|
||||||
|
@ -46,16 +47,179 @@ namespace LibCmo::CK2 {
|
||||||
this->m_Parser.m_Status = CKStateChunkStatus::IDLE;
|
this->m_Parser.m_Status = CKStateChunkStatus::IDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CKStateChunk::LockWriteBuffer(const void** ppData, CKDWORD size_in_byte) {
|
/* ========== Identifier Functions ==========*/
|
||||||
return false;
|
|
||||||
|
bool CKStateChunk::WriteIdentifierDword(CKDWORD identifier) {
|
||||||
|
// check self status
|
||||||
|
if (this->m_Parser.m_Status != CKStateChunkStatus::WRITE) return false;
|
||||||
|
// make sure there are 2 DWORD space for writing identifier header
|
||||||
|
if (!EnsureWriteSpace(2)) return false;
|
||||||
|
|
||||||
|
// update the last identifier header to fill its length indicator
|
||||||
|
if (m_Parser.m_PrevIdentifierPos < m_Parser.m_CurrentPos) {
|
||||||
|
m_pData[m_Parser.m_PrevIdentifierPos + 1] = m_Parser.m_CurrentPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set prev ident to this new created ident
|
||||||
|
m_Parser.m_PrevIdentifierPos = m_Parser.m_CurrentPos;
|
||||||
|
// write identifier and set default next ident data
|
||||||
|
m_pData[m_Parser.m_CurrentPos++] = identifier;
|
||||||
|
m_pData[m_Parser.m_CurrentPos++] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== Write Buffer Controller ==========*/
|
||||||
|
|
||||||
|
bool CKStateChunk::LockWriteBuffer(void** ppData, CKDWORD size_in_byte) {
|
||||||
|
// same as LockReadBuffer with slight difference.
|
||||||
|
if (this->m_Parser.m_Status != CKStateChunkStatus::WRITE) return false;
|
||||||
|
if (*ppData == nullptr) return false;
|
||||||
|
*ppData = nullptr;
|
||||||
|
|
||||||
|
CKDWORD size_in_dword = this->GetCeilDwordSize(size_in_byte);
|
||||||
|
if (this->EnsureWriteSpace(size_in_dword)) {
|
||||||
|
*ppData = this->m_pData + this->m_Parser.m_CurrentPos;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
m_BindContext->OutputToConsoleEx("CKStateChunk::LockWriteBuffer at buffer pos %" PRIuCKDWORD ".", this->m_Parser.m_CurrentPos);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CKStateChunk::UnLockWriteBuffer(CKDWORD size_in_byte) {
|
bool CKStateChunk::UnLockWriteBuffer(CKDWORD size_in_byte) {
|
||||||
return false;
|
// same as UnLockReadBuffer with slight difference.
|
||||||
|
if (this->m_Parser.m_Status != CKStateChunkStatus::WRITE) return false;
|
||||||
|
|
||||||
|
CKDWORD size_in_dword = this->GetCeilDwordSize(size_in_byte);
|
||||||
|
if (this->EnsureWriteSpace(size_in_dword)) {
|
||||||
|
this->m_Parser.m_CurrentPos += size_in_dword;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
m_BindContext->OutputToConsoleEx("CKStateChunk::UnLockWriteBuffer at buffer pos %" PRIuCKDWORD ".", this->m_Parser.m_CurrentPos);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CKStateChunk::LockedWriteBuffer_t CKStateChunk::LockWriteBufferWrapper(CKDWORD size_in_byte) {
|
CKStateChunk::LockedWriteBuffer_t CKStateChunk::LockWriteBufferWrapper(CKDWORD size_in_byte) {
|
||||||
return LockedWriteBuffer_t();
|
// same as LockReadBufferWrapper with slight difference.
|
||||||
|
void* pData;
|
||||||
|
bool ret = LockWriteBuffer(&pData, size_in_byte);
|
||||||
|
if (ret) {
|
||||||
|
return LockedWriteBuffer_t(pData, LockedWriteBufferDeleter(this, size_in_byte));
|
||||||
|
} else {
|
||||||
|
return LockedWriteBuffer_t();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== Basic Data Write Functions ==========*/
|
||||||
|
|
||||||
|
bool CKStateChunk::WriteByteData(const void* data_ptr, CKDWORD size_in_byte) {
|
||||||
|
// same as ReadByteData with slight difference.
|
||||||
|
if (data_ptr == nullptr) return false;
|
||||||
|
|
||||||
|
void* pData;
|
||||||
|
bool ret = LockWriteBuffer(&pData, size_in_byte);
|
||||||
|
if (ret) {
|
||||||
|
std::memcpy(pData, data_ptr, size_in_byte);
|
||||||
|
UnLockWriteBuffer(size_in_byte);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::WriteString(const XContainer::XString* strl) {
|
||||||
|
if (strl == nullptr) return;
|
||||||
|
|
||||||
|
// convert encoding
|
||||||
|
XContainer::XString cache;
|
||||||
|
m_BindContext->GetNativeString(*strl, cache);
|
||||||
|
|
||||||
|
// get size
|
||||||
|
CKDWORD strByteSize = static_cast<CKDWORD>(cache.size());
|
||||||
|
if (!this->WriteStruct(strByteSize)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write data
|
||||||
|
if (!this->WriteByteData(cache.c_str(), strByteSize)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::WriteObjectID(const CK_ID* id) {
|
||||||
|
// MARK: if BindFile is not nullptr, no need to push this obj into obj list according to IDA code.
|
||||||
|
// but we assume BindFile always it not nullptr, so I remove that pushing code.
|
||||||
|
return this->WriteStruct(m_BindFile->GetIndexByObjectID(*id));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::WriteObjectPointer(ObjImpls::CKObject* obj) {
|
||||||
|
CK_ID objid;
|
||||||
|
if (obj != nullptr) {
|
||||||
|
objid = obj->GetID();
|
||||||
|
}
|
||||||
|
|
||||||
|
return WriteObjectID(objid);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::WriteManagerInt(const CKGUID* guid, CKINT intval) {
|
||||||
|
// push into manager list
|
||||||
|
m_ManagerList.emplace_back(m_Parser.m_CurrentPos);
|
||||||
|
// write data
|
||||||
|
if (!this->WriteStruct(guid)) return false;
|
||||||
|
if (!this->WriteStruct(intval)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== Buffer Functions ==========*/
|
||||||
|
|
||||||
|
bool CKStateChunk::WriteBuffer(const void* buf, CKDWORD size_in_byte) {
|
||||||
|
if (buf != nullptr) {
|
||||||
|
// write size
|
||||||
|
if (!this->WriteStruct(size_in_byte)) return false;
|
||||||
|
// write data
|
||||||
|
auto locker = LockWriteBufferWrapper(size_in_byte);
|
||||||
|
if (locker == nullptr) return false;
|
||||||
|
std::memcpy(locker.get(), buf, size_in_byte);
|
||||||
|
locker.reset();
|
||||||
|
} else {
|
||||||
|
// write blank data
|
||||||
|
if (!this->WriteStruct(0)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::WriteBufferNoSize(const void* buf, CKDWORD size_in_byte) {
|
||||||
|
if (buf != nullptr) {
|
||||||
|
// write data
|
||||||
|
auto locker = LockWriteBufferWrapper(size_in_byte);
|
||||||
|
if (locker == nullptr) return false;
|
||||||
|
std::memcpy(locker.get(), buf, size_in_byte);
|
||||||
|
locker.reset();
|
||||||
|
}
|
||||||
|
// if nosize buffer is nullptr, nothing need to write.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== Sequence Functions ==========*/
|
||||||
|
|
||||||
|
bool CKStateChunk::WriteObjectIDSequence(const XContainer::XObjectArray* ls) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::WriteManagerIntSequence(const CKGUID* guid, const XContainer::XArray<CKINT>* ls) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::WriteXObjectArray(const XContainer::XObjectArray* ls) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::WriteXObjectPointerArray(const XContainer::XObjectPointerArray* ls) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user