finish CKStateChunk refactor
This commit is contained in:
		| @ -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) { | ||||||
|  | |||||||
| @ -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 | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -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 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | |||||||
| @ -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()); | ||||||
|  |  | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user