1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
/*
* CCompressedStream.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "CInputStream.h"
struct z_stream_s;
VCMI_LIB_NAMESPACE_BEGIN
class DecompressionException : public std::runtime_error
{
public:
using runtime_error::runtime_error;
};
/// Abstract class that provides buffer for one-directional input streams (e.g. compressed data)
/// Used for zip archives support and in .lod deflate compression
class CBufferedStream : public CInputStream
{
public:
CBufferedStream();
/**
* Reads n bytes from the stream into the data buffer.
*
* @param data A pointer to the destination data array.
* @param size The number of bytes to read.
* @return the number of bytes read actually.
*
* @throws std::runtime_error if the file decompression was not successful
*/
si64 read(ui8 * data, si64 size) override;
/**
* Seeks the internal read pointer to the specified position.
* This will cause decompressing data till this position is found
*
* @param position The read position from the beginning.
* @return the position actually moved to, -1 on error.
*/
si64 seek(si64 position) override;
/**
* Gets the current read position in the stream.
*
* @return the read position.
*/
si64 tell() override;
/**
* Skips delta numbers of bytes.
*
* @param delta The count of bytes to skip.
* @return the count of bytes skipped actually.
*/
si64 skip(si64 delta) override;
/**
* Gets the length in bytes of the stream.
* Causes complete data decompression
*
* @return the length in bytes of the stream.
*/
si64 getSize() override;
protected:
/**
* @brief virtual method to get more data into the buffer
* @return amount of bytes actually read, non-positive values are considered to be end-of-file mark
*/
virtual si64 readMore(ui8 * data, si64 size) = 0;
/// resets all internal state
void reset();
private:
/// ensures that buffer contains at lest size of bytes. Calls readMore() to fill remaining part
void ensureSize(si64 size);
/** buffer with already decompressed data */
std::vector<ui8> buffer;
/** Current read position */
si64 position;
bool endOfFileReached;
};
/**
* A class which provides method definitions for reading a gzip-compressed file
* This class implements lazy loading - data will be decompressed (and cached) only by request
*/
class DLL_LINKAGE CCompressedStream : public CBufferedStream
{
public:
/**
* C-tor.
*
* @param stream - stream with compressed data
* @param gzip - this is gzipp'ed file e.g. campaign or maps, false for files in .lod
* @param decompressedSize - optional parameter to hint size of decompressed data
*/
CCompressedStream(std::unique_ptr<CInputStream> stream, bool gzip, size_t decompressedSize=0);
~CCompressedStream();
/**
* Prepare stream for decompression of next block (e.g. next part of h3c)
* Applicable only for streams that contain multiple concatenated compressed data
*
* @return false if next block was not found, true othervice
*/
bool getNextBlock();
private:
/**
* Decompresses data to ensure that buffer has newSize bytes or end of stream was reached
*/
si64 readMore(ui8 * data, si64 size) override;
/** The file stream with compressed data. */
std::unique_ptr<CInputStream> gzipStream;
/** buffer with not yet decompressed data*/
std::vector<ui8> compressedBuffer;
/** struct with current zlib inflate state */
z_stream_s * inflateState;
enum EState
{
ERROR_OCCURRED,
INITIALIZED,
IN_PROGRESS,
STREAM_END,
FINISHED
};
};
VCMI_LIB_NAMESPACE_END
|