update CKStateChunk

This commit is contained in:
yyc12345 2023-02-27 15:16:04 +08:00
parent 0519a557b8
commit 00a7e041c6
3 changed files with 339 additions and 27 deletions

View File

@ -26,6 +26,7 @@ namespace LibCmo {
using XIntArray = std::vector<int32_t>; using XIntArray = std::vector<int32_t>;
template<typename T> template<typename T>
using XClassArray = std::vector<T>; using XClassArray = std::vector<T>;
using XObjectArray = std::vector<CK_ID>;
//using CKObjectArray = std::vector<CKObject*>; //using CKObjectArray = std::vector<CKObject*>;
@ -131,6 +132,39 @@ namespace LibCmo {
VxMatrix(float m[4][4]) : m_Data() { std::memcpy(m_Data, m, sizeof(m_Data)); } VxMatrix(float m[4][4]) : m_Data() { std::memcpy(m_Data, m, sizeof(m_Data)); }
}; };
struct VxImageDescEx {
CK2::CKINT Size;
CK2::CKDWORD Flags;
CK2::CKINT Width;
CK2::CKINT Height;
union {
CK2::CKINT BytesPerLine;
CK2::CKINT TotalImageSize;
};
CK2::CKINT BitsPerPixel;
union {
CK2::CKDWORD RedMask;
CK2::CKDWORD BumpDuMask;
};
union {
CK2::CKDWORD GreenMask;
CK2::CKDWORD BumpDvMask;
};
union {
CK2::CKDWORD BlueMask;
CK2::CKDWORD BumpLumMask;
};
CK2::CKDWORD AlphaMask;
CK2::CKWORD BytesPerColorEntry;
CK2::CKWORD ColorMapEntries;
CK2::CKBYTE* ColorMap;
CK2::CKBYTE* Image;
};
} }
} }

View File

