/src/ogre/OgreMain/include/OgreDeflate.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | ----------------------------------------------------------------------------- |
3 | | This source file is part of OGRE |
4 | | (Object-oriented Graphics Rendering Engine) |
5 | | For the latest info, see http://www.ogre3d.org/ |
6 | | |
7 | | Copyright (c) 2000-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | #ifndef __OGRE_DEFLATE_H__ |
29 | | #define __OGRE_DEFLATE_H__ |
30 | | |
31 | | #if OGRE_NO_ZIP_ARCHIVE == 0 |
32 | | |
33 | | #include "OgrePrerequisites.h" |
34 | | #include "OgreDataStream.h" |
35 | | #include "OgreHeaderPrefix.h" |
36 | | |
37 | | /// forward decls |
38 | | struct mz_stream_s; |
39 | | typedef struct mz_stream_s z_stream; |
40 | | |
41 | | namespace Ogre |
42 | | { |
43 | | /** Template version of cache based on static array. |
44 | | 'cacheSize' defines size of cache in bytes. */ |
45 | | template <size_t cacheSize> |
46 | | class StaticCache |
47 | | { |
48 | | private: |
49 | | /// Static buffer |
50 | | char mBuffer[cacheSize]; |
51 | | |
52 | | /// Number of bytes valid in cache (written from the beginning of static buffer) |
53 | | size_t mValidBytes; |
54 | | /// Current read position |
55 | | size_t mPos; |
56 | | public: |
57 | | /// Constructor |
58 | | StaticCache() |
59 | 0 | { |
60 | 0 | mValidBytes = 0; |
61 | 0 | mPos = 0; |
62 | 0 | memset(mBuffer, 0, cacheSize); |
63 | 0 | } |
64 | | |
65 | | /** Cache data pointed by 'buf'. If 'count' is greater than cache size, we cache only last bytes. |
66 | | Returns number of bytes written to cache. */ |
67 | | size_t cacheData(const void* buf, size_t count) |
68 | 0 | { |
69 | 0 | assert(avail() == 0 && "It is assumed that you cache data only after you have read everything."); |
70 | |
|
71 | 0 | if (count < cacheSize) |
72 | 0 | { |
73 | | // number of bytes written is less than total size of cache |
74 | 0 | if (count + mValidBytes <= cacheSize) |
75 | 0 | { |
76 | | // just append |
77 | 0 | memcpy(mBuffer + mValidBytes, buf, count); |
78 | 0 | mValidBytes += count; |
79 | 0 | } |
80 | 0 | else |
81 | 0 | { |
82 | 0 | size_t begOff = count - (cacheSize - mValidBytes); |
83 | | // override old cache content in the beginning |
84 | 0 | memmove(mBuffer, mBuffer + begOff, mValidBytes - begOff); |
85 | | // append new data |
86 | 0 | memcpy(mBuffer + cacheSize - count, buf, count); |
87 | 0 | mValidBytes = cacheSize; |
88 | 0 | } |
89 | 0 | mPos = mValidBytes; |
90 | 0 | return count; |
91 | 0 | } |
92 | 0 | else |
93 | 0 | { |
94 | | // discard all |
95 | 0 | memcpy(mBuffer, (const char*)buf + count - cacheSize, cacheSize); |
96 | 0 | mValidBytes = mPos = cacheSize; |
97 | 0 | return cacheSize; |
98 | 0 | } |
99 | 0 | } |
100 | | /** Read data from cache to 'buf' (maximum 'count' bytes). Returns number of bytes read from cache. */ |
101 | | size_t read(void* buf, size_t count) |
102 | 0 | { |
103 | 0 | size_t rb = avail(); |
104 | 0 | rb = (rb < count) ? rb : count; |
105 | 0 | memcpy(buf, mBuffer + mPos, rb); |
106 | 0 | mPos += rb; |
107 | 0 | return rb; |
108 | 0 | } |
109 | | |
110 | | /** Step back in cached stream by 'count' bytes. Returns 'true' if cache contains resulting position. */ |
111 | | bool rewind(size_t count) |
112 | 0 | { |
113 | 0 | if (mPos < count) |
114 | 0 | { |
115 | 0 | clear(); |
116 | 0 | return false; |
117 | 0 | } |
118 | 0 | else |
119 | 0 | { |
120 | 0 | mPos -= count; |
121 | 0 | return true; |
122 | 0 | } |
123 | 0 | } |
124 | | /** Step forward in cached stream by 'count' bytes. Returns 'true' if cache contains resulting position. */ |
125 | | bool ff(size_t count) |
126 | 0 | { |
127 | 0 | if (avail() < count) |
128 | 0 | { |
129 | 0 | clear(); |
130 | 0 | return false; |
131 | 0 | } |
132 | 0 | else |
133 | 0 | { |
134 | 0 | mPos += count; |
135 | 0 | return true; |
136 | 0 | } |
137 | 0 | } |
138 | | |
139 | | /** Returns number of bytes available for reading in cache after rewinding. */ |
140 | | size_t avail() const |
141 | 0 | { |
142 | 0 | return mValidBytes - mPos; |
143 | 0 | } |
144 | | |
145 | | /** Clear the cache */ |
146 | | void clear() |
147 | 0 | { |
148 | 0 | mValidBytes = 0; |
149 | 0 | mPos = 0; |
150 | 0 | } |
151 | | }; |
152 | | |
153 | | /** Stream which compresses / uncompresses data using the 'deflate' compression |
154 | | algorithm. |
155 | | |
156 | | This stream is designed to wrap another stream for the actual source / destination |
157 | | of the compressed data, it has no concrete source / data itself. The idea is |
158 | | that you pass uncompressed data through this stream, and the underlying |
159 | | stream reads/writes compressed data to the final source. |
160 | | @note |
161 | | This is an alternative to using a compressed archive since it is able to |
162 | | compress & decompress regardless of the actual source of the stream. |
163 | | You should avoid using this with already compressed archives. |
164 | | Also note that this cannot be used as a read / write stream, only a read-only |
165 | | or write-only stream. |
166 | | */ |
167 | | class _OgreExport DeflateStream : public DataStream |
168 | | { |
169 | | public: |
170 | | /** Requested stream type. All are essentially the same deflate stream with varying wrapping. |
171 | | ZLib is used by default. |
172 | | */ |
173 | | enum StreamType |
174 | | { |
175 | | Invalid = -1, /// Unexpected stream type or uncompressed data |
176 | | Deflate = 0, /// no header, no checksum, rfc1951 |
177 | | ZLib = 1, /// 2 byte header, 4 byte footer with adler32 checksum, rfc1950 |
178 | | GZip = 2, /// 10 byte header, 8 byte footer with crc32 checksum and unpacked size, rfc1952 |
179 | | }; |
180 | | private: |
181 | | DataStreamPtr mCompressedStream; |
182 | | DataStreamPtr mTmpWriteStream; |
183 | | String mTempFileName; |
184 | | z_stream* mZStream; |
185 | | int mStatus; |
186 | | size_t mCurrentPos; |
187 | | size_t mAvailIn; |
188 | | |
189 | | /// Cache for read data in case skipping around |
190 | | StaticCache<16 * OGRE_STREAM_TEMP_SIZE> mReadCache; |
191 | | |
192 | | /// Intermediate buffer for read / write |
193 | | unsigned char *mTmp; |
194 | | |
195 | | /// Whether the underlying stream is valid compressed data |
196 | | StreamType mStreamType; |
197 | | |
198 | | void init(); |
199 | | void destroy(); |
200 | | void compressFinal(); |
201 | | |
202 | | size_t getAvailInForSinglePass(); |
203 | | public: |
204 | | /** Constructor for creating unnamed stream wrapping another stream. |
205 | | @param compressedStream The stream that this stream will use when reading / |
206 | | writing compressed data. The access mode from this stream will be matched. |
207 | | @param tmpFileName Path/Filename to be used for temporary storage of incoming data |
208 | | @param avail_in Available data length to be uncompressed. With it we can uncompress |
209 | | DataStream partly. |
210 | | */ |
211 | | DeflateStream(const DataStreamPtr& compressedStream, const String& tmpFileName = "", |
212 | | size_t avail_in = 0); |
213 | | /** Constructor for creating named stream wrapping another stream. |
214 | | @param name The name to give this stream |
215 | | @param compressedStream The stream that this stream will use when reading / |
216 | | writing compressed data. The access mode from this stream will be matched. |
217 | | @param tmpFileName Path/Filename to be used for temporary storage of incoming data |
218 | | @param avail_in Available data length to be uncompressed. With it we can uncompress |
219 | | DataStream partly. |
220 | | */ |
221 | | DeflateStream(const String& name, const DataStreamPtr& compressedStream, const String& tmpFileName="", |
222 | | size_t avail_in = 0); |
223 | | /** Constructor for creating named stream wrapping another stream. |
224 | | @param name The name to give this stream |
225 | | @param compressedStream The stream that this stream will use when reading / |
226 | | writing compressed data. The access mode from this stream will be matched. |
227 | | @param streamType The type of compressed stream |
228 | | @param tmpFileName Path/Filename to be used for temporary storage of incoming data |
229 | | @param avail_in Available data length to be uncompressed. With it we can uncompress |
230 | | DataStream partly. |
231 | | */ |
232 | | DeflateStream(const String& name, const DataStreamPtr& compressedStream, StreamType streamType, const String& tmpFileName="", |
233 | | size_t avail_in = 0); |
234 | | |
235 | | ~DeflateStream(); |
236 | | |
237 | | /** Returns whether the compressed stream is valid deflated data. |
238 | | |
239 | | If you pass this class a READ stream which is not compressed with the |
240 | | deflate algorithm, this method returns false and all read commands |
241 | | will actually be executed as passthroughs as a fallback. |
242 | | */ |
243 | 0 | bool isCompressedStreamValid() const { return mStreamType != Invalid; } |
244 | | |
245 | | /** @copydoc DataStream::read |
246 | | */ |
247 | | size_t read(void* buf, size_t count) override; |
248 | | |
249 | | /** @copydoc DataStream::write |
250 | | */ |
251 | | size_t write(const void* buf, size_t count) override; |
252 | | |
253 | | /** @copydoc DataStream::skip |
254 | | */ |
255 | | void skip(long count) override; |
256 | | |
257 | | /** @copydoc DataStream::seek |
258 | | */ |
259 | | void seek( size_t pos ) override; |
260 | | |
261 | | /** @copydoc DataStream::tell |
262 | | */ |
263 | | size_t tell(void) const override; |
264 | | |
265 | | /** @copydoc DataStream::eof |
266 | | */ |
267 | | bool eof(void) const override; |
268 | | |
269 | | /** @copydoc DataStream::close |
270 | | */ |
271 | | void close(void) override; |
272 | | |
273 | | }; |
274 | | } |
275 | | |
276 | | #include "OgreHeaderSuffix.h" |
277 | | |
278 | | #endif |
279 | | |
280 | | #endif |