split the implement of CKStateChunk because code is too much
This commit is contained in:
parent
81d1e80d14
commit
616a32ce19
|
@ -502,539 +502,4 @@ namespace LibCmo::CK2 {
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region Read Functions
|
|
||||||
|
|
||||||
void CKStateChunk::StartRead(void) {
|
|
||||||
if (this->m_Parser.m_Status != CKStateChunkStatus::IDLE) 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::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);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CKStateChunk::SeekIdentifierDwordAndReturnSize(CKDWORD identifier, CKDWORD* out_size) {
|
|
||||||
if (this->m_Parser.m_Status != CKStateChunkStatus::READ) return false;
|
|
||||||
|
|
||||||
CKDWORD pos = 0u;
|
|
||||||
if (this->m_DataDwSize < 2u) return false; // impossible to have a identifier
|
|
||||||
|
|
||||||
// search identifier
|
|
||||||
while (this->m_pData[pos] != identifier) {
|
|
||||||
pos = this->m_pData[pos + 1];
|
|
||||||
if (pos == 0u) return false; // got tail. no more identifier
|
|
||||||
if (pos + 1 >= this->m_DataDwSize) return false; // out of buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
// got identifier
|
|
||||||
this->m_Parser.m_PrevIdentifierPos = pos;
|
|
||||||
this->m_Parser.m_CurrentPos = pos + 2;
|
|
||||||
|
|
||||||
// calc size
|
|
||||||
CKDWORD nextptr = this->m_pData[pos + 1];
|
|
||||||
if (nextptr == 0) {
|
|
||||||
// the last identifier, use chunk size instead
|
|
||||||
nextptr = this->m_DataDwSize;
|
|
||||||
}
|
|
||||||
*out_size = CKSizeof(CKDWORD) * (nextptr - pos - 2u);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CKStateChunk::LockReadBuffer(const void** ppData, CKDWORD size_in_byte) {
|
|
||||||
// check arguments
|
|
||||||
if (*ppData == nullptr) return false;
|
|
||||||
*ppData = nullptr;
|
|
||||||
// check self status
|
|
||||||
if (this->m_Parser.m_Status != CKStateChunkStatus::READ) return false;
|
|
||||||
|
|
||||||
// get corresponding size
|
|
||||||
CKDWORD size_in_dword = this->GetCeilDwordSize(size_in_byte);
|
|
||||||
// ensure space
|
|
||||||
if (this->EnsureReadSpace(size_in_dword)) {
|
|
||||||
*ppData = this->m_pData + this->m_Parser.m_CurrentPos;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// failed, report to context
|
|
||||||
m_BindContext->OutputToConsoleEx("CKStateChunk::LockReadBuffer at buffer pos %" PRIuCKDWORD ".", this->m_Parser.m_CurrentPos);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CKStateChunk::UnLockReadBuffer(CKDWORD size_in_byte) {
|
|
||||||
// check self status
|
|
||||||
if (this->m_Parser.m_Status != CKStateChunkStatus::READ) return false;
|
|
||||||
|
|
||||||
// get corresponding size
|
|
||||||
CKDWORD size_in_dword = this->GetCeilDwordSize(size_in_byte);
|
|
||||||
// ensure space
|
|
||||||
if (this->EnsureReadSpace(size_in_dword)) {
|
|
||||||
this->m_Parser.m_CurrentPos += size_in_dword;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// failed, report to context
|
|
||||||
m_BindContext->OutputToConsoleEx("CKStateChunk::UnLockReadBuffer at buffer pos %" PRIuCKDWORD ".", this->m_Parser.m_CurrentPos);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CKStateChunk::LockedReadBuffer_t CKStateChunk::LockReadBufferWrapper(CKDWORD size_in_byte) {
|
|
||||||
const void* pData;
|
|
||||||
bool ret = LockReadBuffer(&pData, size_in_byte);
|
|
||||||
if (ret) {
|
|
||||||
return LockedReadBuffer_t(pData, LockedReadBufferDeleter(this, size_in_byte));
|
|
||||||
} else {
|
|
||||||
return LockedReadBuffer_t();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========== Basic Data Read Functions ==========*/
|
|
||||||
|
|
||||||
|
|
||||||
bool CKStateChunk::ReadByteData(void* data_ptr, CKDWORD size_in_byte) {
|
|
||||||
if (data_ptr == nullptr) return false;
|
|
||||||
|
|
||||||
const void* pData;
|
|
||||||
bool ret = LockReadBuffer(&pData, size_in_byte);
|
|
||||||
if (ret) {
|
|
||||||
std::memcpy(data_ptr, pData, size_in_byte);
|
|
||||||
UnLockReadBuffer(size_in_byte);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CKStateChunk::ReadString(XContainer::XString* strl) {
|
|
||||||
if (strl == nullptr) return false;
|
|
||||||
|
|
||||||
// get byte based size
|
|
||||||
CKDWORD strByteSize = 0u;
|
|
||||||
if (!this->ReadStruct(strByteSize)) {
|
|
||||||
strl->clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read data
|
|
||||||
XContainer::XString cache;
|
|
||||||
cache.resize(strByteSize);
|
|
||||||
if (!this->ReadByteData(cache.data(), strByteSize)) {
|
|
||||||
strl->clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert encoding
|
|
||||||
m_BindContext->GetUtf8String(cache, *strl);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========== Complex Data Read Functions ==========*/
|
|
||||||
|
|
||||||
bool CKStateChunk::ReadObjectID(CK_ID* id) {
|
|
||||||
if (id == nullptr) return false;
|
|
||||||
|
|
||||||
// get basic value
|
|
||||||
CKINT gotten_id = 0;
|
|
||||||
if (!this->ReadStruct(gotten_id)) return false;
|
|
||||||
|
|
||||||
// different strategy according to chunk ver
|
|
||||||
if (this->m_ChunkVersion >= CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION1) {
|
|
||||||
// new file
|
|
||||||
|
|
||||||
// if no doc associated, return directly
|
|
||||||
if (this->m_BindFile == nullptr) {
|
|
||||||
*id = static_cast<CK_ID>(gotten_id);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// if it is positive, return corresponding value
|
|
||||||
if (gotten_id >= 0) {
|
|
||||||
*id = this->m_BindFile->GetFileObjectByIndex(gotten_id)->CreatedObjectId;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// old file
|
|
||||||
// i don't know why I need skip 2 DWORD
|
|
||||||
// just copy IDA code.
|
|
||||||
|
|
||||||
if (gotten_id) {
|
|
||||||
this->Skip(2);
|
|
||||||
return this->ReadStruct(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// all failed
|
|
||||||
*id = 0u;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CKStateChunk::ReadManagerInt(CKGUID* guid, CKINT* intval) {
|
|
||||||
if (guid == nullptr || intval == nullptr) return false;
|
|
||||||
|
|
||||||
// read guid first
|
|
||||||
if (!this->ReadStruct(guid)) return false;
|
|
||||||
// then read int value
|
|
||||||
if (!this->ReadStruct(intval)) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
CKStateChunk* CKStateChunk::ReadSubChunk(void) {
|
|
||||||
CKStateChunk* subchunk = nullptr;
|
|
||||||
|
|
||||||
// get size and do a enough space check
|
|
||||||
CKDWORD subChunkSize;
|
|
||||||
if (!this->ReadStruct(subChunkSize)) goto subchunk_defer;
|
|
||||||
if (!this->EnsureReadSpace(subChunkSize)) goto subchunk_defer;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// 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<CK_STATECHUNK_DATAVERSION>(versionInfo & 0xffff);
|
|
||||||
subchunk->m_ChunkVersion = static_cast<CK_STATECHUNK_CHUNKVERSION>((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];
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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<CKDWORD>(subchunk->m_ObjectList.size()) * CKSizeof(CKDWORD)
|
|
||||||
)) goto subchunk_defer;
|
|
||||||
}
|
|
||||||
if (!subchunk->m_ChunkList.empty()) {
|
|
||||||
if (!this->ReadByteData(
|
|
||||||
subchunk->m_ChunkList.data(),
|
|
||||||
static_cast<CKDWORD>(subchunk->m_ChunkList.size()) * CKSizeof(CKDWORD)
|
|
||||||
)) goto subchunk_defer;
|
|
||||||
}
|
|
||||||
if (!subchunk->m_ManagerList.empty()) {
|
|
||||||
if (!this->ReadByteData(
|
|
||||||
subchunk->m_ManagerList.data(),
|
|
||||||
static_cast<CKDWORD>(subchunk->m_ManagerList.size()) * CKSizeof(CKDWORD)
|
|
||||||
)) goto subchunk_defer;
|
|
||||||
}
|
|
||||||
|
|
||||||
} 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];
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return subchunk;
|
|
||||||
subchunk_defer:
|
|
||||||
if (subchunk != nullptr) delete subchunk;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========== Buffer Functions ==========*/
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// special treat for zero length buffer
|
|
||||||
if (bufByteSize == 0) {
|
|
||||||
*buf = nullptr;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create buffer
|
|
||||||
*buf = new CKBYTE[bufByteSize];
|
|
||||||
|
|
||||||
// read data
|
|
||||||
if (!this->ReadByteData(*buf, bufByteSize)) {
|
|
||||||
this->DeleteBuffer(*buf);
|
|
||||||
*buf = nullptr;
|
|
||||||
*len_in_byte = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CKStateChunk::DeleteBuffer(const void* buf) {
|
|
||||||
if (buf == nullptr) return;
|
|
||||||
delete[] reinterpret_cast<const CKBYTE*>(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
CKStateChunk::Buffer_t CKStateChunk::ReadBufferWrapper() {
|
|
||||||
void* bufcache = nullptr;
|
|
||||||
CKDWORD len_in_byte;
|
|
||||||
bool ret = ReadBuffer(&bufcache, &len_in_byte);
|
|
||||||
if (ret) {
|
|
||||||
return Buffer_t(bufcache, BufferDeleter(this, len_in_byte));
|
|
||||||
} else {
|
|
||||||
return Buffer_t();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========== Sequence Functions ==========*/
|
|
||||||
|
|
||||||
bool CKStateChunk::ReadObjectIDSequence(XContainer::XArray<CK_ID>* ls) {
|
|
||||||
if (ls == nullptr) return false;
|
|
||||||
ls->clear();
|
|
||||||
|
|
||||||
// read count
|
|
||||||
CKDWORD count;
|
|
||||||
if (!this->ReadStruct(count)) return false;
|
|
||||||
|
|
||||||
// resize list and read it
|
|
||||||
ls->resize(count);
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
if (!this->ReadObjectID(ls->data() + i)) {
|
|
||||||
ls->clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CKStateChunk::ReadManagerIntSequence(CKGUID* guid, XContainer::XArray<CKINT>* ls) {
|
|
||||||
if (guid == nullptr || ls == nullptr) return false;
|
|
||||||
|
|
||||||
// read count
|
|
||||||
CKDWORD count;
|
|
||||||
if (!this->ReadStruct(count)) return false;
|
|
||||||
|
|
||||||
// read guid
|
|
||||||
if (!this->ReadStruct(guid)) return false;
|
|
||||||
|
|
||||||
// resize list and read it
|
|
||||||
ls->resize(count);
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
if (!this->ReadStruct(ls->data() + i)) {
|
|
||||||
ls->clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CKStateChunk::ReadSubChunkSequence(XContainer::XArray<CKStateChunk*>* ls) {
|
|
||||||
if (ls == nullptr) return false;
|
|
||||||
|
|
||||||
// clear first
|
|
||||||
for (auto& item : *ls) {
|
|
||||||
if (item != nullptr)
|
|
||||||
delete (item);
|
|
||||||
}
|
|
||||||
ls->clear();
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CKStateChunk::ReadXObjectArray(XContainer::XObjectArray* ls) {
|
|
||||||
if (ls == nullptr) return false;
|
|
||||||
ls->clear();
|
|
||||||
|
|
||||||
// read count
|
|
||||||
CKDWORD count;
|
|
||||||
if (!this->ReadStruct(count)) return false;
|
|
||||||
if (count == 0) return true; // 0 size array
|
|
||||||
|
|
||||||
// old file size correction
|
|
||||||
bool old_file = this->m_ChunkVersion < CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION1;
|
|
||||||
if (old_file) {
|
|
||||||
// skip 4. but I don't know why!!!
|
|
||||||
this->Skip(4);
|
|
||||||
if (!this->ReadStruct(count)) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// resize list and read
|
|
||||||
ls->resize(count);
|
|
||||||
for (auto& id : *ls) {
|
|
||||||
// read ID first
|
|
||||||
CKINT cache;
|
|
||||||
if (!this->ReadStruct(cache)) {
|
|
||||||
ls->clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// in old file or no bind file, the read data directly is CK_ID.
|
|
||||||
// in new file or has bind file, the read data is the index in FileObjects
|
|
||||||
if (old_file || this->m_BindFile == nullptr) {
|
|
||||||
id = static_cast<CK_ID>(cache);
|
|
||||||
} else {
|
|
||||||
if (cache < 0) id = 0;
|
|
||||||
else id = this->m_BindFile->GetFileObjectByIndex(cache)->CreatedObjectId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CKStateChunk::ReadXObjectPointerArray(XContainer::XObjectPointerArray* ls) {
|
|
||||||
if (ls == nullptr) return false;
|
|
||||||
|
|
||||||
// very very similar to ReadXObjectArray
|
|
||||||
// we execute it first.
|
|
||||||
XContainer::XObjectArray idarr;
|
|
||||||
if (!ReadXObjectArray(idarr)) return false;
|
|
||||||
|
|
||||||
// then convert it to pointer list
|
|
||||||
ls->resize(idarr.size());
|
|
||||||
for (size_t i = 0; i < idarr.size(); ++i) {
|
|
||||||
(*ls)[i] = m_BindContext->GetObject(idarr[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma endregion
|
|
||||||
|
|
||||||
|
|
||||||
#pragma region Write Functions
|
|
||||||
|
|
||||||
void CKStateChunk::StartWrite() {
|
|
||||||
if (this->m_Parser.m_Status != CKStateChunkStatus::IDLE) return;
|
|
||||||
|
|
||||||
// delete all current buffer
|
|
||||||
if (this->m_pData != nullptr) {
|
|
||||||
delete[] this->m_pData;
|
|
||||||
this->m_pData = nullptr;
|
|
||||||
}
|
|
||||||
this->m_DataDwSize = 0u;
|
|
||||||
|
|
||||||
// reset parser
|
|
||||||
this->m_Parser.m_CurrentPos = 0u;
|
|
||||||
this->m_Parser.m_DataSize = this->m_DataDwSize;
|
|
||||||
this->m_Parser.m_PrevIdentifierPos = 0u;
|
|
||||||
|
|
||||||
// force chunk version
|
|
||||||
this->m_ChunkVersion = CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION4;
|
|
||||||
|
|
||||||
// switch status
|
|
||||||
this->m_Parser.m_Status = CKStateChunkStatus::WRITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CKStateChunk::StopWrite(void) {
|
|
||||||
if (this->m_Parser.m_Status != CKStateChunkStatus::WRITE) return;
|
|
||||||
|
|
||||||
// update buffer size
|
|
||||||
this->m_DataDwSize = this->m_Parser.m_CurrentPos;
|
|
||||||
// shrink it
|
|
||||||
ResizeBuffer(this->m_DataDwSize);
|
|
||||||
|
|
||||||
// shrink 3 vector also
|
|
||||||
this->m_ObjectList.shrink_to_fit();
|
|
||||||
this->m_ManagerList.shrink_to_fit();
|
|
||||||
this->m_ChunkList.shrink_to_fit();
|
|
||||||
|
|
||||||
// reset parser
|
|
||||||
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::LockWriteBuffer(const void** ppData, CKDWORD size_in_byte) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CKStateChunk::UnLockWriteBuffer(CKDWORD size_in_byte) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
CKStateChunk::LockedWriteBuffer_t CKStateChunk::LockWriteBufferWrapper(CKDWORD size_in_byte) {
|
|
||||||
return LockedWriteBuffer_t();
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma endregion
|
|
||||||
|
|
||||||
}
|
}
|
479
LibCmo/CK2/CKStateChunkReader.cpp
Normal file
479
LibCmo/CK2/CKStateChunkReader.cpp
Normal file
|
@ -0,0 +1,479 @@
|
||||||
|
#include "CKStateChunk.hpp"
|
||||||
|
#include "CKFile.hpp"
|
||||||
|
#include "CKContext.hpp"
|
||||||
|
|
||||||
|
namespace LibCmo::CK2 {
|
||||||
|
|
||||||
|
void CKStateChunk::StartRead(void) {
|
||||||
|
if (this->m_Parser.m_Status != CKStateChunkStatus::IDLE) 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::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);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::SeekIdentifierDwordAndReturnSize(CKDWORD identifier, CKDWORD* out_size) {
|
||||||
|
if (this->m_Parser.m_Status != CKStateChunkStatus::READ) return false;
|
||||||
|
|
||||||
|
CKDWORD pos = 0u;
|
||||||
|
if (this->m_DataDwSize < 2u) return false; // impossible to have a identifier
|
||||||
|
|
||||||
|
// search identifier
|
||||||
|
while (this->m_pData[pos] != identifier) {
|
||||||
|
pos = this->m_pData[pos + 1];
|
||||||
|
if (pos == 0u) return false; // got tail. no more identifier
|
||||||
|
if (pos + 1 >= this->m_DataDwSize) return false; // out of buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// got identifier
|
||||||
|
this->m_Parser.m_PrevIdentifierPos = pos;
|
||||||
|
this->m_Parser.m_CurrentPos = pos + 2;
|
||||||
|
|
||||||
|
// calc size
|
||||||
|
CKDWORD nextptr = this->m_pData[pos + 1];
|
||||||
|
if (nextptr == 0) {
|
||||||
|
// the last identifier, use chunk size instead
|
||||||
|
nextptr = this->m_DataDwSize;
|
||||||
|
}
|
||||||
|
*out_size = CKSizeof(CKDWORD) * (nextptr - pos - 2u);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::LockReadBuffer(const void** ppData, CKDWORD size_in_byte) {
|
||||||
|
// check arguments
|
||||||
|
if (*ppData == nullptr) return false;
|
||||||
|
*ppData = nullptr;
|
||||||
|
// check self status
|
||||||
|
if (this->m_Parser.m_Status != CKStateChunkStatus::READ) return false;
|
||||||
|
|
||||||
|
// get corresponding size
|
||||||
|
CKDWORD size_in_dword = this->GetCeilDwordSize(size_in_byte);
|
||||||
|
// ensure space
|
||||||
|
if (this->EnsureReadSpace(size_in_dword)) {
|
||||||
|
*ppData = this->m_pData + this->m_Parser.m_CurrentPos;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// failed, report to context
|
||||||
|
m_BindContext->OutputToConsoleEx("CKStateChunk::LockReadBuffer at buffer pos %" PRIuCKDWORD ".", this->m_Parser.m_CurrentPos);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::UnLockReadBuffer(CKDWORD size_in_byte) {
|
||||||
|
// check self status
|
||||||
|
if (this->m_Parser.m_Status != CKStateChunkStatus::READ) return false;
|
||||||
|
|
||||||
|
// get corresponding size
|
||||||
|
CKDWORD size_in_dword = this->GetCeilDwordSize(size_in_byte);
|
||||||
|
// ensure space
|
||||||
|
if (this->EnsureReadSpace(size_in_dword)) {
|
||||||
|
this->m_Parser.m_CurrentPos += size_in_dword;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// failed, report to context
|
||||||
|
m_BindContext->OutputToConsoleEx("CKStateChunk::UnLockReadBuffer at buffer pos %" PRIuCKDWORD ".", this->m_Parser.m_CurrentPos);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CKStateChunk::LockedReadBuffer_t CKStateChunk::LockReadBufferWrapper(CKDWORD size_in_byte) {
|
||||||
|
const void* pData;
|
||||||
|
bool ret = LockReadBuffer(&pData, size_in_byte);
|
||||||
|
if (ret) {
|
||||||
|
return LockedReadBuffer_t(pData, LockedReadBufferDeleter(this, size_in_byte));
|
||||||
|
} else {
|
||||||
|
return LockedReadBuffer_t();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== Basic Data Read Functions ==========*/
|
||||||
|
|
||||||
|
|
||||||
|
bool CKStateChunk::ReadByteData(void* data_ptr, CKDWORD size_in_byte) {
|
||||||
|
if (data_ptr == nullptr) return false;
|
||||||
|
|
||||||
|
const void* pData;
|
||||||
|
bool ret = LockReadBuffer(&pData, size_in_byte);
|
||||||
|
if (ret) {
|
||||||
|
std::memcpy(data_ptr, pData, size_in_byte);
|
||||||
|
UnLockReadBuffer(size_in_byte);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::ReadString(XContainer::XString* strl) {
|
||||||
|
if (strl == nullptr) return false;
|
||||||
|
|
||||||
|
// get byte based size
|
||||||
|
CKDWORD strByteSize = 0u;
|
||||||
|
if (!this->ReadStruct(strByteSize)) {
|
||||||
|
strl->clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read data
|
||||||
|
XContainer::XString cache;
|
||||||
|
cache.resize(strByteSize);
|
||||||
|
if (!this->ReadByteData(cache.data(), strByteSize)) {
|
||||||
|
strl->clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert encoding
|
||||||
|
m_BindContext->GetUtf8String(cache, *strl);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== Complex Data Read Functions ==========*/
|
||||||
|
|
||||||
|
bool CKStateChunk::ReadObjectID(CK_ID* id) {
|
||||||
|
if (id == nullptr) return false;
|
||||||
|
|
||||||
|
// get basic value
|
||||||
|
CKINT gotten_id = 0;
|
||||||
|
if (!this->ReadStruct(gotten_id)) return false;
|
||||||
|
|
||||||
|
// different strategy according to chunk ver
|
||||||
|
if (this->m_ChunkVersion >= CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION1) {
|
||||||
|
// new file
|
||||||
|
|
||||||
|
// if no doc associated, return directly
|
||||||
|
if (this->m_BindFile == nullptr) {
|
||||||
|
*id = static_cast<CK_ID>(gotten_id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// if it is positive, return corresponding value
|
||||||
|
if (gotten_id >= 0) {
|
||||||
|
*id = this->m_BindFile->GetFileObjectByIndex(gotten_id)->CreatedObjectId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// old file
|
||||||
|
// i don't know why I need skip 2 DWORD
|
||||||
|
// just copy IDA code.
|
||||||
|
|
||||||
|
if (gotten_id) {
|
||||||
|
this->Skip(2);
|
||||||
|
return this->ReadStruct(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// all failed
|
||||||
|
*id = 0u;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::ReadManagerInt(CKGUID* guid, CKINT* intval) {
|
||||||
|
if (guid == nullptr || intval == nullptr) return false;
|
||||||
|
|
||||||
|
// read guid first
|
||||||
|
if (!this->ReadStruct(guid)) return false;
|
||||||
|
// then read int value
|
||||||
|
if (!this->ReadStruct(intval)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CKStateChunk* CKStateChunk::ReadSubChunk(void) {
|
||||||
|
CKStateChunk* subchunk = nullptr;
|
||||||
|
|
||||||
|
// get size and do a enough space check
|
||||||
|
CKDWORD subChunkSize;
|
||||||
|
if (!this->ReadStruct(subChunkSize)) goto subchunk_defer;
|
||||||
|
if (!this->EnsureReadSpace(subChunkSize)) goto subchunk_defer;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// 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<CK_STATECHUNK_DATAVERSION>(versionInfo & 0xffff);
|
||||||
|
subchunk->m_ChunkVersion = static_cast<CK_STATECHUNK_CHUNKVERSION>((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];
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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<CKDWORD>(subchunk->m_ObjectList.size()) * CKSizeof(CKDWORD)
|
||||||
|
)) goto subchunk_defer;
|
||||||
|
}
|
||||||
|
if (!subchunk->m_ChunkList.empty()) {
|
||||||
|
if (!this->ReadByteData(
|
||||||
|
subchunk->m_ChunkList.data(),
|
||||||
|
static_cast<CKDWORD>(subchunk->m_ChunkList.size()) * CKSizeof(CKDWORD)
|
||||||
|
)) goto subchunk_defer;
|
||||||
|
}
|
||||||
|
if (!subchunk->m_ManagerList.empty()) {
|
||||||
|
if (!this->ReadByteData(
|
||||||
|
subchunk->m_ManagerList.data(),
|
||||||
|
static_cast<CKDWORD>(subchunk->m_ManagerList.size()) * CKSizeof(CKDWORD)
|
||||||
|
)) goto subchunk_defer;
|
||||||
|
}
|
||||||
|
|
||||||
|
} 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];
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return subchunk;
|
||||||
|
subchunk_defer:
|
||||||
|
if (subchunk != nullptr) delete subchunk;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== Buffer Functions ==========*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// special treat for zero length buffer
|
||||||
|
if (bufByteSize == 0) {
|
||||||
|
*buf = nullptr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create buffer
|
||||||
|
*buf = new CKBYTE[bufByteSize];
|
||||||
|
|
||||||
|
// read data
|
||||||
|
if (!this->ReadByteData(*buf, bufByteSize)) {
|
||||||
|
this->DeleteBuffer(*buf);
|
||||||
|
*buf = nullptr;
|
||||||
|
*len_in_byte = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CKStateChunk::DeleteBuffer(const void* buf) {
|
||||||
|
if (buf == nullptr) return;
|
||||||
|
delete[] reinterpret_cast<const CKBYTE*>(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
CKStateChunk::Buffer_t CKStateChunk::ReadBufferWrapper() {
|
||||||
|
void* bufcache = nullptr;
|
||||||
|
CKDWORD len_in_byte;
|
||||||
|
bool ret = ReadBuffer(&bufcache, &len_in_byte);
|
||||||
|
if (ret) {
|
||||||
|
return Buffer_t(bufcache, BufferDeleter(this, len_in_byte));
|
||||||
|
} else {
|
||||||
|
return Buffer_t();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== Sequence Functions ==========*/
|
||||||
|
|
||||||
|
bool CKStateChunk::ReadObjectIDSequence(XContainer::XArray<CK_ID>* ls) {
|
||||||
|
if (ls == nullptr) return false;
|
||||||
|
ls->clear();
|
||||||
|
|
||||||
|
// read count
|
||||||
|
CKDWORD count;
|
||||||
|
if (!this->ReadStruct(count)) return false;
|
||||||
|
|
||||||
|
// resize list and read it
|
||||||
|
ls->resize(count);
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
if (!this->ReadObjectID(ls->data() + i)) {
|
||||||
|
ls->clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::ReadManagerIntSequence(CKGUID* guid, XContainer::XArray<CKINT>* ls) {
|
||||||
|
if (guid == nullptr || ls == nullptr) return false;
|
||||||
|
|
||||||
|
// read count
|
||||||
|
CKDWORD count;
|
||||||
|
if (!this->ReadStruct(count)) return false;
|
||||||
|
|
||||||
|
// read guid
|
||||||
|
if (!this->ReadStruct(guid)) return false;
|
||||||
|
|
||||||
|
// resize list and read it
|
||||||
|
ls->resize(count);
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
if (!this->ReadStruct(ls->data() + i)) {
|
||||||
|
ls->clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::ReadSubChunkSequence(XContainer::XArray<CKStateChunk*>* ls) {
|
||||||
|
if (ls == nullptr) return false;
|
||||||
|
|
||||||
|
// clear first
|
||||||
|
for (auto& item : *ls) {
|
||||||
|
if (item != nullptr)
|
||||||
|
delete (item);
|
||||||
|
}
|
||||||
|
ls->clear();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::ReadXObjectArray(XContainer::XObjectArray* ls) {
|
||||||
|
if (ls == nullptr) return false;
|
||||||
|
ls->clear();
|
||||||
|
|
||||||
|
// read count
|
||||||
|
CKDWORD count;
|
||||||
|
if (!this->ReadStruct(count)) return false;
|
||||||
|
if (count == 0) return true; // 0 size array
|
||||||
|
|
||||||
|
// old file size correction
|
||||||
|
bool old_file = this->m_ChunkVersion < CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION1;
|
||||||
|
if (old_file) {
|
||||||
|
// skip 4. but I don't know why!!!
|
||||||
|
this->Skip(4);
|
||||||
|
if (!this->ReadStruct(count)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// resize list and read
|
||||||
|
ls->resize(count);
|
||||||
|
for (auto& id : *ls) {
|
||||||
|
// read ID first
|
||||||
|
CKINT cache;
|
||||||
|
if (!this->ReadStruct(cache)) {
|
||||||
|
ls->clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// in old file or no bind file, the read data directly is CK_ID.
|
||||||
|
// in new file or has bind file, the read data is the index in FileObjects
|
||||||
|
if (old_file || this->m_BindFile == nullptr) {
|
||||||
|
id = static_cast<CK_ID>(cache);
|
||||||
|
} else {
|
||||||
|
if (cache < 0) id = 0;
|
||||||
|
else id = this->m_BindFile->GetFileObjectByIndex(cache)->CreatedObjectId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::ReadXObjectPointerArray(XContainer::XObjectPointerArray* ls) {
|
||||||
|
if (ls == nullptr) return false;
|
||||||
|
|
||||||
|
// very very similar to ReadXObjectArray
|
||||||
|
// we execute it first.
|
||||||
|
XContainer::XObjectArray idarr;
|
||||||
|
if (!ReadXObjectArray(idarr)) return false;
|
||||||
|
|
||||||
|
// then convert it to pointer list
|
||||||
|
ls->resize(idarr.size());
|
||||||
|
for (size_t i = 0; i < idarr.size(); ++i) {
|
||||||
|
(*ls)[i] = m_BindContext->GetObject(idarr[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
61
LibCmo/CK2/CKStateChunkWriter.cpp
Normal file
61
LibCmo/CK2/CKStateChunkWriter.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#include "CKStateChunk.hpp"
|
||||||
|
#include "CKFile.hpp"
|
||||||
|
#include "CKContext.hpp"
|
||||||
|
|
||||||
|
namespace LibCmo::CK2 {
|
||||||
|
|
||||||
|
void CKStateChunk::StartWrite() {
|
||||||
|
if (this->m_Parser.m_Status != CKStateChunkStatus::IDLE) return;
|
||||||
|
|
||||||
|
// delete all current buffer
|
||||||
|
if (this->m_pData != nullptr) {
|
||||||
|
delete[] this->m_pData;
|
||||||
|
this->m_pData = nullptr;
|
||||||
|
}
|
||||||
|
this->m_DataDwSize = 0u;
|
||||||
|
|
||||||
|
// reset parser
|
||||||
|
this->m_Parser.m_CurrentPos = 0u;
|
||||||
|
this->m_Parser.m_DataSize = this->m_DataDwSize;
|
||||||
|
this->m_Parser.m_PrevIdentifierPos = 0u;
|
||||||
|
|
||||||
|
// force chunk version
|
||||||
|
this->m_ChunkVersion = CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION4;
|
||||||
|
|
||||||
|
// switch status
|
||||||
|
this->m_Parser.m_Status = CKStateChunkStatus::WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CKStateChunk::StopWrite(void) {
|
||||||
|
if (this->m_Parser.m_Status != CKStateChunkStatus::WRITE) return;
|
||||||
|
|
||||||
|
// update buffer size
|
||||||
|
this->m_DataDwSize = this->m_Parser.m_CurrentPos;
|
||||||
|
// shrink it
|
||||||
|
ResizeBuffer(this->m_DataDwSize);
|
||||||
|
|
||||||
|
// shrink 3 vector also
|
||||||
|
this->m_ObjectList.shrink_to_fit();
|
||||||
|
this->m_ManagerList.shrink_to_fit();
|
||||||
|
this->m_ChunkList.shrink_to_fit();
|
||||||
|
|
||||||
|
// reset parser
|
||||||
|
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::LockWriteBuffer(const void** ppData, CKDWORD size_in_byte) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CKStateChunk::UnLockWriteBuffer(CKDWORD size_in_byte) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CKStateChunk::LockedWriteBuffer_t CKStateChunk::LockWriteBufferWrapper(CKDWORD size_in_byte) {
|
||||||
|
return LockedWriteBuffer_t();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -179,6 +179,8 @@
|
||||||
<ClCompile Include="CK2\CKFileOthers.cpp" />
|
<ClCompile Include="CK2\CKFileOthers.cpp" />
|
||||||
<ClCompile Include="CK2\CKFileWriter.cpp" />
|
<ClCompile Include="CK2\CKFileWriter.cpp" />
|
||||||
<ClCompile Include="CK2\CKGlobals.cpp" />
|
<ClCompile Include="CK2\CKGlobals.cpp" />
|
||||||
|
<ClCompile Include="CK2\CKStateChunkReader.cpp" />
|
||||||
|
<ClCompile Include="CK2\CKStateChunkWriter.cpp" />
|
||||||
<ClCompile Include="CK2\DataHandlers\CKBitmapHandler.cpp" />
|
<ClCompile Include="CK2\DataHandlers\CKBitmapHandler.cpp" />
|
||||||
<ClCompile Include="CK2\MgrImpls\CKBaseManager.cpp" />
|
<ClCompile Include="CK2\MgrImpls\CKBaseManager.cpp" />
|
||||||
<ClCompile Include="CK2\CKContext.cpp" />
|
<ClCompile Include="CK2\CKContext.cpp" />
|
||||||
|
@ -195,7 +197,7 @@
|
||||||
<ClCompile Include="CK2\ObjImpls\CKTexture.cpp" />
|
<ClCompile Include="CK2\ObjImpls\CKTexture.cpp" />
|
||||||
<ClCompile Include="VTEncoding.cpp" />
|
<ClCompile Include="VTEncoding.cpp" />
|
||||||
<ClCompile Include="CK2\CKFileReader.cpp" />
|
<ClCompile Include="CK2\CKFileReader.cpp" />
|
||||||
<ClCompile Include="CK2\CKStateChunk.cpp" />
|
<ClCompile Include="CK2\CKStateChunkOthers.cpp" />
|
||||||
<ClCompile Include="VTImage.cpp" />
|
<ClCompile Include="VTImage.cpp" />
|
||||||
<ClCompile Include="VTUtils.cpp" />
|
<ClCompile Include="VTUtils.cpp" />
|
||||||
<ClCompile Include="VxMath\VxMath.cpp" />
|
<ClCompile Include="VxMath\VxMath.cpp" />
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
<ClCompile Include="CK2\CKContext.cpp">
|
<ClCompile Include="CK2\CKContext.cpp">
|
||||||
<Filter>Sources\CK2</Filter>
|
<Filter>Sources\CK2</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="CK2\CKStateChunk.cpp">
|
<ClCompile Include="CK2\CKStateChunkOthers.cpp">
|
||||||
<Filter>Sources\CK2</Filter>
|
<Filter>Sources\CK2</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="CK2\ObjImpls\CKSceneObject.cpp">
|
<ClCompile Include="CK2\ObjImpls\CKSceneObject.cpp">
|
||||||
|
@ -129,6 +129,12 @@
|
||||||
<ClCompile Include="XContainer\XTypes.cpp">
|
<ClCompile Include="XContainer\XTypes.cpp">
|
||||||
<Filter>Sources\XContainer</Filter>
|
<Filter>Sources\XContainer</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="CK2\CKStateChunkReader.cpp">
|
||||||
|
<Filter>Sources\CK2</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="CK2\CKStateChunkWriter.cpp">
|
||||||
|
<Filter>Sources\CK2</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="VTUtils.hpp">
|
<ClInclude Include="VTUtils.hpp">
|
||||||
|
|
Loading…
Reference in New Issue
Block a user