OpenShot Library | OpenShotAudio  0.2.1
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 
23 namespace juce
24 {
25 
26 #if JUCE_MSVC
27  #pragma warning (push)
28  #pragma warning (disable: 4309 4305 4365)
29 #endif
30 
31 namespace 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.
115 {
116 public:
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 
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 
195 private:
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 
226 {
227 }
228 
230 {
231  return uncompressedStreamLength;
232 }
233 
234 int GZIPDecompressorInputStream::read (void* destBuffer, int howMany)
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 
318 struct GZIPDecompressorInputStreamTests : public UnitTest
319 {
320  GZIPDecompressorInputStreamTests()
321  : UnitTest ("GZIPDecompressorInputStreamTests", UnitTestCategories::streams)
322  {}
323 
324  void runTest() override
325  {
326  const MemoryBlock data ("abcdefghijklmnopqrstuvwxyz", 26);
327 
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);
375  numBytesRead += 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 
389 static GZIPDecompressorInputStreamTests gzipDecompressorInputStreamTests;
390 
391 #endif
392 
393 } // namespace juce
size_t getSize() const noexcept
Returns the block&#39;s current allocated size, in bytes.
void flush() override
Flushes and closes the stream.
virtual void skipNextBytes(int64 numBytesToSkip)
Reads and discards a number of bytes from the stream.
bool isExhausted() override
Returns true if the stream has no more data to read.
The base class for streams that read data.
A stream which uses zlib to compress the data written into it.
bool setPosition(int64 pos) override
Tries to move the current read position of the stream.
This is a base class for classes that perform a unit test.
Definition: juce_UnitTest.h:73
int64 getPosition() override
Returns the offset of the next byte that will be read from the stream.
bool write(const void *, size_t) override
Writes a block of data to the stream.
int read(void *destBuffer, int maxBytesToRead) override
Reads some data from the stream into a memory buffer.
const void * getData() const noexcept
Returns a pointer to the data that has been written to the stream.
void * getData() noexcept
Returns a void pointer to the data.
GZIPDecompressorInputStream(InputStream *sourceStream, bool deleteSourceWhenDestroyed, Format sourceFormat=zlibFormat, int64 uncompressedStreamLength=-1)
Creates a decompressor stream.
int64 getTotalLength() override
Returns the total number of bytes available for reading in this stream.
size_t getDataSize() const noexcept
Returns the number of bytes of data that have been written to the stream.
Writes data to an internal memory buffer, which grows as required.
This stream will decompress a source-stream using zlib.
A class to hold a resizable block of raw data.
Allows a block of data to be accessed as a stream.