OpenShot Library | libopenshot-audio 0.2.0
juce_GZIPDecompressorInputStream.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26#if JUCE_MSVC
27 #pragma warning (push)
28 #pragma warning (disable: 4309 4305 4365)
29#endif
30
31namespace zlibNamespace
32{
33 #if JUCE_INCLUDE_ZLIB_CODE
34 #if JUCE_CLANG
35 #pragma clang diagnostic push
36 #pragma clang diagnostic ignored "-Wconversion"
37 #pragma clang diagnostic ignored "-Wshadow"
38 #pragma clang diagnostic ignored "-Wdeprecated-register"
39 #if __has_warning("-Wzero-as-null-pointer-constant")
40 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
41 #endif
42 #if __has_warning("-Wcomma")
43 #pragma clang diagnostic ignored "-Wcomma"
44 #endif
45 #endif
46
47 #undef OS_CODE
48 #undef fdopen
49 #define ZLIB_INTERNAL
50 #define NO_DUMMY_DECL
51 #include "zlib/zlib.h"
52 #include "zlib/adler32.c"
53 #include "zlib/compress.c"
54 #undef DO1
55 #undef DO8
56 #include "zlib/crc32.c"
57 #include "zlib/deflate.c"
58 #include "zlib/inffast.c"
59 #undef PULLBYTE
60 #undef LOAD
61 #undef RESTORE
62 #undef INITBITS
63 #undef NEEDBITS
64 #undef DROPBITS
65 #undef BYTEBITS
66 #include "zlib/inflate.c"
67 #include "zlib/inftrees.c"
68 #include "zlib/trees.c"
69 #include "zlib/zutil.c"
70 #undef Byte
71 #undef fdopen
72 #undef local
73 #undef Freq
74 #undef Code
75 #undef Dad
76 #undef Len
77
78 #if JUCE_CLANG
79 #pragma clang diagnostic pop
80 #endif
81 #else
82 #include JUCE_ZLIB_INCLUDE_PATH
83
84 #ifndef z_uInt
85 #ifdef uInt
86 #define z_uInt uInt
87 #else
88 #define z_uInt unsigned int
89 #endif
90 #endif
91
92 #endif
93}
94
95#if JUCE_MSVC
96 #pragma warning (pop)
97#endif
98
99//==============================================================================
100// internal helper object that holds the zlib structures so they don't have to be
101// included publicly.
103{
104public:
105 GZIPDecompressHelper (Format f)
106 {
107 using namespace zlibNamespace;
108 zerostruct (stream);
109 streamIsValid = (inflateInit2 (&stream, getBitsForFormat (f)) == Z_OK);
110 finished = error = ! streamIsValid;
111 }
112
114 {
115 if (streamIsValid)
116 zlibNamespace::inflateEnd (&stream);
117 }
118
119 bool needsInput() const noexcept { return dataSize <= 0; }
120
121 void setInput (uint8* const data_, const size_t size) noexcept
122 {
123 data = data_;
124 dataSize = size;
125 }
126
127 int doNextBlock (uint8* const dest, const unsigned int destSize)
128 {
129 using namespace zlibNamespace;
130
131 if (streamIsValid && data != nullptr && ! finished)
132 {
133 stream.next_in = data;
134 stream.next_out = dest;
135 stream.avail_in = (uInt) dataSize;
136 stream.avail_out = (uInt) destSize;
137
138 switch (inflate (&stream, Z_PARTIAL_FLUSH))
139 {
140 case Z_STREAM_END:
141 finished = true;
142 // deliberate fall-through
143 case Z_OK:
144 data += dataSize - stream.avail_in;
145 dataSize = (uInt) stream.avail_in;
146 return (int) (destSize - stream.avail_out);
147
148 case Z_NEED_DICT:
149 needsDictionary = true;
150 data += dataSize - stream.avail_in;
151 dataSize = (size_t) stream.avail_in;
152 break;
153
154 case Z_DATA_ERROR:
155 case Z_MEM_ERROR:
156 error = true;
157
158 default:
159 break;
160 }
161 }
162
163 return 0;
164 }
165
166 static int getBitsForFormat (Format f) noexcept
167 {
168 switch (f)
169 {
170 case zlibFormat: return MAX_WBITS;
171 case deflateFormat: return -MAX_WBITS;
172 case gzipFormat: return MAX_WBITS | 16;
173 default: jassertfalse; break;
174 }
175
176 return MAX_WBITS;
177 }
178
179 bool finished = true, needsDictionary = false, error = true, streamIsValid = false;
180
181 enum { gzipDecompBufferSize = 32768 };
182
183private:
184 zlibNamespace::z_stream stream;
185 uint8* data = nullptr;
186 size_t dataSize = 0;
187
188 JUCE_DECLARE_NON_COPYABLE (GZIPDecompressHelper)
189};
190
191//==============================================================================
193 Format f, int64 uncompressedLength)
194 : sourceStream (source, deleteSourceWhenDestroyed),
195 uncompressedStreamLength (uncompressedLength),
196 format (f),
197 originalSourcePos (source->getPosition()),
198 buffer ((size_t) GZIPDecompressHelper::gzipDecompBufferSize),
199 helper (new GZIPDecompressHelper (f))
200{
201}
202
204 : sourceStream (&source, false),
205 uncompressedStreamLength (-1),
206 format (zlibFormat),
207 originalSourcePos (source.getPosition()),
208 buffer ((size_t) GZIPDecompressHelper::gzipDecompBufferSize),
209 helper (new GZIPDecompressHelper (zlibFormat))
210{
211}
212
216
218{
219 return uncompressedStreamLength;
220}
221
223{
224 jassert (destBuffer != nullptr && howMany >= 0);
225
226 if (howMany > 0 && ! isEof)
227 {
228 int numRead = 0;
229 auto d = static_cast<uint8*> (destBuffer);
230
231 while (! helper->error)
232 {
233 auto n = helper->doNextBlock (d, (unsigned int) howMany);
234 currentPos += n;
235
236 if (n == 0)
237 {
238 if (helper->finished || helper->needsDictionary)
239 {
240 isEof = true;
241 return numRead;
242 }
243
244 if (helper->needsInput())
245 {
246 activeBufferSize = sourceStream->read (buffer, (int) GZIPDecompressHelper::gzipDecompBufferSize);
247
248 if (activeBufferSize > 0)
249 {
250 helper->setInput (buffer, (size_t) activeBufferSize);
251 }
252 else
253 {
254 isEof = true;
255 return numRead;
256 }
257 }
258 }
259 else
260 {
261 numRead += n;
262 howMany -= n;
263 d += n;
264
265 if (howMany <= 0)
266 return numRead;
267 }
268 }
269 }
270
271 return 0;
272}
273
275{
276 return helper->error || helper->finished || isEof;
277}
278
280{
281 return currentPos;
282}
283
285{
286 if (newPos < currentPos)
287 {
288 // to go backwards, reset the stream and start again..
289 isEof = false;
290 activeBufferSize = 0;
291 currentPos = 0;
292 helper.reset (new GZIPDecompressHelper (format));
293
294 sourceStream->setPosition (originalSourcePos);
295 }
296
297 skipNextBytes (newPos - currentPos);
298 return true;
299}
300
301//==============================================================================
302#if JUCE_UNIT_TESTS
303
305{
307 : UnitTest ("GZIPDecompressorInputStreamTests", "Streams")
308 {}
309
310 void runTest() override
311 {
312 const MemoryBlock data ("abcdefghijklmnopqrstuvwxyz", 26);
313
314 MemoryOutputStream mo;
315 GZIPCompressorOutputStream gzipOutputStream (mo);
316 gzipOutputStream.write (data.getData(), data.getSize());
317 gzipOutputStream.flush();
318
319 MemoryInputStream mi (mo.getData(), mo.getDataSize(), false);
320 GZIPDecompressorInputStream stream (&mi, false, GZIPDecompressorInputStream::zlibFormat, (int64) data.getSize());
321
322 beginTest ("Read");
323
324 expectEquals (stream.getPosition(), (int64) 0);
325 expectEquals (stream.getTotalLength(), (int64) data.getSize());
326 expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
327 expect (! stream.isExhausted());
328
329 size_t numBytesRead = 0;
330 MemoryBlock readBuffer (data.getSize());
331
332 while (numBytesRead < data.getSize())
333 {
334 numBytesRead += (size_t) stream.read (&readBuffer[numBytesRead], 3);
335
336 expectEquals (stream.getPosition(), (int64) numBytesRead);
337 expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
338 expect (stream.isExhausted() == (numBytesRead == data.getSize()));
339 }
340
341 expectEquals (stream.getPosition(), (int64) data.getSize());
342 expectEquals (stream.getNumBytesRemaining(), (int64) 0);
343 expect (stream.isExhausted());
344
345 expect (readBuffer == data);
346
347 beginTest ("Skip");
348
349 stream.setPosition (0);
350 expectEquals (stream.getPosition(), (int64) 0);
351 expectEquals (stream.getTotalLength(), (int64) data.getSize());
352 expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
353 expect (! stream.isExhausted());
354
355 numBytesRead = 0;
356 const int numBytesToSkip = 5;
357
358 while (numBytesRead < data.getSize())
359 {
360 stream.skipNextBytes (numBytesToSkip);
362 numBytesRead = std::min (numBytesRead, data.getSize());
363
364 expectEquals (stream.getPosition(), (int64) numBytesRead);
365 expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
366 expect (stream.isExhausted() == (numBytesRead == data.getSize()));
367 }
368
369 expectEquals (stream.getPosition(), (int64) data.getSize());
370 expectEquals (stream.getNumBytesRemaining(), (int64) 0);
371 expect (stream.isExhausted());
372 }
373};
374
375static GZIPDecompressorInputStreamTests gzipDecompressorInputStreamTests;
376
377#endif
378
379} // namespace juce
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:60
Array()=default
Creates an empty array.
ElementType * data() const noexcept
Returns a pointer to the first element in the array.
Definition juce_Array.h:325
bool setPosition(int64 pos) override
Tries to move the current read position of the stream.
int64 getPosition() override
Returns the offset of the next byte that will be read from the stream.
int64 getTotalLength() override
Returns the total number of bytes available for reading in this stream.
bool isExhausted() override
Returns true if the stream has no more data to read.
int read(void *destBuffer, int maxBytesToRead) override
Reads some data from the stream into a memory buffer.
GZIPDecompressorInputStream(InputStream *sourceStream, bool deleteSourceWhenDestroyed, Format sourceFormat=zlibFormat, int64 uncompressedStreamLength=-1)
Creates a decompressor stream.
The base class for streams that read data.
virtual void skipNextBytes(int64 numBytesToSkip)
Reads and discards a number of bytes from the stream.
This is a base class for classes that perform a unit test.