@ -17,8 +17,7 @@ namespace LibCmo::CK2 {
m_ClassId(rhs.m_ClassId), m_DataVersion(rhs.m_DataVersion), m_ChunkVersion(rhs.m_ChunkVersion), m_ClassId(rhs.m_ClassId), m_DataVersion(rhs.m_DataVersion), m_ChunkVersion(rhs.m_ChunkVersion),
m_Parser(rhs.m_Parser), m_Parser(rhs.m_Parser),
m_ObjectList(rhs.m_ObjectList), m_ManagerList(rhs.m_ManagerList), m_ChunkList(rhs.m_ChunkList), m_ObjectList(rhs.m_ObjectList), m_ManagerList(rhs.m_ManagerList), m_ChunkList(rhs.m_ChunkList),
m_pData(nullptr), m_DataDwSize(rhs.m_DataDwSize) m_pData(nullptr), m_DataDwSize(rhs.m_DataDwSize) {
{
// copy buffer // copy buffer
if (rhs.m_pData != nullptr) { if (rhs.m_pData != nullptr) {
this->m_pData = new(std::nothrow) CKDWORD[rhs.m_DataDwSize]; this->m_pData = new(std::nothrow) CKDWORD[rhs.m_DataDwSize];
@ -62,8 +61,8 @@ namespace LibCmo::CK2 {
void CKStateChunk::Clear(void) { void CKStateChunk::Clear(void) {
this->m_ClassId = CK_CLASSID::CKCID_OBJECT; this->m_ClassId = CK_CLASSID::CKCID_OBJECT;
//this->m_DataVersion = CK_STATECHUNK_DATAVERSION::CHUNK_DEV_2_1; this->m_DataVersion = CK_STATECHUNK_DATAVERSION::CHUNK_DEV_2_1;
//this->m_ChunkVersion = CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION4; this->m_ChunkVersion = CK_STATECHUNK_CHUNKVERSION::CHUNK_VERSION4;
this->m_Parser.m_CurrentPos = 0; this->m_Parser.m_CurrentPos = 0;
this->m_Parser.m_DataSize = 0; this->m_Parser.m_DataSize = 0;
@ -84,8 +83,82 @@ namespace LibCmo::CK2 {
return sizeof(CKDWORD) * this->m_DataDwSize; return sizeof(CKDWORD) * this->m_DataDwSize;
} }
void CKStateChunk::_EnsureWriteSpace(CKDWORD size) { CK_STATECHUNK_DATAVERSION CKStateChunk::GetDataVersion() {
; return this->m_DataVersion;
}
void CKStateChunk::SetDataVersion(CK_STATECHUNK_DATAVERSION version) {
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);
}
bool CKStateChunk::ResizeBuffer(CKDWORD new_dwsize) {
if (new_dwsize == 0u) {
// if reuqired size is zero, we just delete it
if (this->m_pData != nullptr) {
delete[] this->m_pData;
this->m_pData = nullptr;
}
} else {
// otherwise, we create a new buffer instead it
CKDWORD* newbuf = new(std::nothrow) CKDWORD[new_dwsize];
if (newbuf == nullptr) return false; // if fail to create, return
// if no original data, we do not need copy it and free it
if (this->m_pData != nullptr) {
std::memcpy(newbuf, this->m_pData, sizeof(CKDWORD) * new_dwsize);
delete[] this->m_pData;
}
// assign new buffer
this->m_pData = newbuf;
}
return true;
}
bool CKStateChunk::EnsureWriteSpace(CKDWORD dwsize) {
if (this->m_Parser.m_Status != CKStateChunkStatus::WRITE) return false;
// check whether need enlarge
CKDWORD needed = dwsize + this->m_Parser.m_CurrentPos;
if (needed > this->m_Parser.m_DataSize) {
// add a very enough space to buffer
if (dwsize < 512) dwsize = 512;
needed = dwsize + this->m_Parser.m_CurrentPos;
// try resizing it
this->ResizeBuffer(needed);
// update size
this->m_Parser.m_DataSize = needed;
}
}
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;
} }
@ -258,9 +331,7 @@ namespace LibCmo::CK2 {
// return true; // return true;
//} //}
bool CKStateChunk::SeekIdentifier(CKDWORD identifier) { #pragma region Read Functions
return false;
}
void CKStateChunk::StartRead(void) { void CKStateChunk::StartRead(void) {
if (this->m_Parser.m_Status != CKStateChunkStatus::IDLE) return; if (this->m_Parser.m_Status != CKStateChunkStatus::IDLE) return;
@ -271,8 +342,116 @@ namespace LibCmo::CK2 {
this->m_Parser.m_Status = CKStateChunkStatus::READ; this->m_Parser.m_Status = CKStateChunkStatus::READ;
} }
void CKStateChunk::ReadString(std::string& strl) { bool CKStateChunk::SeekIdentifier(CKDWORD identifier) {
; CKDWORD cache;
return SeekIdentifierAndReturnSize(identifier, &cache);
} }
bool CKStateChunk::SeekIdentifierAndReturnSize(CKDWORD identifier, CKDWORD* out_size) {
if (this->m_Parser.m_Status != CKStateChunkStatus::READ) return false;
CKDWORD pos = 0u;
if (this->m_DataDwSize < 2) 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 = sizeof(CKDWORD) * (nextptr - pos);
return true;
}
CKERROR CKStateChunk::ReadString(std::string& strl) {
// get byte based size
CKDWORD strByteSize = 0u;
CKERROR err = this->ReadStructPtr(&strByteSize);
if (err != CKERROR::CKERR_OK) {
strl.clear();
return err;
}
// 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();
}
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;
}
#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;
}
#pragma endregion
} }

View File

@ -2,6 +2,8 @@
#include "CKDefines.hpp" #include "CKDefines.hpp"
#include "CKEnums.hpp" #include "CKEnums.hpp"
#include <type_traits>
#include <cinttypes>
namespace LibCmo::CK2 { namespace LibCmo::CK2 {
@ -12,19 +14,6 @@ namespace LibCmo::CK2 {
CKStateChunk& operator=(const CKStateChunk&); CKStateChunk& operator=(const CKStateChunk&);
~CKStateChunk(); ~CKStateChunk();
void Clear(void);
bool ConvertFromBuffer(const void* buf);
CKDWORD ConvertToBuffer(void* buf);
//bool UnPack(CKDWORD DestSize);
CKDWORD GetDataSize(void);
bool SeekIdentifier(CKDWORD identifier);
void StartRead(void);
void ReadString(std::string& strl);
private: private:
enum class CKStateChunkStatus : int32_t { enum class CKStateChunkStatus : int32_t {
IDLE, IDLE,
@ -51,10 +40,120 @@ namespace LibCmo::CK2 {
std::vector<CKDWORD> m_ManagerList; std::vector<CKDWORD> m_ManagerList;
private: private:
void _EnsureWriteSpace(CKDWORD size); inline size_t GetCeilDwordSize(size_t char_size) {
inline bool _EnsureReadSpace(CKDWORD required) { return (char_size + 3) >> 3;
return (this->m_Parser.m_CurrentPos <= this->m_Parser.m_DataSize) && (required <= (this->m_Parser.m_DataSize - this->m_Parser.m_CurrentPos));
} }
bool ResizeBuffer(CKDWORD new_dwsize);
bool EnsureWriteSpace(CKDWORD dwsize);
bool EnsureReadSpace(CKDWORD dword_required);
public:
bool ConvertFromBuffer(const void* buf);
CKDWORD ConvertToBuffer(void* buf);
//bool UnPack(CKDWORD DestSize);
void Clear(void);
CKDWORD GetDataSize(void);
CK_STATECHUNK_DATAVERSION GetDataVersion();
void SetDataVersion(CK_STATECHUNK_DATAVERSION version);
bool Skip(CKDWORD DwordCount);
#pragma region Read Function
public:
void StartRead(void);
bool SeekIdentifier(CKDWORD identifier);
bool SeekIdentifierAndReturnSize(CKDWORD identifier, CKDWORD* out_size);
CKERROR ReadString(std::string& strl);
/*
* Read Struct
Primitive type: ReadInt, ReadByte, ReadWord, ReadDword, ReadFloat, etc...
Struct type: ReadGuid, ReadVector, ReadMatrix, etc...
Both of them are redirected to this.
*/
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);
} return CKERROR::CKERR_OUTOFMEMORY;
return CKERROR::CKERR_OK;
}
/*
* Read Struct
A wrapper for ReadStructPtr.
Use reference, not pointer.
*/
template<typename T>
inline CKERROR ReadStructRef(T& data) {
return ReadStructPtr(&data);
}
/*
* 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 ReadBuffer(void* allocatedBuf);
CKERROR ReadNoSizeBuffer(CKDWORD size, void* allocatedBuf);
//int ReadInt();
//int StartReadSequence();
//CK_ID ReadObjectID();
//CKStateChunk* ReadSubChunk();
//int StartManagerReadSequence(CKGUID* guid);
//CKGUID ReadGuid();
//void ReadAndFillBuffer_LEndian(void* buffer);
//void ReadAndFillBuffer_LEndian16(void* buffer);
//float ReadFloat();
//CKWORD ReadWord();
//CKDWORD ReadDword();
//CKDWORD ReadDwordAsWords();
//void ReadVector(VxMath::VxVector* v);
//void ReadMatrix(VxMath::VxMatrix& mat);
//CKObjectImplements::CKObject* ReadObject(CKMinContext*);
//void ReadAndFillBuffer(void* buffer);
//CKBYTE* ReadRawBitmap(VxMath::VxImageDescEx& desc);
//XObjectArray ReadXObjectArray(void);
void StopRead(void);
#pragma endregion
#pragma region Write Function
public:
void StartWrite();
//void WriteIdentifier(CKDWORD id);
//void AddChunkAndDelete(CKStateChunk*);
//void StartObjectIDSequence(int count);
//void WriteObjectSequence(CKObjectImplements::CKObject* obj);
//void WriteInt(int data);
//void WriteFloat(float data);
//void WriteDword(CKDWORD data);
//void WriteDwordAsWords(CKDWORD data);
//void WriteVector(const VxMath::VxVector* v);
//void WriteMatrix(const VxMath::VxMatrix& mat);
//void WriteObject(CKObjectImplements::CKObject* obj);
//void WriteBuffer_LEndian(int size, void* buf);
//void WriteBuffer_LEndian16(int size, void* buf);
//void WriteBufferNoSize_LEndian(int size, void* buf);
///*void UpdateDataSize();*/
//void* LockWriteBuffer(int DwordCount);
/*
* Old Name: CloseChunk();
*/
void StopWrite(void);
#pragma endregion
}; };
} }