File: CCompressedStream.h

package info (click to toggle)
vcmi 1.6.5%2Bdfsg-2
  • links: PTS, VCS
  • area: contrib
  • in suites: forky, sid, trixie
  • size: 32,060 kB
  • sloc: cpp: 238,971; python: 265; sh: 224; xml: 157; ansic: 78; objc: 61; makefile: 49
file content (147 lines) | stat: -rw-r--r-- 3,737 bytes parent folder | download
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