OpenShot Audio Library | OpenShotAudio  0.6.0
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 
23 namespace juce
24 {
25 
26 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4309 4305 4365 6385 6326 6340)
27 
28 namespace 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 
88 JUCE_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.
93 class GZIPDecompressorInputStream::GZIPDecompressHelper
94 {
95 public:
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 
174 private:
175  zlibNamespace::z_stream stream;
176  uint8* data = nullptr;
177  size_t dataSize = 0;
178 
179  JUCE_DECLARE_NON_COPYABLE (GZIPDecompressHelper)
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 
205 {
206 }
207 
209 {
210  return uncompressedStreamLength;
211 }
212 
213 int 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 
297 struct 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 
368 static 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)