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