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