mirror of
https://github.com/GearsProgress/Poke_Transporter_GB.git
synced 2026-07-15 07:44:11 -05:00
text_data_table was very similar in concept to FileContainerReader. But FileContainerReader is generally more flexible, as it allows you to split up your table into several chunks. This takes away the worry of these files getting too big to compress. However, we now have a maintenance duty for the text_tables file, which maps a table index to the list of chunks. We also need to be careful about every use of FileContainerReader::getPointerToFileInDecompressionBuffer(). Using it is fine when you're dealing with a single chunk or if you're sure the file doesn't span multiple chunks. But the moment you seek to a different chunk, any pointer obtained from getPointerToFileInDecompressionBuffer() becomes stale as the decompression buffer gets overwritten. Still, this function is necessary for high memory pressure situations, such as mystery_gift_builder, because we can't maintain multiple lineBuffers there.
128 lines
5.1 KiB
C++
128 lines
5.1 KiB
C++
#ifndef _FILECONTAINERREADER_H
|
|
#define _FILECONTAINERREADER_H
|
|
|
|
#include "typeDefs.h"
|
|
|
|
#define FILE_NAME_LENGTH 16
|
|
#define DEFAULT_CHUNK_SIZE 2048
|
|
|
|
/**
|
|
* @brief This class provides functionality to read files from the file container format
|
|
* created by the make-file-container tool.
|
|
*
|
|
* This format consists of multiple compressed chunks.
|
|
*
|
|
* It is done this way to keep the decompression buffer small (because we can't afford to consume too much IWRAM)
|
|
* but still allow for large file containers and bundling files together. (which you might want to do to improve compression ratios)
|
|
* The chunk size can be configured when creating the file container, and the
|
|
* FileContainerReader will read and decompress chunks on demand when seeking or reading data.
|
|
*/
|
|
class FileContainerReader
|
|
{
|
|
public:
|
|
FileContainerReader(const u8 **chunkList, u32 chunkCount, u32 chunkSize = DEFAULT_CHUNK_SIZE);
|
|
~FileContainerReader();
|
|
|
|
/**
|
|
* @brief This function initializes the FileContainerReader. It should be called before any other function is used.
|
|
* The reason for this initialization step is to give you control over the moment when the first chunk is decompressed.
|
|
* This can be useful if you want to perform some setup or checks before the decompression process begins. By calling init() explicitly, you can ensure that the FileContainerReader is ready to handle file reading operations at the appropriate time in your application.
|
|
*
|
|
* Note: because of this, we also only pass the decompression buffer here
|
|
* If the decompression buffer is not large enough to hold the chunks,
|
|
* the function will return false and the FileContainerReader will not be initialized. In this case, you should provide a larger decompression buffer and call init() again.
|
|
*
|
|
* If it DOES return true, please note that the FileContainerReader will keep using the decompressionBuffer_ until
|
|
* it gets destroyed.
|
|
*/
|
|
bool init(u8 *decompressionBuffer, u32 decompressionBufferSize);
|
|
|
|
/**
|
|
* @brief Returns the number of files stored in the file container.
|
|
*/
|
|
u32 getNumberOfFiles() const;
|
|
|
|
/**
|
|
* @brief IF the file container stores the file names,
|
|
* this function returns a pointer to the file name of the file at the given index.
|
|
* Otherwise, it returns nullptr.
|
|
*/
|
|
const char* getFileName(u32 fileIndex);
|
|
|
|
/**
|
|
* @brief This function returns the size of the file at the given index.
|
|
*/
|
|
u32 getFileSize(u32 fileIndex) const;
|
|
|
|
/**
|
|
* @brief This function seeks to the beginning of the file at the given index.
|
|
*/
|
|
void seekToFile(u32 fileIndex);
|
|
|
|
/**
|
|
* @brief Read data from the current position in the file container into the provided buffer.
|
|
*/
|
|
void read(u8 *buffer, u32 size);
|
|
|
|
/**
|
|
* @brief Gives you a direct pointer to the specified file in the decompression buffer. (unsafe!)
|
|
*
|
|
* This is useful to use data directly from the decompression buffer without having to allocate and
|
|
* copy another buffer. This is essential in high memory pressure scenarios, such as mystery_gift_builder.
|
|
* We can't afford to keep multiple linebuffers in memory in addition to the decompression buffer and all the other variables there.
|
|
*
|
|
* WARNING: this is only safe if you know the file is stored fully in the current chunk, because files may span multiple chunks.
|
|
* Or if the container only consists of a single chunk.
|
|
* Pointers acquired this way will become stale whenever a seek is done to a position in a different chunk,
|
|
* as that will cause the decompression buffer to be overwritten with the new chunk's data.
|
|
*/
|
|
u8 *getPointerToFileInDecompressionBuffer(u32 fileIndex);
|
|
|
|
/**
|
|
* @brief Combines seekToFile and read().
|
|
* Just a convenience function to make our code shorter :-)
|
|
*/
|
|
void seekAndRead(u32 fileIndex, u8 *buffer, u32 size);
|
|
|
|
/**
|
|
* @brief Even shorter variant of seekAndRead that reads the entire file at once.
|
|
* But it assumes you have provided a large enough buffer to hold the entire file.
|
|
*
|
|
* (useful for text table reading)
|
|
*/
|
|
void readFile(u32 fileIndex, u8 *buffer);
|
|
protected:
|
|
private:
|
|
/**
|
|
* @brief This function calculates the file offset for the specified file index
|
|
* The file offset is determined by reading the file index (which contains the file entry sizes)
|
|
* and summing up the sizes of all previous entries + header size + optional name table size
|
|
* (if names are stored).
|
|
*/
|
|
u32 getFileOffset(u32 fileIndex) const;
|
|
|
|
/**
|
|
* @brief This function seeks to the specified absolute offset in the file container data.
|
|
* Absolute offset refers to an offset across the file container chunks.
|
|
*/
|
|
void seek(u32 offset);
|
|
|
|
/**
|
|
* @brief This function just uncompresses the chunk at the specified index
|
|
* into decompressionBuffer_.
|
|
*/
|
|
void uncompressChunk(u32 chunkIndex);
|
|
|
|
char fileNameBuffer_[FILE_NAME_LENGTH + 1];
|
|
u8 *decompressionBuffer_;
|
|
const u8 **chunkList_;
|
|
u32 chunkCount_;
|
|
u32 chunkSize_;
|
|
u16 *fileIndex_;
|
|
u32 curChunkIndex_;
|
|
u32 curPos_;
|
|
u32 fileCount_;
|
|
bool hasNames_;
|
|
};
|
|
|
|
#endif |