From bf0fca756b5cc1c5fd7e44a2f1ec50fae80ada5a Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Sun, 5 Mar 2023 22:31:11 +0800 Subject: [PATCH] write CKStateChunk --- LibCmo/CKFileReader.cpp | 12 +- LibCmo/CKObjectImplements/CKObject.cpp | 4 +- LibCmo/CKObjects.hpp | 2 +- LibCmo/CKStateChunk.cpp | 152 +++++++++++++++++-------- LibCmo/CKStateChunk.hpp | 138 +++++++++++++++------- 5 files changed, 212 insertions(+), 96 deletions(-) diff --git a/LibCmo/CKFileReader.cpp b/LibCmo/CKFileReader.cpp index 901c1fa..fc12847 100644 --- a/LibCmo/CKFileReader.cpp +++ b/LibCmo/CKFileReader.cpp @@ -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; } } diff --git a/LibCmo/CKObjectImplements/CKObject.cpp b/LibCmo/CKObjectImplements/CKObject.cpp index 69f9b05..6a2edec 100644 --- a/LibCmo/CKObjectImplements/CKObject.cpp +++ b/LibCmo/CKObjectImplements/CKObject.cpp @@ -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; diff --git a/LibCmo/CKObjects.hpp b/LibCmo/CKObjects.hpp index 0c31693..7984b76 100644 --- a/LibCmo/CKObjects.hpp +++ b/LibCmo/CKObjects.hpp @@ -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); }; diff --git a/LibCmo/CKStateChunk.cpp b/LibCmo/CKStateChunk.cpp index 8f367f2..422ecd9 100644 --- a/LibCmo/CKStateChunk.cpp +++ b/LibCmo/CKStateChunk.cpp @@ -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(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 diff --git a/LibCmo/CKStateChunk.hpp b/LibCmo/CKStateChunk.hpp index 9bfbbf5..310adfe 100644 --- a/LibCmo/CKStateChunk.hpp +++ b/LibCmo/CKStateChunk.hpp @@ -39,29 +39,42 @@ namespace LibCmo::CK2 { std::vector m_ChunkList; std::vector 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 @@ -73,44 +86,90 @@ namespace LibCmo::CK2 { return SeekIdentifierDwordAndReturnSize(static_cast(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: + /// + /// The base read function for all data. + /// This function will check all read requirements. + /// If you have use this function or functions calling this function. You do not need check any reading requirements anymore + /// + /// the pointer to data. must be allocated first. + /// the size of data in byte. + /// + bool ReadByteData(void* data_ptr, CKDWORD size_in_byte); + public: + /// + /// Read Struct + /// Primitive type: ReadInt, ReadByte, ReadWord, ReadDword, ReadFloat, etc... + /// Struct type: ReadGuid, ReadVector, ReadMatrix, etc... + /// Both of them are redirected to this. + /// + /// + /// + /// template - CKERROR ReadStructPtr(T* data) { - size_t size = GetCeilDwordSize(sizeof(T)); - if (EnsureReadSpace(static_cast(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(sizeof(T))); } - /* - * Read Struct - A wrapper for ReadStructPtr. - Use reference, not pointer. - */ + /// + /// Read Struct + /// A wrapper for ReadStructPtr. + /// Use reference, not pointer. + /// + /// + /// + /// template - inline CKERROR ReadStructRef(T& data) { - return ReadStructPtr(&data); + inline bool ReadStruct(T& data) { + return ReadByteData(&data, static_cast(sizeof(T))); } - ///* - //* Read Enum Data - //A wrapper for ReadStructPtr. - //All Enum read redirect to this. - //*/ - //template - //inline CKERROR ReadEnum(T& data) { - // return ReadStructPtr(reinterpret_cast*>(&data)); - //} - CKERROR ReadString(std::string& strl); + /// + /// Read string + /// + /// + /// + 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. + */ + + /// + /// Read a buffer with unknow size (order user specific it). + /// ReadAndFillBuffer(int, void*), ReadAndFillBuffer_LEndian(int, void*), ReadAndFillBuffer_LEndian16(int, void*) are redirected to this. + /// The buffer should be allocated by caller first. + /// + /// + /// + /// + bool ReadNoSizeBuffer(CKDWORD size_in_byte, void* allocatedBuf); + /// + /// Read a buffer with knowen size stored in chunk. + /// ReadBuffer(void**), ReadAndFillBuffer(void*), ReadAndFillBuffer_LEndian(void*), ReadAndFillBuffer_LEndian16(void*) are redirected to this. + /// The buffer will be allocated by function. + /// Use CKStateChunk::DeleteBuffer() to delete it. + /// + /// a pointer to the pointer receiving data start address. + /// a pointer to the variable receiving the length of gotten buffer. + /// + 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