JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_GZIPDecompressorInputStream.cpp
Go to the documentation of this file.
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.
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
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;
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;
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
180};
181
182//==============================================================================
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
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
298{
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);
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
369
370#endif
371
372} // namespace juce
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.
T data(T... args)
#define jassert(expression)
Platform-independent assertion macro.
#define JUCE_DECLARE_NON_COPYABLE(className)
This is a shorthand macro for deleting a class's copy constructor and copy assignment operator.
#define jassertfalse
This will always cause an assertion failure.
#define JUCE_FALLTHROUGH
Used to silence Wimplicit-fallthrough on Clang and GCC where available as there are a few places in t...
T min(T... args)
JUCE Namespace.
void zerostruct(Type &structure) noexcept
Overwrites a structure or object with zeros.
Definition juce_Memory.h:32
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
long long int64
A platform-independent 64-bit integer type.
typedef size_t