26JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4309 4305 4365 6385 6326 6340)
28namespace zlibNamespace
30 #if JUCE_INCLUDE_ZLIB_CODE
31 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE (
"-Wconversion",
34 "-Wdeprecated-register",
38 "-Wimplicit-fallthrough",
39 "-Wzero-as-null-pointer-constant",
46 #include "zlib/zlib.h"
47 #include "zlib/adler32.c"
48 #include "zlib/compress.c"
51 #include "zlib/crc32.c"
52 #include "zlib/deflate.c"
53 #include "zlib/inffast.c"
61 #include "zlib/inflate.c"
62 #include "zlib/inftrees.c"
63 #include "zlib/trees.c"
64 #include "zlib/zutil.c"
73 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
75 #include JUCE_ZLIB_INCLUDE_PATH
81 #define z_uInt unsigned int
88JUCE_END_IGNORE_WARNINGS_MSVC
93class GZIPDecompressorInputStream::GZIPDecompressHelper
96 GZIPDecompressHelper (Format f)
98 using namespace zlibNamespace;
100 streamIsValid = (inflateInit2 (&stream, getBitsForFormat (f)) == Z_OK);
101 finished = error = ! streamIsValid;
104 ~GZIPDecompressHelper()
107 zlibNamespace::inflateEnd (&stream);
110 bool needsInput() const noexcept {
return dataSize <= 0; }
112 void setInput (uint8*
const data_,
const size_t size)
noexcept
118 int doNextBlock (uint8*
const dest,
const unsigned int destSize)
120 using namespace zlibNamespace;
122 if (streamIsValid && data !=
nullptr && ! finished)
124 stream.next_in = data;
125 stream.next_out = dest;
126 stream.avail_in = (z_uInt) dataSize;
127 stream.avail_out = (z_uInt) destSize;
129 switch (inflate (&stream, Z_PARTIAL_FLUSH))
135 data += dataSize - stream.avail_in;
136 dataSize = (z_uInt) stream.avail_in;
137 return (
int) (destSize - stream.avail_out);
140 needsDictionary =
true;
141 data += dataSize - stream.avail_in;
142 dataSize = (size_t) stream.avail_in;
157 static int getBitsForFormat (Format f)
noexcept
161 case zlibFormat:
return MAX_WBITS;
162 case deflateFormat:
return -MAX_WBITS;
163 case gzipFormat:
return MAX_WBITS | 16;
164 default: jassertfalse;
break;
170 bool finished =
true, needsDictionary =
false, error =
true, streamIsValid =
false;
172 enum { gzipDecompBufferSize = 32768 };
175 zlibNamespace::z_stream stream;
176 uint8* data =
nullptr;
179 JUCE_DECLARE_NON_COPYABLE (GZIPDecompressHelper)
184 Format f, int64 uncompressedLength)
185 : sourceStream (source, deleteSourceWhenDestroyed),
186 uncompressedStreamLength (uncompressedLength),
189 buffer ((size_t) GZIPDecompressHelper::gzipDecompBufferSize),
190 helper (new GZIPDecompressHelper (f))
195 : sourceStream (&source, false),
196 uncompressedStreamLength (-1),
199 buffer ((size_t) GZIPDecompressHelper::gzipDecompBufferSize),
200 helper (new GZIPDecompressHelper (zlibFormat))
210 return uncompressedStreamLength;
215 jassert (destBuffer !=
nullptr && howMany >= 0);
217 if (howMany > 0 && ! isEof)
220 auto d =
static_cast<uint8*
> (destBuffer);
222 while (! helper->error)
224 auto n = helper->doNextBlock (d, (
unsigned int) howMany);
229 if (helper->finished || helper->needsDictionary)
235 if (helper->needsInput())
237 activeBufferSize = sourceStream->read (buffer, (
int) GZIPDecompressHelper::gzipDecompBufferSize);
239 if (activeBufferSize > 0)
241 helper->setInput (buffer, (
size_t) activeBufferSize);
267 return helper->error || helper->finished || isEof;
277 if (newPos < currentPos)
281 activeBufferSize = 0;
283 helper.reset (
new GZIPDecompressHelper (format));
285 sourceStream->setPosition (originalSourcePos);
297struct GZIPDecompressorInputStreamTests final :
public UnitTest
299 GZIPDecompressorInputStreamTests()
300 :
UnitTest (
"GZIPDecompressorInputStreamTests", UnitTestCategories::streams)
303 void runTest()
override
305 const MemoryBlock data (
"abcdefghijklmnopqrstuvwxyz", 26);
307 MemoryOutputStream mo;
308 GZIPCompressorOutputStream gzipOutputStream (mo);
309 gzipOutputStream.write (data.getData(), data.getSize());
310 gzipOutputStream.flush();
312 MemoryInputStream mi (mo.getData(), mo.getDataSize(),
false);
313 GZIPDecompressorInputStream stream (&mi,
false, GZIPDecompressorInputStream::zlibFormat, (int64) data.getSize());
317 expectEquals (stream.getPosition(), (int64) 0);
318 expectEquals (stream.getTotalLength(), (int64) data.getSize());
319 expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
320 expect (! stream.isExhausted());
322 size_t numBytesRead = 0;
323 MemoryBlock readBuffer (data.getSize());
325 while (numBytesRead < data.getSize())
327 numBytesRead += (size_t) stream.read (&readBuffer[numBytesRead], 3);
329 expectEquals (stream.getPosition(), (int64) numBytesRead);
330 expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
331 expect (stream.isExhausted() == (numBytesRead == data.getSize()));
334 expectEquals (stream.getPosition(), (int64) data.getSize());
335 expectEquals (stream.getNumBytesRemaining(), (int64) 0);
336 expect (stream.isExhausted());
338 expect (readBuffer == data);
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());
349 const int numBytesToSkip = 5;
351 while (numBytesRead < data.getSize())
353 stream.skipNextBytes (numBytesToSkip);
354 numBytesRead += numBytesToSkip;
355 numBytesRead = std::min (numBytesRead, data.getSize());
357 expectEquals (stream.getPosition(), (int64) numBytesRead);
358 expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
359 expect (stream.isExhausted() == (numBytesRead == data.getSize()));
362 expectEquals (stream.getPosition(), (int64) data.getSize());
363 expectEquals (stream.getNumBytesRemaining(), (int64) 0);
364 expect (stream.isExhausted());
368static GZIPDecompressorInputStreamTests gzipDecompressorInputStreamTests;