OpenShot Audio Library | OpenShotAudio 0.3.2
Loading...
Searching...
No Matches
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 #if JUCE_GCC
48 #pragma GCC diagnostic push
49 #pragma GCC diagnostic ignored "-Wconversion"
50 #pragma GCC diagnostic ignored "-Wsign-conversion"
51 #pragma GCC diagnostic ignored "-Wshadow"
52 #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
53 #endif
54
55 #undef OS_CODE
56 #undef fdopen
57 #define ZLIB_INTERNAL
58 #define NO_DUMMY_DECL
59 #include "zlib/zlib.h"
60 #include "zlib/adler32.c"
61 #include "zlib/compress.c"
62 #undef DO1
63 #undef DO8
64 #include "zlib/crc32.c"
65 #include "zlib/deflate.c"
66 #include "zlib/inffast.c"
67 #undef PULLBYTE
68 #undef LOAD
69 #undef RESTORE
70 #undef INITBITS
71 #undef NEEDBITS
72 #undef DROPBITS
73 #undef BYTEBITS
74 #include "zlib/inflate.c"
75 #include "zlib/inftrees.c"
76 #include "zlib/trees.c"
77 #include "zlib/zutil.c"
78 #undef Byte
79 #undef fdopen
80 #undef local
81 #undef Freq
82 #undef Code
83 #undef Dad
84 #undef Len
85
86 #if JUCE_CLANG
87 #pragma clang diagnostic pop
88 #endif
89
90 #if JUCE_GCC
91 #pragma GCC diagnostic pop
92 #endif
93 #else
94 #include JUCE_ZLIB_INCLUDE_PATH
95
96 #ifndef z_uInt
97 #ifdef uInt
98 #define z_uInt uInt
99 #else
100 #define z_uInt unsigned int
101 #endif
102 #endif
103
104 #endif
105}
106
107#if JUCE_MSVC
108 #pragma warning (pop)
109#endif
110
111//==============================================================================
112// internal helper object that holds the zlib structures so they don't have to be
113// included publicly.
114class GZIPDecompressorInputStream::GZIPDecompressHelper
115{
116public:
117 GZIPDecompressHelper (Format f)
118 {
119 using namespace zlibNamespace;
120 zerostruct (stream);
121 streamIsValid = (inflateInit2 (&stream, getBitsForFormat (f)) == Z_OK);
122 finished = error = ! streamIsValid;
123 }
124
125 ~GZIPDecompressHelper()
126 {
127 if (streamIsValid)
128 zlibNamespace::inflateEnd (&stream);
129 }
130
131 bool needsInput() const noexcept { return dataSize <= 0; }
132
133 void setInput (uint8* const data_, const size_t size) noexcept
134 {
135 data = data_;
136 dataSize = size;
137 }
138
139 int doNextBlock (uint8* const dest, const unsigned int destSize)
140 {
141 using namespace zlibNamespace;
142
143 if (streamIsValid && data != nullptr && ! finished)
144 {
145 stream.next_in = data;
146 stream.next_out = dest;
147 stream.avail_in = (z_uInt) dataSize;
148 stream.avail_out = (z_uInt) destSize;
149
150 switch (inflate (&stream, Z_PARTIAL_FLUSH))
151 {
152 case Z_STREAM_END:
153 finished = true;
154 // deliberate fall-through
155 case Z_OK:
156 data += dataSize - stream.avail_in;
157 dataSize = (z_uInt) stream.avail_in;
158 return (int) (destSize - stream.avail_out);
159
160 case Z_NEED_DICT:
161 needsDictionary = true;
162 data += dataSize - stream.avail_in;
163 dataSize = (size_t) stream.avail_in;
164 break;
165
166 case Z_DATA_ERROR:
167 case Z_MEM_ERROR:
168 error = true;
169
170 default:
171 break;
172 }
173 }
174
175 return 0;
176 }
177
178 static int getBitsForFormat (Format f) noexcept
179 {
180 switch (f)
181 {
182 case zlibFormat: return MAX_WBITS;
183 case deflateFormat: return -MAX_WBITS;
184 case gzipFormat: return MAX_WBITS | 16;
185 default: jassertfalse; break;
186 }
187
188 return MAX_WBITS;
189 }
190
191 bool finished = true, needsDictionary = false, error = true, streamIsValid = false;
192
193 enum { gzipDecompBufferSize = 32768 };
194
195private:
196 zlibNamespace::z_stream stream;
197 uint8* data = nullptr;
198 size_t dataSize = 0;
199
200 JUCE_DECLARE_NON_COPYABLE (GZIPDecompressHelper)
201};
202
203//==============================================================================
205 Format f, int64 uncompressedLength)
206 : sourceStream (source, deleteSourceWhenDestroyed),
207 uncompressedStreamLength (uncompressedLength),
208 format (f),
209 originalSourcePos (source->getPosition()),
210 buffer ((size_t) GZIPDecompressHelper::gzipDecompBufferSize),
211 helper (new GZIPDecompressHelper (f))
212{
213}
214
216 : sourceStream (&source, false),
217 uncompressedStreamLength (-1),
218 format (zlibFormat),
219 originalSourcePos (source.getPosition()),
220 buffer ((size_t) GZIPDecompressHelper::gzipDecompBufferSize),
221 helper (new GZIPDecompressHelper (zlibFormat))
222{
223}
224
228
230{
231 return uncompressedStreamLength;
232}
233
235{
236 jassert (destBuffer != nullptr && howMany >= 0);
237
238 if (howMany > 0 && ! isEof)
239 {
240 int numRead = 0;
241 auto d = static_cast<uint8*> (destBuffer);
242
243 while (! helper->error)
244 {
245 auto n = helper->doNextBlock (d, (unsigned int) howMany);
246 currentPos += n;
247
248 if (n == 0)
249 {
250 if (helper->finished || helper->needsDictionary)
251 {
252 isEof = true;
253 return numRead;
254 }
255
256 if (helper->needsInput())
257 {
258 activeBufferSize = sourceStream->read (buffer, (int) GZIPDecompressHelper::gzipDecompBufferSize);
259
260 if (activeBufferSize > 0)
261 {
262 helper->setInput (buffer, (size_t) activeBufferSize);
263 }
264 else
265 {
266 isEof = true;
267 return numRead;
268 }
269 }
270 }
271 else
272 {
273 numRead += n;
274 howMany -= n;
275 d += n;
276
277 if (howMany <= 0)
278 return numRead;
279 }
280 }
281 }
282
283 return 0;
284}
285
287{
288 return helper->error || helper->finished || isEof;
289}
290
292{
293 return currentPos;
294}
295
297{
298 if (newPos < currentPos)
299 {
300 // to go backwards, reset the stream and start again..
301 isEof = false;
302 activeBufferSize = 0;
303 currentPos = 0;
304 helper.reset (new GZIPDecompressHelper (format));
305
306 sourceStream->setPosition (originalSourcePos);
307 }
308
309 skipNextBytes (newPos - currentPos);
310 return true;
311}
312
313
314//==============================================================================
315//==============================================================================
316#if JUCE_UNIT_TESTS
317
319{
321 : UnitTest ("GZIPDecompressorInputStreamTests", UnitTestCategories::streams)
322 {}
323
324 void runTest() override
325 {
326 const MemoryBlock data ("abcdefghijklmnopqrstuvwxyz", 26);
327
328 MemoryOutputStream mo;
329 GZIPCompressorOutputStream gzipOutputStream (mo);
330 gzipOutputStream.write (data.getData(), data.getSize());
331 gzipOutputStream.flush();
332
333 MemoryInputStream mi (mo.getData(), mo.getDataSize(), false);
334 GZIPDecompressorInputStream stream (&mi, false, GZIPDecompressorInputStream::zlibFormat, (int64) data.getSize());
335
336 beginTest ("Read");
337
338 expectEquals (stream.getPosition(), (int64) 0);
339 expectEquals (stream.getTotalLength(), (int64) data.getSize());
340 expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
341 expect (! stream.isExhausted());
342
343 size_t numBytesRead = 0;
344 MemoryBlock readBuffer (data.getSize());
345
346 while (numBytesRead < data.getSize())
347 {
348 numBytesRead += (size_t) stream.read (&readBuffer[numBytesRead], 3);
349
350 expectEquals (stream.getPosition(), (int64) numBytesRead);
351 expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
352 expect (stream.isExhausted() == (numBytesRead == data.getSize()));
353 }
354
355 expectEquals (stream.getPosition(), (int64) data.getSize());
356 expectEquals (stream.getNumBytesRemaining(), (int64) 0);
357 expect (stream.isExhausted());
358
359 expect (readBuffer == data);
360
361 beginTest ("Skip");
362
363 stream.setPosition (0);
364 expectEquals (stream.getPosition(), (int64) 0);
365 expectEquals (stream.getTotalLength(), (int64) data.getSize());
366 expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
367 expect (! stream.isExhausted());
368
369 numBytesRead = 0;
370 const int numBytesToSkip = 5;
371
372 while (numBytesRead < data.getSize())
373 {
374 stream.skipNextBytes (numBytesToSkip);
376 numBytesRead = std::min (numBytesRead, data.getSize());
377
378 expectEquals (stream.getPosition(), (int64) numBytesRead);
379 expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
380 expect (stream.isExhausted() == (numBytesRead == data.getSize()));
381 }
382
383 expectEquals (stream.getPosition(), (int64) data.getSize());
384 expectEquals (stream.getNumBytesRemaining(), (int64) 0);
385 expect (stream.isExhausted());
386 }
387};
388
389static GZIPDecompressorInputStreamTests gzipDecompressorInputStreamTests;
390
391#endif
392
393} // namespace juce
Array()=default
ElementType * data() noexcept
Definition juce_Array.h:360
int read(void *destBuffer, int maxBytesToRead) override
GZIPDecompressorInputStream(InputStream *sourceStream, bool deleteSourceWhenDestroyed, Format sourceFormat=zlibFormat, int64 uncompressedStreamLength=-1)
virtual void skipNextBytes(int64 numBytesToSkip)