finish CKStateChunk refactor

This commit is contained in:
yyc12345 2023-09-18 16:37:05 +08:00
parent 50784e719c
commit 81d1e80d14
5 changed files with 289 additions and 188 deletions

View File

@ -30,16 +30,18 @@ namespace LibCmo::CK2 {
chk->ReadStruct(imgbytesize); chk->ReadStruct(imgbytesize);
if (imgbytesize != 0) { if (imgbytesize != 0) {
// get image data ptr // get image data ptr
const void* imgdata = nullptr; auto imgdata = chk->LockReadBufferWrapper(imgbytesize);
if (!chk->ReadDryBuffer(&imgdata, imgbytesize)) { if (imgdata == nullptr) {
return false; return false;
} }
// parse image // parse image
VxMath::VxImageDescEx cache; VxMath::VxImageDescEx cache;
if (!reader->ReadMemory(imgdata, imgbytesize, &cache)) { if (!reader->ReadMemory(imgdata.get(), imgbytesize, &cache)) {
return false; return false;
} }
// unlock buffer
imgdata.reset();
// post proc image (copy to slot) // post proc image (copy to slot)
VxMath::VxDoBlit(&cache, slot); VxMath::VxDoBlit(&cache, slot);
@ -53,9 +55,7 @@ namespace LibCmo::CK2 {
chk->ReadStruct(globalalpha); chk->ReadStruct(globalalpha);
VxMath::VxDoAlphaBlit(slot, static_cast<CKBYTE>(globalalpha)); VxMath::VxDoAlphaBlit(slot, static_cast<CKBYTE>(globalalpha));
} else { } else {
CKStateChunk::TBuffer alphabuf; auto alphabuf = chk->ReadBufferWrapper();
CKDWORD buflen;
chk->ReadBufferWrapper(&alphabuf, &buflen);
VxMath::VxDoAlphaBlit(slot, reinterpret_cast<CKBYTE*>(alphabuf.get())); VxMath::VxDoAlphaBlit(slot, reinterpret_cast<CKBYTE*>(alphabuf.get()));
} }
} }
@ -78,7 +78,7 @@ namespace LibCmo::CK2 {
chk->ReadStruct(blueMask); chk->ReadStruct(blueMask);
// read RGBA buffer // read RGBA buffer
CKStateChunk::TBuffer redBuffer, greenBuffer, blueBuffer, alphaBuffer; CKStateChunk::Buffer_t redBuffer, greenBuffer, blueBuffer, alphaBuffer;
CKDWORD bufsize; CKDWORD bufsize;
CKDWORD bufopt; CKDWORD bufopt;
chk->ReadStruct(bufopt); chk->ReadStruct(bufopt);
@ -90,11 +90,11 @@ namespace LibCmo::CK2 {
// so return false simply // so return false simply
return false; return false;
} else { } else {
chk->ReadBufferWrapper(&blueBuffer, &bufsize); blueBuffer = chk->ReadBufferWrapper();
chk->ReadBufferWrapper(&greenBuffer, &bufsize); greenBuffer = chk->ReadBufferWrapper();
chk->ReadBufferWrapper(&redBuffer, &bufsize); redBuffer = chk->ReadBufferWrapper();
} }
chk->ReadBufferWrapper(&alphaBuffer, &bufsize); alphaBuffer = chk->ReadBufferWrapper();
// write into file // write into file
if (redBuffer != nullptr && greenBuffer != nullptr && blueBuffer != nullptr) { if (redBuffer != nullptr && greenBuffer != nullptr && blueBuffer != nullptr) {

View File

@ -99,6 +99,37 @@ namespace LibCmo::CK2 {
#pragma endregion #pragma endregion
#pragma region Self Used Data Struct
void CKStateChunk::LockedReadBufferDeleter::operator()(LIBCMO_UNUSED const void* buf) {
if (m_Host == nullptr) return;
m_Host->UnLockReadBuffer(m_ConsumedSize);
}
void CKStateChunk::LockedReadBufferDeleter::SetConsumedSize(CKDWORD newsize) {
m_ConsumedSize = newsize;
}
void CKStateChunk::LockedWriteBufferDeleter::operator()(LIBCMO_UNUSED const void* buf) {
if (m_Host == nullptr) return;
m_Host->UnLockWriteBuffer(m_ConsumedSize);
}
void CKStateChunk::LockedWriteBufferDeleter::SetConsumedSize(CKDWORD newsize) {
m_ConsumedSize = newsize;
}
void CKStateChunk::BufferDeleter::operator()(const void* buf) {
if (m_Host == nullptr) return;
m_Host->DeleteBuffer(buf);
}
CKDWORD CKStateChunk::BufferDeleter::GetBufferSize() const {
return m_BufSize;
}
#pragma endregion
#pragma region Misc Funcs #pragma region Misc Funcs
// ========== Public Funcs ========== // ========== Public Funcs ==========
@ -525,24 +556,66 @@ namespace LibCmo::CK2 {
return true; return true;
} }
bool CKStateChunk::LockReadBuffer(const void** ppData, CKDWORD size_in_byte) {
/* ========== Basic Data Read Functions ==========*/ // check arguments
if (*ppData == nullptr) return false;
bool CKStateChunk::ReadByteData(void* data_ptr, CKDWORD size_in_byte) { *ppData = nullptr;
// check self status
if (this->m_Parser.m_Status != CKStateChunkStatus::READ) return false; if (this->m_Parser.m_Status != CKStateChunkStatus::READ) return false;
// get corresponding size
CKDWORD size_in_dword = this->GetCeilDwordSize(size_in_byte); 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)) { if (this->EnsureReadSpace(size_in_dword)) {
// only copy when data_ptr is not nullptr
// do dry run if there are no dest to copy for.
if (data_ptr != nullptr) {
std::memcpy(data_ptr, this->m_pData + this->m_Parser.m_CurrentPos, size_in_byte);
}
this->m_Parser.m_CurrentPos += size_in_dword; this->m_Parser.m_CurrentPos += size_in_dword;
return true; return true;
} else { } else {
// failed, report to context // failed, report to context
m_BindContext->OutputToConsoleEx("CKStateChunk read length error at %" PRIuCKDWORD ".", this->m_Parser.m_CurrentPos); 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; return false;
} }
} }
@ -753,38 +826,22 @@ namespace LibCmo::CK2 {
return true; return true;
} }
bool CKStateChunk::ReadBufferWrapper(TBuffer* uptr, CKDWORD* len_in_byte) {
if (uptr == nullptr || len_in_byte == nullptr) return false;
void* bufcache = nullptr;
bool ret = ReadBuffer(&bufcache, len_in_byte);
uptr->reset(bufcache);
return ret;
}
bool CKStateChunk::ReadDryBuffer(const void** buf, CKDWORD ordered_size) {
if (buf == nullptr) return false;
// backup current pos
*buf = GetCurrentPointer();
if (!this->ReadByteData(nullptr, ordered_size)) {
*buf = nullptr;
return false;
}
return true;
}
void CKStateChunk::BufferDeleter::operator()(void* buf) {
if (buf == nullptr) return;
delete[] reinterpret_cast<const CKBYTE*>(buf);
}
void CKStateChunk::DeleteBuffer(const void* buf) { void CKStateChunk::DeleteBuffer(const void* buf) {
if (buf == nullptr) return; if (buf == nullptr) return;
delete[] reinterpret_cast<const CKBYTE*>(buf); 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 ==========*/ /* ========== Sequence Functions ==========*/
bool CKStateChunk::ReadObjectIDSequence(XContainer::XArray<CK_ID>* ls) { bool CKStateChunk::ReadObjectIDSequence(XContainer::XArray<CK_ID>* ls) {
@ -966,6 +1023,18 @@ namespace LibCmo::CK2 {
this->m_Parser.m_Status = CKStateChunkStatus::IDLE; 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 #pragma endregion
} }

View File

@ -37,69 +37,52 @@ namespace LibCmo::CK2 {
void* m_DataPtr; void* m_DataPtr;
CKDWORD m_AreaSize; CKDWORD m_AreaSize;
}; };
template<bool _TCanWrite>
class LockedBuffer_t { class LockedReadBufferDeleter {
public: public:
/** LockedReadBufferDeleter() : m_Host(nullptr), m_ConsumedSize(0) {}
* @brief The type of free function called by this class. LockedReadBufferDeleter(CKStateChunk* host, CKDWORD init_size) :
* It must have 2 argument, first one is buffer need to be free, second is consumed size. m_Host(host), m_ConsumedSize(init_size) {}
*/ LIBCMO_DEFAULT_COPY_MOVE(LockedReadBufferDeleter);
using FreeFct = std::function<void(const void*,CKDWORD)>;
LockedBuffer_t() : m_Ptr(nullptr), m_ConsumedByteSize(0), m_FreeFct(nullptr) {} void operator()(LIBCMO_UNUSED const void* buf);
LockedBuffer_t(const void* ptr, CKDWORD expectedByteSize, FreeFct fct) : void SetConsumedSize(CKDWORD newsize);
m_Ptr(const_cast<CKBYTE*>(static_cast<const CKBYTE*>(ptr))), m_ConsumedByteSize(expectedByteSize), m_FreeFct(fct) {}
LockedBuffer_t(const LockedBuffer_t&) = delete;
LockedBuffer_t& operator=(const LockedBuffer_t&) = delete;
LockedBuffer_t(LockedBuffer_t&& rhs) :
m_Ptr(rhs.m_Ptr), m_ConsumedByteSize(rhs.m_ConsumedByteSize), m_FreeFct(rhs.m_FreeFct) {
rhs.m_Ptr = nullptr;
rhs.m_ConsumedByteSize = 0;
rhs.m_FreeFct = nullptr;
}
LockedBuffer_t& operator=(LockedBuffer_t&& rhs) {
// reset self
Reset();
// copy data
m_Ptr = rhs.m_Ptr;
m_ConsumedByteSize = rhs.m_ConsumedByteSize;
m_FreeFct = rhs.m_FreeFct;
// remove rhs data.
rhs.m_Ptr = nullptr;
rhs.m_ConsumedByteSize = 0;
rhs.m_FreeFct = nullptr;
}
~LockedBuffer_t() {
Reset();
}
const void* GetPtr() const {
return m_Ptr;
}
// References:
// https://stackoverflow.com/questions/43051882/how-to-disable-a-class-member-function-for-certain-template-types
// https://stackoverflow.com/questions/13964447/why-compile-error-with-enable-if
template<bool _UCanWrite = _TCanWrite, std::enable_if_t<sizeof(_UCanWrite) && _TCanWrite, int> = 0>
void* GetMutablePtr() {
return m_Ptr;
}
void SetRealConsumedSize(CKDWORD sizeInByte) {
m_ConsumedByteSize = sizeInByte;
}
void Reset() {
if (m_Ptr == nullptr) return;
if (m_FreeFct == nullptr) return;
m_FreeFct(m_Ptr, m_ConsumedByteSize);
m_Ptr = nullptr;
m_ConsumedByteSize = 0;
m_FreeFct = nullptr;
}
private: private:
CKBYTE* m_Ptr; CKStateChunk* m_Host;
CKDWORD m_ConsumedByteSize; CKDWORD m_ConsumedSize;
FreeFct m_FreeFct;
}; };
class LockedWriteBufferDeleter {
public:
LockedWriteBufferDeleter() : m_Host(nullptr), m_ConsumedSize(0) {}
LockedWriteBufferDeleter(CKStateChunk* host, CKDWORD init_size) :
m_Host(host), m_ConsumedSize(init_size) {}
LIBCMO_DEFAULT_COPY_MOVE(LockedWriteBufferDeleter);
void operator()(LIBCMO_UNUSED const void* buf);
void SetConsumedSize(CKDWORD newsize);
private:
CKStateChunk* m_Host;
CKDWORD m_ConsumedSize;
};
class BufferDeleter {
public:
BufferDeleter() : m_Host(nullptr), m_BufSize(0) {}
BufferDeleter(CKStateChunk* host, CKDWORD bufsize) :
m_Host(host), m_BufSize(bufsize) {}
LIBCMO_DEFAULT_COPY_MOVE(BufferDeleter);
void operator()(const void* buf);
CKDWORD GetBufferSize() const;
private:
CKStateChunk* m_Host;
CKDWORD m_BufSize;
};
using LockedReadBuffer_t = std::unique_ptr<const void, LockedReadBufferDeleter>;
using LockedWriteBuffer_t = std::unique_ptr<void, LockedWriteBufferDeleter>;
using Buffer_t = std::unique_ptr<void, BufferDeleter>;
private: private:
enum class CKStateChunkStatus : CKDWORD { enum class CKStateChunkStatus : CKDWORD {
@ -226,44 +209,91 @@ namespace LibCmo::CK2 {
return SeekIdentifierDwordAndReturnSize(static_cast<CKDWORD>(enum_v), out_size); return SeekIdentifierDwordAndReturnSize(static_cast<CKDWORD>(enum_v), out_size);
} }
/* ========== Read Buffer Controller ==========*/
public:
/**
* @brief Lock read buffer and make sure it has at least some bytes to read.
* @param ppData[out] The pointer to pointer receiving data address.
* @param size_in_byte[in] The number of bytes present in the read buffer needs to be ensured.
* @return Treu if success (can read)
* @remark
* + It actually not lock the buffer, just make sure that the read area is okey.
* + Do not forget calling UnLockReadBuffer after all read work done.
* @see UnLockReadBuffer, ReadBufferLocker
*/
bool LockReadBuffer(const void** ppData, CKDWORD size_in_byte);
/**
* @brief Unlock read buffer and move forward with specified bytes.
* @param size_in_byte[in] The number of bytes you wish to move forward.
* This value can be different with the value passed to LockReadBuffer but should not greater than it.
* @return True if success (have enough space to move forward)
* @remark
* + It actually not unlock the buffer, just move forward reading pointer.
* + Used together with LockReadBuffer.
* @see LockReadBuffer
*/
bool UnLockReadBuffer(CKDWORD size_in_byte);
/**
* @brief A RAII wrapper for LockReadBuffer and UnLockReadBuffer.
* @param size_in_byte[in] The value passed to LockReadBuffer.
* @return A read-only buffer with RAII feature (more like std::unique_ptr).
* @remark
* + The return value is more like std::unique_ptr but it have more features.
* + If GeneralBuffer_t::GetPtr return nullptr, it mean this function is failed.
* + If you only use the pointer-getter provided by the return value, the final moving forward byte count is the value passed in this function.
* + You also can use GeneralBuffer_t::SetSize to set the final moving forward byte count before the return value free itself.
* + The value passed to GeneralBuffer_t::SetSize will finally be passed to UnLockReadBuffer.
* + You can use GeneralBuffer_t::Reset to force free the return value.
* @example
* ```
* LockedReadBuffer_t buf = ReadBufferLocker(1919810);
* if (buf.GetPtr() == nullptr) {
* // failed
* } else {
* stuff(buf); // do some operation...
* buf.SetSize(114514); // i only consume these bytes.
* buf.Reset(); // immediately free it.
* }
* ```
* @see LockReadBuffer, UnLockReadBuffer, LockedReadBuffer_t
*/
LockedReadBuffer_t LockReadBufferWrapper(CKDWORD size_in_byte);
/* ========== Basic Data Read Functions ==========*/ /* ========== Basic Data Read Functions ==========*/
private: private:
bool LockReadBuffer(void** ppData, CKDWORD expectedByteSize);
bool UnLockReadBuffer(CKDWORD realConsumedByteSize);
/** /**
* @brief The base read function for all data. * @brief A struct-read-friendly wrapper for LockReadBuffer and UnLockReadBuffer.
* This function will check all read requirements. * All following struct reading function use this function as a underlaying calling.
* If you have use this function or functions calling this function. You do not need check any reading requirements anymore.
* @param data_ptr[out] the pointer to data. must be allocated first. * @param data_ptr[out] the pointer to data. must be allocated first.
* @param size_in_byte[in] the size of data in byte. * @param size_in_byte[in] the size of data in byte.
* @return True if success. * @return True if success.
*/ */
bool ReadByteData(void* data_ptr, CKDWORD size_in_byte); bool ReadByteData(void* data_ptr, CKDWORD size_in_byte);
public: public:
/// <summary> /**
/// Read Struct * @brief Read Struct
/// <para>Primitive type: ReadInt, ReadByte, ReadWord, ReadDword, ReadFloat, etc...</para> * @tparam T The reading type.
/// <para>Struct type: ReadGuid, ReadVector, ReadMatrix, etc...</para> * @param data Data pointer for reading. Can not be bullptr
/// <para>Both of them are redirected to this.</para> * @return True if reading success.
/// </summary> * @remark
/// <typeparam name="T"></typeparam> * + This function is a reinterpter of a bunch of original Virtools SDK reading functions, including:
/// <param name="data"></param> * - Primitive type: ReadInt, ReadByte, ReadWord, ReadDword, ReadFloat, etc...
/// <returns></returns> * - Struct type: ReadGuid, ReadVector, ReadMatrix, etc...
* @see ReadStruct(T&)
*/
template<typename T> template<typename T>
bool ReadStruct(T* data) { bool ReadStruct(T* data) {
return ReadByteData(data, CKSizeof(T)); return ReadByteData(data, CKSizeof(T));
} }
/// <summary> /**
/// Read Struct * @brief Read Struct (Reference Type)
/// <para>A wrapper for ReadStructPtr.</para> * @tparam T The reading type.
/// <para>Use reference, not pointer.</para> * @param data Data reference for reading.
/// </summary> * @return True if reading success.
/// <typeparam name="T"></typeparam> * @see ReadStruct(T*)
/// <param name="data"></param> */
/// <returns></returns>
template<typename T> template<typename T>
inline bool ReadStruct(T& data) { inline bool ReadStruct(T& data) {
return ReadByteData(&data, CKSizeof(T)); return ReadByteData(&data, CKSizeof(T));
@ -291,14 +321,12 @@ namespace LibCmo::CK2 {
return ReadManagerInt(&guid, &intval); return ReadManagerInt(&guid, &intval);
} }
/// <summary> /**
/// Read sub chunk * @brief Read sub chunk
/// <para>Return nullptr if failed.</para> * @return Returned a new created of CKStateChunk if success, otherwise nullptr.
/// <para>Returned CKStateChunk should be manually released!</para> * Returned CKStateChunk should be manually released!
/// </summary> */
/// <param name=""></param> CKStateChunk* ReadSubChunk();
/// <returns></returns>
CKStateChunk* ReadSubChunk(void);
/* ========== Buffer Functions ==========*/ /* ========== Buffer Functions ==========*/
@ -315,61 +343,63 @@ namespace LibCmo::CK2 {
*/ */
/** /**
* @brief The deleter for std::unique_ptr of CKStateChunk created buffer. * @brief Read a buffer with unknow size (order user specific it).
* @param size_in_byte[in] The size of buffer.
* @param allocatedBuf[out] Buffer for filling.
* @return true if success.
* @remark
* + Following original Virtools functions can use this function to implement:
* - ReadAndFillBuffer(int, void*)
* - ReadAndFillBuffer_LEndian(int, void*)
* - ReadAndFillBuffer_LEndian16(int, void*)
*/ */
struct BufferDeleter {
BufferDeleter() = default;
BufferDeleter(const BufferDeleter&) noexcept {}
void operator()(void* buf);
};
/**
* @brief The type of CKStateChunk auto free buffer.
*/
using TBuffer = std::unique_ptr<void, BufferDeleter>;
/// <summary>
/// Read a buffer with unknow size (order user specific it).
/// <para>ReadAndFillBuffer(int, void*), ReadAndFillBuffer_LEndian(int, void*), ReadAndFillBuffer_LEndian16(int, void*) are redirected to this.</para>
/// <para>The buffer should be allocated by caller first.</para>
/// </summary>
/// <param name="size"></param>
/// <param name="allocatedBuf"></param>
/// <returns></returns>
bool ReadNoSizeBuffer(CKDWORD size_in_byte, void* allocatedBuf); bool ReadNoSizeBuffer(CKDWORD size_in_byte, void* allocatedBuf);
/// <summary>
/// Read a buffer with knowen size stored in chunk.
/// <para>ReadBuffer(void**), ReadAndFillBuffer(void*), ReadAndFillBuffer_LEndian(void*), ReadAndFillBuffer_LEndian16(void*) are redirected to this.</para>
/// <para>The buffer will be allocated by function.</para>
/// <para>Use CKStateChunk::DeleteBuffer() to delete it.</para>
/// </summary>
/// <param name="buf">a pointer to the pointer receiving data start address.</param>
/// <param name="len">a pointer to the variable receiving the length of gotten buffer.</param>
/// <returns></returns>
bool ReadBuffer(void** buf, CKDWORD* len_in_byte);
/** /**
* @brief A auto free wrapper for ReadBuffer * @brief Read a buffer with knowen size stored in chunk.
* @param uptr The pointer to unique_ptr receiving data.
* @param len_in_byte The size of gotten buffer.
* @return
*/
bool ReadBufferWrapper(TBuffer* uptr, CKDWORD* len_in_byte);
/**
* @brief Perform a dry buffer reading.
* This function will only make sure there is enough space for your reading.
* And return the start memory address to you.
* And will not create any extra memory like ReadBuffer.
* @param buf[out] a pointer to the pointer receiving data start address. * @param buf[out] a pointer to the pointer receiving data start address.
* @param ordered_sizepin] your expected length of this buffer. * @param len_in_byte[out] a pointer to the variable receiving the length of gotten buffer.
* @return * @return true if success.
* @remark
* + Following original Virtools functions can use this function to implement:
* - ReadBuffer(void**)
* - ReadAndFillBuffer(void*)
* - ReadAndFillBuffer_LEndian(void*)
* - ReadAndFillBuffer_LEndian16(void*)
* + The created buffer should be freed by DeleteBuffer().
*/ */
bool ReadDryBuffer(const void** buf, CKDWORD ordered_size); bool ReadBuffer(void** buf, CKDWORD* len_in_byte);
/** /**
* @brief Free the buffer allocated by CKStateChunk reading functions. * @brief Free the buffer allocated by CKStateChunk reading functions.
* @param buf The buffer need to be free. * @param buf[in] The buffer need to be free.
* @see ReadBuffer
*/ */
void DeleteBuffer(const void* buf); void DeleteBuffer(const void* buf);
/**
* @brief A RAII wrapper for ReadBuffer and DeleteBuffer
* @param uptr The pointer to unique_ptr receiving data.
* @param len_in_byte The size of gotten buffer.
* @return A buffer with RAII feature (more like std::unique_ptr).
* @remark
* + The return value is more like std::unique_ptr but it have more features.
* + If Buffer_t::GetPtr return nullptr, it mean this function is failed.
* + Use Buffer_t::GetSize to get the size of buffer.
* + You can use Buffer_t::Reset to force free the return value.
* @example
* ```
* Buffer_t buf = ReadBufferWrapper(1919810);
* if (buf.GetPtr() == nullptr) {
* // failed
* } else {
* stuff(buf); // do some operation...
* buf.SetSize(114514); // i only consume these bytes.
* buf.Reset(); // immediately free it.
* }
* ```
*/
Buffer_t ReadBufferWrapper();
/* ========== Sequence Functions ==========*/ /* ========== Sequence Functions ==========*/
/// <summary> /// <summary>
@ -476,6 +506,10 @@ namespace LibCmo::CK2 {
*/ */
void StopWrite(void); void StopWrite(void);
bool LockWriteBuffer(const void** ppData, CKDWORD size_in_byte);
bool UnLockWriteBuffer(CKDWORD size_in_byte);
LockedWriteBuffer_t LockWriteBufferWrapper(CKDWORD size_in_byte);
#pragma endregion #pragma endregion

View File

@ -168,9 +168,7 @@ namespace LibCmo::CK2::ObjImpls {
// save properties // save properties
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXSAVEFORMAT)) { if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXSAVEFORMAT)) {
CKDWORD bufsize; auto buf = chunk->ReadBufferWrapper();
CKStateChunk::TBuffer buf;
chunk->ReadBufferWrapper(&buf, &bufsize);
if (buf != nullptr) { if (buf != nullptr) {
FakeBitmapProperties* props = reinterpret_cast<FakeBitmapProperties*>(buf.get()); FakeBitmapProperties* props = reinterpret_cast<FakeBitmapProperties*>(buf.get());

View File

@ -222,7 +222,7 @@ namespace Unvirt::StructFormatter {
// write identifiers // write identifiers
operchunk->StartRead(); operchunk->StartRead();
const auto collection = operchunk->GetIdentifierProfile(); const auto collection = operchunk->GetIdentifiersProfile();
operchunk->StopRead(); operchunk->StopRead();
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("Identifiers\n")), stdout); fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("Identifiers\n")), stdout);
fputs("Identifier\tData Pointer\tData Size\n", stdout); fputs("Identifier\tData Pointer\tData Size\n", stdout);