#pragma once #include "Loading/ILoadingStream.h" #include "Utils/MemoryManager.h" #include "Zone/Stream/IZoneStream.h" #include "Zone/XBlock.h" #include #include #include #include class ZoneStreamFillReadAccessor { public: ZoneStreamFillReadAccessor(const void* dataBuffer, void* blockBuffer, size_t bufferSize, unsigned pointerByteCount); [[nodiscard]] ZoneStreamFillReadAccessor AtOffset(size_t offset) const; template void Fill(T& value, const size_t offset) const { assert(offset + sizeof(T) <= m_buffer_size); value = *reinterpret_cast(static_cast(m_data_buffer) + offset); } template void FillArray(T (&value)[S], const size_t offset) const { assert(offset + sizeof(T) * S <= m_buffer_size); std::memcpy(value, static_cast(m_data_buffer) + offset, sizeof(T) * S); } template void FillPtr(T*& value, const size_t offset) const { assert(offset + m_pointer_byte_count <= m_buffer_size); assert(m_pointer_byte_count <= sizeof(uintptr_t)); value = nullptr; std::memcpy(&value, static_cast(m_data_buffer) + offset, m_pointer_byte_count); } void InsertPointerRedirect(uintptr_t aliasValue, size_t offset) const; private: const void* m_data_buffer; void* m_block_buffer; size_t m_buffer_size; unsigned m_pointer_byte_count; }; class ZoneInputStream : public IZoneStream { public: /** * \brief Returns the configured bits that make up a pointer. */ [[nodiscard]] virtual unsigned GetPointerBitCount() const = 0; /** * \brief Retrieves the new read position in the current block by aligning the position with the specified value and then returning the current read * position in the block. * \param align The alignment value that the read position is aligned with before being returned. This should typically be the alignment of the struct that * should be read afterward. * \return A pointer to the memory in which following load calls will load data to. */ virtual void* Alloc(unsigned align) = 0; /** * \copydoc ZoneInputStream#Alloc(unsigned) */ template T* Alloc(const unsigned align) { return static_cast(Alloc(align)); } virtual void* AllocOutOfBlock(unsigned align, size_t size) = 0; /** * \copydoc ZoneInputStream#AllocOutOfBlock(unsigned) */ template T* AllocOutOfBlock(const unsigned align, const size_t arraySize = 1u) { return static_cast(AllocOutOfBlock(align, sizeof(T) * arraySize)); } /** * \brief Loads data from the underlying stream without considering the current block or advancing the block position. * The data is read directly to the specified location instead of block memory. * \param dst The memory location to load data to. * \param size The amount of data to load. */ virtual void LoadDataRaw(void* dst, size_t size) = 0; /** * \brief Loads data with the current blocks read operation into its block memory. * Depending on the block type, the underlying stream might be read from or not. * The current block position is advanced by the number of bytes read. * The destination must be inside the current block's memory space, otherwise an exception is thrown. * \param dst The destination where the data is loaded to. Must be inside the current block's memory bounds. * \param size The amount of data to load. */ virtual void LoadDataInBlock(void* dst, size_t size) = 0; virtual void LoadNullTerminated(void* dst) = 0; virtual ZoneStreamFillReadAccessor LoadWithFill(size_t size) = 0; template void Load(T* dst) { LoadDataInBlock(const_cast(reinterpret_cast(dst)), sizeof(T)); } template void Load(T* dst, const size_t count) { LoadDataInBlock(const_cast(reinterpret_cast(dst)), count * sizeof(T)); } template void LoadPartial(T* dst, const size_t size) { LoadDataInBlock(const_cast(reinterpret_cast(dst)), size); } virtual void* InsertPointerNative() = 0; template T** InsertPointerNative() { return static_cast(InsertPointerNative()); } virtual uintptr_t InsertPointerAliasLookup() = 0; virtual void SetInsertedPointerAliasLookup(uintptr_t lookupEntry, void* value) = 0; virtual void* ConvertOffsetToPointerNative(const void* offset) = 0; template T* ConvertOffsetToPointerNative(T* offset) { return static_cast(ConvertOffsetToPointerNative(static_cast(offset))); } virtual void* ConvertOffsetToAliasNative(const void* offset) = 0; template T* ConvertOffsetToAliasNative(T* offset) { return static_cast(ConvertOffsetToAliasNative(static_cast(offset))); } virtual uintptr_t AllocRedirectEntry(void** alias) = 0; template uintptr_t AllocRedirectEntry(T*& offset) { return AllocRedirectEntry(reinterpret_cast(&offset)); } virtual void* ConvertOffsetToPointerRedirect(const void* offset) = 0; template T* ConvertOffsetToPointerRedirect(T* offset) { return static_cast(ConvertOffsetToPointerRedirect(static_cast(offset))); } virtual void* ConvertOffsetToAliasLookup(const void* offset) = 0; template T* ConvertOffsetToAliasLookup(T* offset) { return static_cast(ConvertOffsetToAliasLookup(static_cast(offset))); } static std::unique_ptr Create( unsigned pointerBitCount, unsigned blockBitCount, std::vector& blocks, block_t insertBlock, ILoadingStream& stream, MemoryManager& memory); };