write CKStateChunk

This commit is contained in:
yyc12345 2023-03-05 22:31:11 +08:00
parent 5a69ce338e
commit bf0fca756b
5 changed files with 212 additions and 96 deletions

View File

@ -387,16 +387,16 @@ namespace LibCmo::CK2 {
// todo: special treat for CK_LEVEL
// try parsing data
obj.Data->StartRead();
err = obj.ObjPtr->Load(obj.Data, deepDoc.get());
bool success = obj.ObjPtr->Load(obj.Data, deepDoc.get());
obj.Data->StopRead();
if (err != CKERROR::CKERR_OK) {
// if failed, delete it
m_MinCtx->DestroyCKObject(obj.ObjectId);
obj.ObjPtr = nullptr;
} else {
if (success) {
// if success, clear CKStateChunk*
delete obj.Data;
obj.Data = nullptr;
} else {
// if failed, delete it
m_MinCtx->DestroyCKObject(obj.ObjectId);
obj.ObjPtr = nullptr;
}
}

View File

@ -16,7 +16,7 @@ namespace LibCmo::CK2::CKObjectImplements {
}
CKERROR CKObject::Load(CKStateChunk* chunk, const CKFileDocument* doc) {
bool CKObject::Load(CKStateChunk* chunk, const CKFileDocument* doc) {
if (chunk->SeekIdentifier(Identifiers::CK_STATESAVEFLAGS_OBJECT::CK_STATESAVE_OBJECTHIDDEN)) {
EnumsHelper::FlagEnumRm(this->m_ObjectFlags,
{ CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE,
@ -43,7 +43,7 @@ namespace LibCmo::CK2::CKObjectImplements {
}
}
return CKERROR::CKERR_OK;
return true;
}
CKStateChunk* CKObject::Save(const CKFileDocument* doc) {
return nullptr;

View File

@ -25,7 +25,7 @@ namespace LibCmo::CK2::CKObjectImplements {
void SetObjectFlags(CK_OBJECT_FLAGS flags) { this->m_ObjectFlags = flags; }
virtual CK_CLASSID GetClassID(void) { return CK_CLASSID::CKCID_OBJECT; }
virtual CKERROR Load(CKStateChunk* chunk, const CKFileDocument* doc);
virtual bool Load(CKStateChunk* chunk, const CKFileDocument* doc);
virtual CKStateChunk* Save(const CKFileDocument* doc);
};

View File

@ -91,9 +91,37 @@ namespace LibCmo::CK2 {
this->m_DataVersion = version;
}
bool CKStateChunk::EnsureReadSpace(CKDWORD dword_required) {
return (m_Parser.m_Status == CKStateChunkStatus::READ) &&
(this->m_Parser.m_CurrentPos + dword_required <= this->m_Parser.m_DataSize);
void CKStateChunk::DeleteBuffer(void* buf) {
if (buf == nullptr) return;
delete[] reinterpret_cast<char*>(buf);
}
bool CKStateChunk::Skip(CKDWORD DwordCount) {
bool result;
switch (this->m_Parser.m_Status) {
case CKStateChunkStatus::READ:
result = EnsureReadSpace(DwordCount);
break;
case CKStateChunkStatus::WRITE:
result = EnsureWriteSpace(DwordCount);
break;
case CKStateChunkStatus::IDLE:
default:
result = false;
break;
}
// if success, move cursor
if (result) {
this->m_Parser.m_CurrentPos += DwordCount;
}
return result;
}
size_t CKStateChunk::GetCeilDwordSize(size_t char_size) {
return (char_size + 3) >> 3;
}
bool CKStateChunk::ResizeBuffer(CKDWORD new_dwsize) {
@ -141,26 +169,9 @@ namespace LibCmo::CK2 {
return true;
}
bool CKStateChunk::Skip(CKDWORD DwordCount) {
bool result;
switch (this->m_Parser.m_Status) {
case CKStateChunkStatus::READ:
result = EnsureReadSpace(DwordCount);
break;
case CKStateChunkStatus::WRITE:
result = EnsureWriteSpace(DwordCount);
break;
case CKStateChunkStatus::IDLE:
default:
result = false;
break;
}
// if success, move cursor
if (result) {
this->m_Parser.m_CurrentPos += DwordCount;
}
return result;
bool CKStateChunk::EnsureReadSpace(CKDWORD dword_required) {
return (m_Parser.m_Status == CKStateChunkStatus::READ) &&
(this->m_Parser.m_CurrentPos + dword_required <= this->m_Parser.m_DataSize);
}
@ -344,6 +355,17 @@ namespace LibCmo::CK2 {
this->m_Parser.m_Status = CKStateChunkStatus::READ;
}
void CKStateChunk::StopRead(void) {
if (this->m_Parser.m_Status != CKStateChunkStatus::READ) return;
this->m_Parser.m_CurrentPos = 0u;
this->m_Parser.m_DataSize = this->m_DataDwSize;
this->m_Parser.m_PrevIdentifierPos = 0u;
this->m_Parser.m_Status = CKStateChunkStatus::IDLE;
}
/* ========== Identifier Functions ==========*/
bool CKStateChunk::SeekIdentifierDword(CKDWORD identifier) {
CKDWORD cache;
return SeekIdentifierDwordAndReturnSize(identifier, &cache);
@ -376,38 +398,74 @@ namespace LibCmo::CK2 {
return true;
}
CKERROR CKStateChunk::ReadString(std::string& strl) {
/* ========== Basic Data Read Functions ==========*/
bool CKStateChunk::ReadByteData(void* data_ptr, CKDWORD size_in_byte) {
if (this->m_Parser.m_Status != CKStateChunkStatus::READ) return false;
if (data_ptr == nullptr) return false;
CKDWORD size_in_dword = this->GetCeilDwordSize(size_in_byte);
if (this->EnsureReadSpace(size_in_dword)) {
std::memcpy(data_ptr, this->m_pData + this->m_Parser.m_CurrentPos, size_in_byte);
return true;
} else return false;
}
bool CKStateChunk::ReadString(std::string* strl) {
if (strl == nullptr) return false;
// get byte based size
CKDWORD strByteSize = 0u;
CKERROR err = this->ReadStructPtr(&strByteSize);
if (err != CKERROR::CKERR_OK) {
strl.clear();
return err;
if (!this->ReadStruct(strByteSize)) {
strl->clear();
return false;
}
// convert to DWORD based
CKDWORD strDwordSize = this->GetCeilDwordSize(strByteSize);
// cp
if (this->EnsureReadSpace(strDwordSize)) {
strl.resize(strByteSize);
std::memcpy(strl.data(), this->m_pData + this->m_Parser.m_CurrentPos, strByteSize);
this->m_Parser.m_CurrentPos += strDwordSize;
} else strl.clear();
return CKERROR::CKERR_OK;
// read data
strl->resize(strByteSize);
if (!this->ReadByteData(strl->data(), strByteSize)) {
strl->clear();
return false;
}
return true;
}
void CKStateChunk::StopRead(void) {
if (this->m_Parser.m_Status != CKStateChunkStatus::READ) return;
this->m_Parser.m_CurrentPos = 0u;
this->m_Parser.m_DataSize = this->m_DataDwSize;
this->m_Parser.m_PrevIdentifierPos = 0u;
this->m_Parser.m_Status = CKStateChunkStatus::IDLE;
bool CKStateChunk::ReadNoSizeBuffer(CKDWORD size_in_byte, void* allocatedBuf) {
if (allocatedBuf == nullptr) return false;
return this->ReadByteData(allocatedBuf, size_in_byte);
}
bool CKStateChunk::ReadBuffer(void** buf, CKDWORD* len_in_byte) {
if (buf == nullptr || len_in_byte == nullptr) return false;
// get buffer size.
CKDWORD bufByteSize = 0u;
if (!this->ReadStruct(bufByteSize)) {
*buf = nullptr;
*len_in_byte = 0;
return false;
}
*len_in_byte = bufByteSize;
// create buffer
*buf = new(std::nothrow) char[bufByteSize];
if (*buf == nullptr) {
*len_in_byte = 0;
return false;
}
// read data
if (!this->ReadByteData(*buf, bufByteSize)) {
this->DeleteBuffer(*buf);
*buf = nullptr;
*len_in_byte = 0;
return false;
}
return true;
}
#pragma endregion

View File

@ -39,29 +39,42 @@ namespace LibCmo::CK2 {
std::vector<CKDWORD> m_ChunkList;
std::vector<CKDWORD> m_ManagerList;
private:
inline size_t GetCeilDwordSize(size_t char_size) {
return (char_size + 3) >> 3;
}
bool ResizeBuffer(CKDWORD new_dwsize);
bool EnsureWriteSpace(CKDWORD dwsize);
bool EnsureReadSpace(CKDWORD dword_required);
#pragma region Buffer Related
public:
bool ConvertFromBuffer(const void* buf);
CKDWORD ConvertToBuffer(void* buf);
#pragma endregion
#pragma region Misc Functions
public:
//bool UnPack(CKDWORD DestSize);
void Clear(void);
CKDWORD GetDataSize(void);
CK_STATECHUNK_DATAVERSION GetDataVersion();
void SetDataVersion(CK_STATECHUNK_DATAVERSION version);
void DeleteBuffer(void* buf);
bool Skip(CKDWORD DwordCount);
private:
size_t GetCeilDwordSize(size_t char_size);
bool ResizeBuffer(CKDWORD new_dwsize);
bool EnsureWriteSpace(CKDWORD dwsize);
bool EnsureReadSpace(CKDWORD dword_required);
#pragma endregion
#pragma region Read Function
public:
void StartRead(void);
void StopRead(void);
/* ========== Identifier Functions ==========*/
bool SeekIdentifierDword(CKDWORD identifier);
bool SeekIdentifierDwordAndReturnSize(CKDWORD identifier, CKDWORD* out_size);
template<typename TEnum>
@ -73,44 +86,90 @@ namespace LibCmo::CK2 {
return SeekIdentifierDwordAndReturnSize(static_cast<CKDWORD>(enum_v), out_size);
}
/*
* Read Struct
Primitive type: ReadInt, ReadByte, ReadWord, ReadDword, ReadFloat, etc...
Struct type: ReadGuid, ReadVector, ReadMatrix, etc...
Both of them are redirected to this.
*/
/* ========== Basic Data Read Functions ==========*/
private:
/// <summary>
/// The base read function for all data.
/// <para>This function will check all read requirements.</para>
/// <para>If you have use this function or functions calling this function. You do not need check any reading requirements anymore</para>
/// </summary>
/// <param name="data_ptr">the pointer to data. must be allocated first.</param>
/// <param name="size_in_byte">the size of data in byte.</param>
/// <returns></returns>
bool ReadByteData(void* data_ptr, CKDWORD size_in_byte);
public:
/// <summary>
/// Read Struct
/// <para>Primitive type: ReadInt, ReadByte, ReadWord, ReadDword, ReadFloat, etc...</para>
/// <para>Struct type: ReadGuid, ReadVector, ReadMatrix, etc...</para>
/// <para>Both of them are redirected to this.</para>
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <returns></returns>
template<typename T>
CKERROR ReadStructPtr(T* data) {
size_t size = GetCeilDwordSize(sizeof(T));
if (EnsureReadSpace(static_cast<CKDWORD>(size))) {
std::memcpy(data, this->m_pData + this->m_Parser.m_CurrentPos, size);
} else return CKERROR::CKERR_OUTOFMEMORY;
return CKERROR::CKERR_OK;
bool ReadStruct(T* data) {
return ReadByteData(data, static_cast<CKDWORD>(sizeof(T)));
}
/*
* Read Struct
A wrapper for ReadStructPtr.
Use reference, not pointer.
*/
/// <summary>
/// Read Struct
/// <para>A wrapper for ReadStructPtr.</para>
/// <para>Use reference, not pointer.</para>
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <returns></returns>
template<typename T>
inline CKERROR ReadStructRef(T& data) {
return ReadStructPtr(&data);
inline bool ReadStruct(T& data) {
return ReadByteData(&data, static_cast<CKDWORD>(sizeof(T)));
}
///*
//* Read Enum Data
//A wrapper for ReadStructPtr.
//All Enum read redirect to this.
//*/
//template<typename T>
//inline CKERROR ReadEnum(T& data) {
// return ReadStructPtr(reinterpret_cast<std::underlying_type_t<T>*>(&data));
//}
CKERROR ReadString(std::string& strl);
/// <summary>
/// Read string
/// </summary>
/// <param name="strl"></param>
/// <returns></returns>
bool ReadString(std::string* strl);
inline bool ReadString(std::string& strl) {
return ReadString(&strl);
}
CKERROR ReadBuffer(void* allocatedBuf);
CKERROR ReadNoSizeBuffer(CKDWORD size, void* allocatedBuf);
/* ========== Buffer Functions ==========*/
/*
Buffer related function implements:
ReadBuffer(void**) Read Byte based size.
ReadAndFillBuffer(int, void*) User give Byte based size.
ReadAndFillBuffer(void*) Read Byte based size.
ReadAndFillBuffer_LEndian(int, void*) User give Byte based size.
ReadAndFillBuffer_LEndian(void*) Read Byte based size.
ReadAndFillBuffer_LEndian16(int, void*) User give Byte based size.
ReadAndFillBuffer_LEndian16(void*) Read Byte based size.
*/
/// <summary>
/// Read a buffer with unknow size (order user specific it).
/// <para>ReadAndFillBuffer(int, void*), ReadAndFillBuffer_LEndian(int, void*), ReadAndFillBuffer_LEndian16(int, void*) are redirected to this.</para>
/// <para>The buffer should be allocated by caller first.</para>
/// </summary>
/// <param name="size"></param>
/// <param name="allocatedBuf"></param>
/// <returns></returns>
bool ReadNoSizeBuffer(CKDWORD size_in_byte, void* allocatedBuf);
/// <summary>
/// Read a buffer with knowen size stored in chunk.
/// <para>ReadBuffer(void**), ReadAndFillBuffer(void*), ReadAndFillBuffer_LEndian(void*), ReadAndFillBuffer_LEndian16(void*) are redirected to this.</para>
/// <para>The buffer will be allocated by function.</para>
/// <para>Use CKStateChunk::DeleteBuffer() to delete it.</para>
/// </summary>
/// <param name="buf">a pointer to the pointer receiving data start address.</param>
/// <param name="len">a pointer to the variable receiving the length of gotten buffer.</param>
/// <returns></returns>
bool ReadBuffer(void** buf, CKDWORD* len_in_byte);
/* ========== Sequence Functions ==========*/
//int ReadInt();
//int StartReadSequence();
@ -130,7 +189,6 @@ namespace LibCmo::CK2 {
//void ReadAndFillBuffer(void* buffer);
//CKBYTE* ReadRawBitmap(VxMath::VxImageDescEx& desc);
//XObjectArray ReadXObjectArray(void);
void StopRead(void);
#pragma endregion