2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-05-16 23:11:42 +00:00
Files
OpenAssetTools/src/ObjLoading/ObjContainer/IPak/IPakEntryReadStream.h
T
2026-05-12 23:44:53 +02:00

129 lines
4.9 KiB
C++

#pragma once
#include "IPakStreamManager.h"
#include "ObjContainer/IPak/IPakTypes.h"
#include "Utils/Endianness.h"
#include "Utils/ObjStream.h"
#include "XMemDecompress.h"
#include <concepts>
#include <istream>
class IPakEntryReadStream final : public objbuf
{
public:
IPakEntryReadStream(
std::istream& stream, bool isLittleEndian, IPakStreamManagerActions* streamManagerActions, uint8_t* chunkBuffer, int64_t startOffset, size_t entrySize);
~IPakEntryReadStream() override;
[[nodiscard]] bool is_open() const override;
bool close() override;
protected:
std::streamsize showmanyc() override;
int_type underflow() override;
int_type uflow() override;
std::streamsize xsgetn(char* ptr, std::streamsize count) override;
pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode mode) override;
pos_type seekpos(pos_type pos, std::ios_base::openmode mode) override;
private:
template<typename T> static T AlignForward(const T num, const T alignTo)
{
return (num + alignTo - 1) / alignTo * alignTo;
}
template<typename T> static T AlignBackwards(const T num, const T alignTo)
{
return num / alignTo * alignTo;
}
template<std::integral T> void SwapBytesIfNecessary(T& value)
{
if (m_little_endian)
value = endianness::FromLittleEndian(value);
else
value = endianness::FromBigEndian(value);
}
/**
* \brief Reads the specified chunks from disk.
* \param buffer The location to write the loaded data to. Must be able to hold the specified amount of data.
* \param startPos The file offset at which the data to be loaded starts at.
* \param chunkCount The amount of chunks to be loaded.
* \return The amount of chunks that could be successfully loaded.
*/
size_t ReadChunks(uint8_t* buffer, int64_t startPos, size_t chunkCount) const;
/**
* \brief Make sure the loaded chunk buffer window corresponds to the specified parameters and loads additional data if necessary.
* \param startPos The offset in the file that should be the start of the chunk buffer.
* \param chunkCount The amount of chunks that the buffer should hold. Can not exceed IPAK_CHUNK_COUNT_PER_READ.
* \return \c true if the chunk buffer window could successfully be adjusted, \c false otherwise.
*/
bool SetChunkBufferWindow(int64_t startPos, size_t chunkCount);
/**
* \brief Makes sure the specified block can be safely loaded.
* \param blockHeader The block header to check.
* \return \c true if the block can be safely loaded, \c false otherwise.
*/
bool ValidateBlockHeader(const IPakDataBlockHeader* blockHeader) const;
/**
* \brief Makes sure that the specified block fits inside the loaded chunk buffer window and adjusts the chunk buffer window if necessary.
* \param blockHeader The header of the block that needs to fit inside the loaded chunk buffer window.
* \param blockOffsetInChunk The offset of the block inside the current chunk.
* \return \c true if the chunk buffer window was either already valid or was successfully adjusted to have all block data loaded. \c false otherwise.
*/
bool AdjustChunkBufferWindowForBlockHeader(const IPakDataBlockHeader* blockHeader, size_t blockOffsetInChunk);
/**
* \brief Ensures the next valid block is loaded.
* \return \c true if a new block was loaded or \c false if no further valid block could be loaded.
*/
bool NextBlock();
/**
* \brief Processes a command with the specified parameters at the current position.
* \param commandSize The size of the command data
* \param compressed The compression value of the command. Can be \c 0 for uncompressed or \c 1 for lzo compression. Any other value skips the specified
* size of data. \return \c true if the specified command could be correctly processed or \c otherwise.
*/
bool ProcessCommand(size_t commandSize, int compressed);
/**
* \brief Ensures that the next valid command is loaded.
* \return \c true if a new command was loaded or \c false if no further valid command could be loaded.
*/
bool AdvanceStream();
static constexpr size_t IPAK_DECOMPRESS_BUFFER_SIZE = 0x8000;
uint8_t* m_chunk_buffer;
bool m_little_endian;
XMemDecompressContext m_xmemdecompress_context;
std::istream& m_stream;
IPakStreamManagerActions* m_stream_manager_actions;
int64_t m_file_offset;
int64_t m_file_head;
size_t m_entry_size;
uint8_t m_decompress_buffer[IPAK_DECOMPRESS_BUFFER_SIZE];
IPakDataBlockHeader* m_current_block;
unsigned m_next_command;
uint8_t* m_current_command_buffer;
size_t m_current_command_length;
size_t m_current_command_offset;
int64_t m_pos;
int64_t m_base_pos;
int64_t m_end_pos;
int64_t m_buffer_start_pos;
int64_t m_buffer_end_pos;
};