diff --git a/LibCmo/CK2/CKFileOthers.cpp b/LibCmo/CK2/CKFileOthers.cpp index 29ebce8..4385d8d 100644 --- a/LibCmo/CK2/CKFileOthers.cpp +++ b/LibCmo/CK2/CKFileOthers.cpp @@ -326,7 +326,7 @@ namespace LibCmo::CK2 { CKDWORD CKFileVisitor::GetIndexByObjectID(CK_ID objid) { // see CKFile::SaveFindObjectIndex in IDA - CKDWORD idx = -1; + CKDWORD idx = static_cast(-1); if (m_IsReader) return idx; auto finder = m_Writer->m_ObjectsHashTable.find(objid); diff --git a/LibCmo/CK2/CKStateChunk.hpp b/LibCmo/CK2/CKStateChunk.hpp index 5dc4fd6..dc9d125 100644 --- a/LibCmo/CK2/CKStateChunk.hpp +++ b/LibCmo/CK2/CKStateChunk.hpp @@ -232,6 +232,29 @@ namespace LibCmo::CK2 { */ bool EnsureReadSpace(CKDWORD dword_required); + /** + * @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& 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& entry_ls, CKDWORD pos); + #pragma endregion #pragma region Read Function @@ -368,12 +391,12 @@ namespace LibCmo::CK2 { return ReadManagerInt(&guid, &intval); } - /** - * @brief Read sub chunk - * @return Returned a new created of CKStateChunk if success, otherwise nullptr. - * Returned CKStateChunk should be manually released! - */ - CKStateChunk* ReadSubChunk(); + ///** + // * @brief Read sub chunk + // * @return Returned a new created of CKStateChunk if success, otherwise nullptr. + // * Returned CKStateChunk should be manually released! + //*/ + //CKStateChunk* ReadSubChunk(); /* ========== Buffer Functions ==========*/ @@ -480,17 +503,17 @@ namespace LibCmo::CK2 { return ReadManagerIntSequence(&guid, &ls); } - /// - /// Read Sub Chunk Sequence - /// The combination using of StartReadSequence() and ReadSubChunk() redirect to this. - /// The item of returned CKStateChunk* list should be manually released! - /// - /// - /// - bool ReadSubChunkSequence(XContainer::XArray* ls); - inline bool ReadSubChunkSequence(XContainer::XArray& ls) { - return ReadSubChunkSequence(&ls); - } + ///// + ///// Read Sub Chunk Sequence + ///// The combination using of StartReadSequence() and ReadSubChunk() redirect to this. + ///// The item of returned CKStateChunk* list should be manually released! + ///// + ///// + ///// + //bool ReadSubChunkSequence(XContainer::XArray* ls); + //inline bool ReadSubChunkSequence(XContainer::XArray& ls) { + // return ReadSubChunkSequence(&ls); + //} /** * @brief Read Object Array (actually still is CK_ID) @@ -601,7 +624,7 @@ namespace LibCmo::CK2 { public: bool WriteObjectIDSequence(const XContainer::XObjectArray* ls); - inline bool ReadObjectIDSequence(const XContainer::XObjectArray& ls) { + inline bool WriteObjectIDSequence(const XContainer::XObjectArray& ls) { return WriteObjectIDSequence(&ls); } diff --git a/LibCmo/CK2/CKStateChunkOthers.cpp b/LibCmo/CK2/CKStateChunkOthers.cpp index d4920af..e494d28 100644 --- a/LibCmo/CK2/CKStateChunkOthers.cpp +++ b/LibCmo/CK2/CKStateChunkOthers.cpp @@ -303,6 +303,14 @@ namespace LibCmo::CK2 { (this->m_Parser.m_CurrentPos + dword_required <= this->m_Parser.m_DataSize); } + void CKStateChunk::AddEntry(XContainer::XArray& entry_ls, CKDWORD pos) { + entry_ls.emplace_back(pos); + } + + void CKStateChunk::AddEntries(XContainer::XArray& entry_ls, CKDWORD pos) { + entry_ls.emplace_back(static_cast(-1)); + entry_ls.emplace_back(pos); + } #pragma endregion diff --git a/LibCmo/CK2/CKStateChunkReader.cpp b/LibCmo/CK2/CKStateChunkReader.cpp index 8171516..b1d69a4 100644 --- a/LibCmo/CK2/CKStateChunkReader.cpp +++ b/LibCmo/CK2/CKStateChunkReader.cpp @@ -205,98 +205,98 @@ namespace LibCmo::CK2 { return true; } - CKStateChunk* CKStateChunk::ReadSubChunk(void) { - CKStateChunk* subchunk = nullptr; + //CKStateChunk* CKStateChunk::ReadSubChunk(void) { + // CKStateChunk* subchunk = nullptr; - // get size and do a enough space check - CKDWORD subDwordChunkSize; - if (!this->ReadStruct(subDwordChunkSize)) goto subchunk_defer; - if (!this->EnsureReadSpace(subDwordChunkSize)) goto subchunk_defer; + // // get size and do a enough space check + // CKDWORD subDwordChunkSize; + // if (!this->ReadStruct(subDwordChunkSize)) goto subchunk_defer; + // if (!this->EnsureReadSpace(subDwordChunkSize)) goto subchunk_defer; - // create statechunk - subchunk = new CKStateChunk(this->m_BindFile, this->m_BindContext); + // // create statechunk + // subchunk = new CKStateChunk(this->m_BindFile, this->m_BindContext); - // start read data - // read class id - if (!this->ReadStruct(subchunk->m_ClassId)) goto subchunk_defer; + // // start read data + // // read class id + // if (!this->ReadStruct(subchunk->m_ClassId)) goto subchunk_defer; - // different read strategy by chunk version - if (this->m_ChunkVersion >= CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION1) { - // new file + // // different read strategy by chunk version + // if (this->m_ChunkVersion >= CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION1) { + // // new file - // read combined version - CKDWORD versionInfo; - if (!this->ReadStruct(versionInfo)) goto subchunk_defer; - subchunk->m_DataVersion = static_cast(versionInfo & 0xffff); - subchunk->m_ChunkVersion = static_cast((versionInfo >> 16) & 0xffff); + // // read combined version + // CKDWORD versionInfo; + // if (!this->ReadStruct(versionInfo)) goto subchunk_defer; + // subchunk->m_DataVersion = static_cast(versionInfo & 0xffff); + // subchunk->m_ChunkVersion = static_cast((versionInfo >> 16) & 0xffff); - // read data size and create it - if (!this->ReadStruct(subchunk->m_DataDwSize)) goto subchunk_defer; - subchunk->m_pData = new CKDWORD[subchunk->m_DataDwSize]; + // // read data size and create it + // if (!this->ReadStruct(subchunk->m_DataDwSize)) goto subchunk_defer; + // subchunk->m_pData = new CKDWORD[subchunk->m_DataDwSize]; - // has bind file? - CKDWORD hasBindFile; - if (!this->ReadStruct(hasBindFile)) goto subchunk_defer; - if (hasBindFile == 1) subchunk->m_BindFile = nullptr; + // // has bind file? + // CKDWORD hasBindFile; + // if (!this->ReadStruct(hasBindFile)) goto subchunk_defer; + // if (hasBindFile == 1) subchunk->m_BindFile = nullptr; - // 3 list size - // manager only existed when ver > 4 - CKDWORD lssize; - if (!this->ReadStruct(lssize)) goto subchunk_defer; - subchunk->m_ObjectList.resize(lssize); - if (!this->ReadStruct(lssize)) goto subchunk_defer; - subchunk->m_ChunkList.resize(lssize); - if (this->m_ChunkVersion > CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION1) { - if (!this->ReadStruct(lssize)) goto subchunk_defer; - subchunk->m_ManagerList.resize(lssize); - } + // // 3 list size + // // manager only existed when ver > 4 + // CKDWORD lssize; + // if (!this->ReadStruct(lssize)) goto subchunk_defer; + // subchunk->m_ObjectList.resize(lssize); + // if (!this->ReadStruct(lssize)) goto subchunk_defer; + // subchunk->m_ChunkList.resize(lssize); + // if (this->m_ChunkVersion > CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION1) { + // if (!this->ReadStruct(lssize)) goto subchunk_defer; + // subchunk->m_ManagerList.resize(lssize); + // } - // core data - if (subchunk->m_DataDwSize != 0) { - if (!this->ReadByteData(subchunk->m_pData, subchunk->m_DataDwSize * CKSizeof(CKDWORD))) goto subchunk_defer; - } + // // core data + // if (subchunk->m_DataDwSize != 0) { + // if (!this->ReadByteData(subchunk->m_pData, subchunk->m_DataDwSize * CKSizeof(CKDWORD))) goto subchunk_defer; + // } - // 3 list data - if (!subchunk->m_ObjectList.empty()) { - if (!this->ReadByteData( - subchunk->m_ObjectList.data(), - static_cast(subchunk->m_ObjectList.size()) * CKSizeof(CKDWORD) - )) goto subchunk_defer; - } - if (!subchunk->m_ChunkList.empty()) { - if (!this->ReadByteData( - subchunk->m_ChunkList.data(), - static_cast(subchunk->m_ChunkList.size()) * CKSizeof(CKDWORD) - )) goto subchunk_defer; - } - if (!subchunk->m_ManagerList.empty()) { - if (!this->ReadByteData( - subchunk->m_ManagerList.data(), - static_cast(subchunk->m_ManagerList.size()) * CKSizeof(CKDWORD) - )) goto subchunk_defer; - } + // // 3 list data + // if (!subchunk->m_ObjectList.empty()) { + // if (!this->ReadByteData( + // subchunk->m_ObjectList.data(), + // static_cast(subchunk->m_ObjectList.size()) * CKSizeof(CKDWORD) + // )) goto subchunk_defer; + // } + // if (!subchunk->m_ChunkList.empty()) { + // if (!this->ReadByteData( + // subchunk->m_ChunkList.data(), + // static_cast(subchunk->m_ChunkList.size()) * CKSizeof(CKDWORD) + // )) goto subchunk_defer; + // } + // if (!subchunk->m_ManagerList.empty()) { + // if (!this->ReadByteData( + // subchunk->m_ManagerList.data(), + // static_cast(subchunk->m_ManagerList.size()) * CKSizeof(CKDWORD) + // )) goto subchunk_defer; + // } - } else { - // old file + // } else { + // // old file - // read data size and create it - if (!this->ReadStruct(subchunk->m_DataDwSize)) goto subchunk_defer; - subchunk->m_pData = new CKDWORD[subchunk->m_DataDwSize]; + // // read data size and create it + // if (!this->ReadStruct(subchunk->m_DataDwSize)) goto subchunk_defer; + // subchunk->m_pData = new CKDWORD[subchunk->m_DataDwSize]; - // skip one? - // I don't know why - this->Skip(1u); + // // skip one? + // // I don't know why + // this->Skip(1u); - // read core buf - if (!this->ReadByteData(subchunk->m_pData, subchunk->m_DataDwSize * CKSizeof(CKDWORD))) goto subchunk_defer; + // // read core buf + // if (!this->ReadByteData(subchunk->m_pData, subchunk->m_DataDwSize * CKSizeof(CKDWORD))) goto subchunk_defer; - } + // } - return subchunk; - subchunk_defer: - if (subchunk != nullptr) delete subchunk; - return nullptr; - } + // return subchunk; + //subchunk_defer: + // if (subchunk != nullptr) delete subchunk; + // return nullptr; + //} /* ========== Buffer Functions ==========*/ @@ -427,38 +427,38 @@ namespace LibCmo::CK2 { return true; } - bool CKStateChunk::ReadSubChunkSequence(XContainer::XArray* ls) { - if (ls == nullptr) return false; + //bool CKStateChunk::ReadSubChunkSequence(XContainer::XArray* ls) { + // if (ls == nullptr) return false; - // clear first - for (auto& item : *ls) { - if (item != nullptr) - delete (item); - } - ls->clear(); + // // clear first + // for (auto& item : *ls) { + // if (item != nullptr) + // delete (item); + // } + // ls->clear(); - // read count - CKDWORD count; - if (!this->ReadStruct(count)) return false; + // // read count + // CKDWORD count; + // if (!this->ReadStruct(count)) return false; - // resize list and read it - ls->resize(count, nullptr); - for (size_t i = 0; i < count; ++i) { - (*ls)[i] = this->ReadSubChunk(); - if ((*ls)[i] == nullptr) { - // fail. remove all created statechunk and clear it - for (auto& item : *ls) { - if (item != nullptr) - delete (item); - } - ls->clear(); - // return - return false; - } - } + // // resize list and read it + // ls->resize(count, nullptr); + // for (size_t i = 0; i < count; ++i) { + // (*ls)[i] = this->ReadSubChunk(); + // if ((*ls)[i] == nullptr) { + // // fail. remove all created statechunk and clear it + // for (auto& item : *ls) { + // if (item != nullptr) + // delete (item); + // } + // ls->clear(); + // // return + // return false; + // } + // } - return true; - } + // return true; + //} bool CKStateChunk::ReadXObjectArray(XContainer::XObjectArray* ls) { if (ls == nullptr) return false; diff --git a/LibCmo/CK2/CKStateChunkWriter.cpp b/LibCmo/CK2/CKStateChunkWriter.cpp index af0b307..a2d85ec 100644 --- a/LibCmo/CK2/CKStateChunkWriter.cpp +++ b/LibCmo/CK2/CKStateChunkWriter.cpp @@ -3,6 +3,22 @@ #include "CKContext.hpp" #include "ObjImpls/CKObject.hpp" +/* +Memorandum: + +No need to write any data in m_ObjectList when writing Object ID. +Because m_ObjectList only need to be written in when no bind CKFile +according to IDA reversed code. +However we assuem all CKStateChunk have bind file so no need to treat it. + +However, m_ManagerList should be filled when writing Manager Int. +This is also instructed by IDA revsersed code. + +For m_ChunkList, it is same as m_ManagerList. We need write it. + +*/ + + namespace LibCmo::CK2 { void CKStateChunk::StartWrite() { @@ -129,7 +145,7 @@ namespace LibCmo::CK2 { } bool CKStateChunk::WriteString(const XContainer::XString* strl) { - if (strl == nullptr) return; + if (strl == nullptr) return false; // convert encoding XContainer::XString cache; @@ -156,17 +172,15 @@ namespace LibCmo::CK2 { } bool CKStateChunk::WriteObjectPointer(ObjImpls::CKObject* obj) { - CK_ID objid; - if (obj != nullptr) { - objid = obj->GetID(); - } + CK_ID objid = 0; + 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); + AddEntry(m_ManagerList, m_Parser.m_CurrentPos); // write data if (!this->WriteStruct(guid)) return false; if (!this->WriteStruct(intval)) return false; @@ -207,19 +221,63 @@ namespace LibCmo::CK2 { /* ========== Sequence Functions ==========*/ bool CKStateChunk::WriteObjectIDSequence(const XContainer::XObjectArray* ls) { - return false; + if (ls == nullptr) return false; + + // MARK: there is a recording oper for object list when no bind file. + // but we always have bind file, so ignore it + + // write size first + CKDWORD objidsize = static_cast(ls->size()); + if (!this->WriteStruct(objidsize)) return false; + + // write each data + for (auto objid : *ls) { + // MARK: originally we should not call WriteObjectID like ReadObjectIDSequence. + // because we do not write position data in obj list for each item. + // even if bind file always is not nullptr. + if (!this->WriteStruct(m_BindFile->GetIndexByObjectID(objid))) return false; + } + + return true; } bool CKStateChunk::WriteManagerIntSequence(const CKGUID* guid, const XContainer::XArray* ls) { - return false; + if (guid == nullptr || ls == nullptr) return false; + + // add current pos into manager list + AddEntries(m_ManagerList, m_Parser.m_CurrentPos); + + // write data length + CKDWORD lssize = static_cast(ls->size()); + if (!this->WriteStruct(lssize)) return false; + // write guid + if (!this->WriteStruct(guid)) return false; + + // then write each items + for (auto iv : *ls) { + // MARK: we should not call WriteManagerInt like ReadManagerIntSequence. + // because we do not want to write postion info into manager list for each item. + if (!this->WriteStruct(iv)) return false; + } + + return true; } bool CKStateChunk::WriteXObjectArray(const XContainer::XObjectArray* ls) { - return false; + // same as WriteObjectIDSequence. + return WriteObjectIDSequence(ls); } bool CKStateChunk::WriteXObjectPointerArray(const XContainer::XObjectPointerArray* ls) { - return false; + if (ls == nullptr) return false; + + XContainer::XObjectArray conv; + for (auto obj : *ls) { + if (obj == nullptr) conv.emplace_back(0); + else conv.emplace_back(obj->GetID()); + } + + return WriteObjectIDSequence(conv); } }