write other CKStateChunk writer and remove sub chunk function

This commit is contained in:
yyc12345 2023-09-24 13:55:41 +08:00
parent 3e265cdf1d
commit 6870fca911
5 changed files with 222 additions and 133 deletions

View File

@ -326,7 +326,7 @@ namespace LibCmo::CK2 {
CKDWORD CKFileVisitor::GetIndexByObjectID(CK_ID objid) { CKDWORD CKFileVisitor::GetIndexByObjectID(CK_ID objid) {
// see CKFile::SaveFindObjectIndex in IDA // see CKFile::SaveFindObjectIndex in IDA
CKDWORD idx = -1; CKDWORD idx = static_cast<CKDWORD>(-1);
if (m_IsReader) return idx; if (m_IsReader) return idx;
auto finder = m_Writer->m_ObjectsHashTable.find(objid); auto finder = m_Writer->m_ObjectsHashTable.find(objid);

View File

@ -232,6 +232,29 @@ namespace LibCmo::CK2 {
*/ */
bool EnsureReadSpace(CKDWORD dword_required); 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<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);
#pragma endregion #pragma endregion
#pragma region Read Function #pragma region Read Function
@ -368,12 +391,12 @@ namespace LibCmo::CK2 {
return ReadManagerInt(&guid, &intval); return ReadManagerInt(&guid, &intval);
} }
/** ///**
* @brief Read sub chunk // * @brief Read sub chunk
* @return Returned a new created of CKStateChunk if success, otherwise nullptr. // * @return Returned a new created of CKStateChunk if success, otherwise nullptr.
* Returned CKStateChunk should be manually released! // * Returned CKStateChunk should be manually released!
*/ //*/
CKStateChunk* ReadSubChunk(); //CKStateChunk* ReadSubChunk();
/* ========== Buffer Functions ==========*/ /* ========== Buffer Functions ==========*/
@ -480,17 +503,17 @@ namespace LibCmo::CK2 {
return ReadManagerIntSequence(&guid, &ls); return ReadManagerIntSequence(&guid, &ls);
} }
/// <summary> ///// <summary>
/// Read Sub Chunk Sequence ///// Read Sub Chunk Sequence
/// <para>The combination using of StartReadSequence() and ReadSubChunk() redirect to this.</para> ///// <para>The combination using of StartReadSequence() and ReadSubChunk() redirect to this.</para>
/// <para>The item of returned CKStateChunk* list should be manually released!</para> ///// <para>The item of returned CKStateChunk* list should be manually released!</para>
/// </summary> ///// </summary>
/// <param name="ls"></param> ///// <param name="ls"></param>
/// <returns></returns> ///// <returns></returns>
bool ReadSubChunkSequence(XContainer::XArray<CKStateChunk*>* ls); //bool ReadSubChunkSequence(XContainer::XArray<CKStateChunk*>* ls);
inline bool ReadSubChunkSequence(XContainer::XArray<CKStateChunk*>& ls) { //inline bool ReadSubChunkSequence(XContainer::XArray<CKStateChunk*>& ls) {
return ReadSubChunkSequence(&ls); // return ReadSubChunkSequence(&ls);
} //}
/** /**
* @brief Read Object Array (actually still is CK_ID) * @brief Read Object Array (actually still is CK_ID)
@ -601,7 +624,7 @@ namespace LibCmo::CK2 {
public: public:
bool WriteObjectIDSequence(const XContainer::XObjectArray* ls); bool WriteObjectIDSequence(const XContainer::XObjectArray* ls);
inline bool ReadObjectIDSequence(const XContainer::XObjectArray& ls) { inline bool WriteObjectIDSequence(const XContainer::XObjectArray& ls) {
return WriteObjectIDSequence(&ls); return WriteObjectIDSequence(&ls);
} }

View File

@ -303,6 +303,14 @@ namespace LibCmo::CK2 {
(this->m_Parser.m_CurrentPos + dword_required <= this->m_Parser.m_DataSize); (this->m_Parser.m_CurrentPos + dword_required <= this->m_Parser.m_DataSize);
} }
void CKStateChunk::AddEntry(XContainer::XArray<CKDWORD>& entry_ls, CKDWORD pos) {
entry_ls.emplace_back(pos);
}
void CKStateChunk::AddEntries(XContainer::XArray<CKDWORD>& entry_ls, CKDWORD pos) {
entry_ls.emplace_back(static_cast<CKDWORD>(-1));
entry_ls.emplace_back(pos);
}
#pragma endregion #pragma endregion

View File

@ -205,98 +205,98 @@ namespace LibCmo::CK2 {
return true; return true;
} }
CKStateChunk* CKStateChunk::ReadSubChunk(void) { //CKStateChunk* CKStateChunk::ReadSubChunk(void) {
CKStateChunk* subchunk = nullptr; // CKStateChunk* subchunk = nullptr;
// get size and do a enough space check // // get size and do a enough space check
CKDWORD subDwordChunkSize; // CKDWORD subDwordChunkSize;
if (!this->ReadStruct(subDwordChunkSize)) goto subchunk_defer; // if (!this->ReadStruct(subDwordChunkSize)) goto subchunk_defer;
if (!this->EnsureReadSpace(subDwordChunkSize)) 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);
// start read data // // start read data
// read class id // // read class id
if (!this->ReadStruct(subchunk->m_ClassId)) goto subchunk_defer; // if (!this->ReadStruct(subchunk->m_ClassId)) goto subchunk_defer;
// different read strategy by chunk version // // different read strategy by chunk version
if (this->m_ChunkVersion >= CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION1) { // if (this->m_ChunkVersion >= CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION1) {
// new file // // new file
// read combined version // // read combined version
CKDWORD versionInfo; // CKDWORD versionInfo;
if (!this->ReadStruct(versionInfo)) goto subchunk_defer; // if (!this->ReadStruct(versionInfo)) goto subchunk_defer;
subchunk->m_DataVersion = static_cast<CK_STATECHUNK_DATAVERSION>(versionInfo & 0xffff); // subchunk->m_DataVersion = static_cast<CK_STATECHUNK_DATAVERSION>(versionInfo & 0xffff);
subchunk->m_ChunkVersion = static_cast<CK_STATECHUNK_CHUNKVERSION>((versionInfo >> 16) & 0xffff); // subchunk->m_ChunkVersion = static_cast<CK_STATECHUNK_CHUNKVERSION>((versionInfo >> 16) & 0xffff);
// read data size and create it // // read data size and create it
if (!this->ReadStruct(subchunk->m_DataDwSize)) goto subchunk_defer; // if (!this->ReadStruct(subchunk->m_DataDwSize)) goto subchunk_defer;
subchunk->m_pData = new CKDWORD[subchunk->m_DataDwSize]; // subchunk->m_pData = new CKDWORD[subchunk->m_DataDwSize];
// has bind file? // // has bind file?
CKDWORD hasBindFile; // CKDWORD hasBindFile;
if (!this->ReadStruct(hasBindFile)) goto subchunk_defer; // if (!this->ReadStruct(hasBindFile)) goto subchunk_defer;
if (hasBindFile == 1) subchunk->m_BindFile = nullptr; // if (hasBindFile == 1) subchunk->m_BindFile = nullptr;
// 3 list size // // 3 list size
// manager only existed when ver > 4 // // manager only existed when ver > 4
CKDWORD lssize; // CKDWORD lssize;
if (!this->ReadStruct(lssize)) goto subchunk_defer; // if (!this->ReadStruct(lssize)) goto subchunk_defer;
subchunk->m_ObjectList.resize(lssize); // subchunk->m_ObjectList.resize(lssize);
if (!this->ReadStruct(lssize)) goto subchunk_defer; // if (!this->ReadStruct(lssize)) goto subchunk_defer;
subchunk->m_ChunkList.resize(lssize); // subchunk->m_ChunkList.resize(lssize);
if (this->m_ChunkVersion > CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION1) { // if (this->m_ChunkVersion > CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION1) {
if (!this->ReadStruct(lssize)) goto subchunk_defer; // if (!this->ReadStruct(lssize)) goto subchunk_defer;
subchunk->m_ManagerList.resize(lssize); // subchunk->m_ManagerList.resize(lssize);
} // }
// core data // // core data
if (subchunk->m_DataDwSize != 0) { // if (subchunk->m_DataDwSize != 0) {
if (!this->ReadByteData(subchunk->m_pData, subchunk->m_DataDwSize * CKSizeof(CKDWORD))) goto subchunk_defer; // if (!this->ReadByteData(subchunk->m_pData, subchunk->m_DataDwSize * CKSizeof(CKDWORD))) goto subchunk_defer;
} // }
// 3 list data // // 3 list data
if (!subchunk->m_ObjectList.empty()) { // if (!subchunk->m_ObjectList.empty()) {
if (!this->ReadByteData( // if (!this->ReadByteData(
subchunk->m_ObjectList.data(), // subchunk->m_ObjectList.data(),
static_cast<CKDWORD>(subchunk->m_ObjectList.size()) * CKSizeof(CKDWORD) // static_cast<CKDWORD>(subchunk->m_ObjectList.size()) * CKSizeof(CKDWORD)
)) goto subchunk_defer; // )) goto subchunk_defer;
} // }
if (!subchunk->m_ChunkList.empty()) { // if (!subchunk->m_ChunkList.empty()) {
if (!this->ReadByteData( // if (!this->ReadByteData(
subchunk->m_ChunkList.data(), // subchunk->m_ChunkList.data(),
static_cast<CKDWORD>(subchunk->m_ChunkList.size()) * CKSizeof(CKDWORD) // static_cast<CKDWORD>(subchunk->m_ChunkList.size()) * CKSizeof(CKDWORD)
)) goto subchunk_defer; // )) goto subchunk_defer;
} // }
if (!subchunk->m_ManagerList.empty()) { // if (!subchunk->m_ManagerList.empty()) {
if (!this->ReadByteData( // if (!this->ReadByteData(
subchunk->m_ManagerList.data(), // subchunk->m_ManagerList.data(),
static_cast<CKDWORD>(subchunk->m_ManagerList.size()) * CKSizeof(CKDWORD) // static_cast<CKDWORD>(subchunk->m_ManagerList.size()) * CKSizeof(CKDWORD)
)) goto subchunk_defer; // )) goto subchunk_defer;
} // }
} else { // } else {
// old file // // old file
// read data size and create it // // read data size and create it
if (!this->ReadStruct(subchunk->m_DataDwSize)) goto subchunk_defer; // if (!this->ReadStruct(subchunk->m_DataDwSize)) goto subchunk_defer;
subchunk->m_pData = new CKDWORD[subchunk->m_DataDwSize]; // subchunk->m_pData = new CKDWORD[subchunk->m_DataDwSize];
// skip one? // // skip one?
// I don't know why // // I don't know why
this->Skip(1u); // this->Skip(1u);
// read core buf // // read core buf
if (!this->ReadByteData(subchunk->m_pData, subchunk->m_DataDwSize * CKSizeof(CKDWORD))) goto subchunk_defer; // if (!this->ReadByteData(subchunk->m_pData, subchunk->m_DataDwSize * CKSizeof(CKDWORD))) goto subchunk_defer;
} // }
return subchunk; // return subchunk;
subchunk_defer: //subchunk_defer:
if (subchunk != nullptr) delete subchunk; // if (subchunk != nullptr) delete subchunk;
return nullptr; // return nullptr;
} //}
/* ========== Buffer Functions ==========*/ /* ========== Buffer Functions ==========*/
@ -427,38 +427,38 @@ namespace LibCmo::CK2 {
return true; return true;
} }
bool CKStateChunk::ReadSubChunkSequence(XContainer::XArray<CKStateChunk*>* ls) { //bool CKStateChunk::ReadSubChunkSequence(XContainer::XArray<CKStateChunk*>* ls) {
if (ls == nullptr) return false; // if (ls == nullptr) return false;
// clear first // // clear first
for (auto& item : *ls) { // for (auto& item : *ls) {
if (item != nullptr) // if (item != nullptr)
delete (item); // delete (item);
} // }
ls->clear(); // ls->clear();
// read count // // read count
CKDWORD count; // CKDWORD count;
if (!this->ReadStruct(count)) return false; // if (!this->ReadStruct(count)) return false;
// resize list and read it // // resize list and read it
ls->resize(count, nullptr); // ls->resize(count, nullptr);
for (size_t i = 0; i < count; ++i) { // for (size_t i = 0; i < count; ++i) {
(*ls)[i] = this->ReadSubChunk(); // (*ls)[i] = this->ReadSubChunk();
if ((*ls)[i] == nullptr) { // if ((*ls)[i] == nullptr) {
// fail. remove all created statechunk and clear it // // fail. remove all created statechunk and clear it
for (auto& item : *ls) { // for (auto& item : *ls) {
if (item != nullptr) // if (item != nullptr)
delete (item); // delete (item);
} // }
ls->clear(); // ls->clear();
// return // // return
return false; // return false;
} // }
} // }
return true; // return true;
} //}
bool CKStateChunk::ReadXObjectArray(XContainer::XObjectArray* ls) { bool CKStateChunk::ReadXObjectArray(XContainer::XObjectArray* ls) {
if (ls == nullptr) return false; if (ls == nullptr) return false;

View File

@ -3,6 +3,22 @@
#include "CKContext.hpp" #include "CKContext.hpp"
#include "ObjImpls/CKObject.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 { namespace LibCmo::CK2 {
void CKStateChunk::StartWrite() { void CKStateChunk::StartWrite() {
@ -129,7 +145,7 @@ namespace LibCmo::CK2 {
} }
bool CKStateChunk::WriteString(const XContainer::XString* strl) { bool CKStateChunk::WriteString(const XContainer::XString* strl) {
if (strl == nullptr) return; if (strl == nullptr) return false;
// convert encoding // convert encoding
XContainer::XString cache; XContainer::XString cache;
@ -156,17 +172,15 @@ namespace LibCmo::CK2 {
} }
bool CKStateChunk::WriteObjectPointer(ObjImpls::CKObject* obj) { bool CKStateChunk::WriteObjectPointer(ObjImpls::CKObject* obj) {
CK_ID objid; CK_ID objid = 0;
if (obj != nullptr) { if (obj != nullptr) objid = obj->GetID();
objid = obj->GetID();
}
return WriteObjectID(objid); return WriteObjectID(objid);
} }
bool CKStateChunk::WriteManagerInt(const CKGUID* guid, CKINT intval) { bool CKStateChunk::WriteManagerInt(const CKGUID* guid, CKINT intval) {
// push into manager list // push into manager list
m_ManagerList.emplace_back(m_Parser.m_CurrentPos); AddEntry(m_ManagerList, m_Parser.m_CurrentPos);
// write data // write data
if (!this->WriteStruct(guid)) return false; if (!this->WriteStruct(guid)) return false;
if (!this->WriteStruct(intval)) return false; if (!this->WriteStruct(intval)) return false;
@ -207,19 +221,63 @@ namespace LibCmo::CK2 {
/* ========== Sequence Functions ==========*/ /* ========== Sequence Functions ==========*/
bool CKStateChunk::WriteObjectIDSequence(const XContainer::XObjectArray* ls) { 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<CKDWORD>(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<CKINT>* ls) { bool CKStateChunk::WriteManagerIntSequence(const CKGUID* guid, const XContainer::XArray<CKINT>* 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<CKDWORD>(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) { bool CKStateChunk::WriteXObjectArray(const XContainer::XObjectArray* ls) {
return false; // same as WriteObjectIDSequence.
return WriteObjectIDSequence(ls);
} }
bool CKStateChunk::WriteXObjectPointerArray(const XContainer::XObjectPointerArray* 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);
} }
} }