OpenShot Library | OpenShotAudio  0.2.1
juce_GZIPCompressorOutputStream.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 
27 {
28 public:
29  GZIPCompressorHelper (int compressionLevel, int windowBits)
30  : compLevel ((compressionLevel < 0 || compressionLevel > 9) ? -1 : compressionLevel)
31  {
32  using namespace zlibNamespace;
33  zerostruct (stream);
34 
35  streamIsValid = (deflateInit2 (&stream, compLevel, Z_DEFLATED,
36  windowBits != 0 ? windowBits : MAX_WBITS,
37  8, strategy) == Z_OK);
38  }
39 
41  {
42  if (streamIsValid)
43  zlibNamespace::deflateEnd (&stream);
44  }
45 
46  bool write (const uint8* data, size_t dataSize, OutputStream& out)
47  {
48  // When you call flush() on a gzip stream, the stream is closed, and you can
49  // no longer continue to write data to it!
50  jassert (! finished);
51 
52  while (dataSize > 0)
53  if (! doNextBlock (data, dataSize, out, Z_NO_FLUSH))
54  return false;
55 
56  return true;
57  }
58 
59  void finish (OutputStream& out)
60  {
61  const uint8* data = nullptr;
62  size_t dataSize = 0;
63 
64  while (! finished)
65  doNextBlock (data, dataSize, out, Z_FINISH);
66  }
67 
68 private:
69  enum { strategy = 0 };
70 
71  zlibNamespace::z_stream stream;
72  const int compLevel;
73  bool isFirstDeflate = true, streamIsValid = false, finished = false;
74  zlibNamespace::Bytef buffer[32768];
75 
76  bool doNextBlock (const uint8*& data, size_t& dataSize, OutputStream& out, const int flushMode)
77  {
78  using namespace zlibNamespace;
79 
80  if (streamIsValid)
81  {
82  stream.next_in = const_cast<uint8*> (data);
83  stream.next_out = buffer;
84  stream.avail_in = (z_uInt) dataSize;
85  stream.avail_out = (z_uInt) sizeof (buffer);
86 
87  auto result = isFirstDeflate ? deflateParams (&stream, compLevel, strategy)
88  : deflate (&stream, flushMode);
89  isFirstDeflate = false;
90 
91  switch (result)
92  {
93  case Z_STREAM_END:
94  finished = true;
95  // Deliberate fall-through..
96  case Z_OK:
97  {
98  data += dataSize - stream.avail_in;
99  dataSize = stream.avail_in;
100  auto bytesDone = (ssize_t) sizeof (buffer) - (ssize_t) stream.avail_out;
101  return bytesDone <= 0 || out.write (buffer, (size_t) bytesDone);
102  }
103 
104  default:
105  break;
106  }
107  }
108 
109  return false;
110  }
111 
112  JUCE_DECLARE_NON_COPYABLE (GZIPCompressorHelper)
113 };
114 
115 //==============================================================================
117  : GZIPCompressorOutputStream (&s, compressionLevel, false, windowBits)
118 {
119 }
120 
121 GZIPCompressorOutputStream::GZIPCompressorOutputStream (OutputStream* out, int compressionLevel, bool deleteDestStream, int windowBits)
122  : destStream (out, deleteDestStream),
123  helper (new GZIPCompressorHelper (compressionLevel, windowBits))
124 {
125  jassert (out != nullptr);
126 }
127 
129 {
130  flush();
131 }
132 
134 {
135  helper->finish (*destStream);
136  destStream->flush();
137 }
138 
139 bool GZIPCompressorOutputStream::write (const void* destBuffer, size_t howMany)
140 {
141  jassert (destBuffer != nullptr && (ssize_t) howMany >= 0);
142 
143  return helper->write (static_cast<const uint8*> (destBuffer), howMany, *destStream);
144 }
145 
147 {
148  return destStream->getPosition();
149 }
150 
151 bool GZIPCompressorOutputStream::setPosition (int64 /*newPosition*/)
152 {
153  jassertfalse; // can't do it!
154  return false;
155 }
156 
157 
158 //==============================================================================
159 //==============================================================================
160 #if JUCE_UNIT_TESTS
161 
162 struct GZIPTests : public UnitTest
163 {
164  GZIPTests()
165  : UnitTest ("GZIP", UnitTestCategories::compression)
166  {}
167 
168  void runTest() override
169  {
170  beginTest ("GZIP");
171  Random rng = getRandom();
172 
173  for (int i = 100; --i >= 0;)
174  {
175  MemoryOutputStream original, compressed, uncompressed;
176 
177  {
178  GZIPCompressorOutputStream zipper (compressed, rng.nextInt (10));
179 
180  for (int j = rng.nextInt (100); --j >= 0;)
181  {
182  MemoryBlock data ((unsigned int) (rng.nextInt (2000) + 1));
183 
184  for (int k = (int) data.getSize(); --k >= 0;)
185  data[k] = (char) rng.nextInt (255);
186 
187  original << data;
188  zipper << data;
189  }
190  }
191 
192  {
193  MemoryInputStream compressedInput (compressed.getData(), compressed.getDataSize(), false);
194  GZIPDecompressorInputStream unzipper (compressedInput);
195 
196  uncompressed << unzipper;
197  }
198 
199  expectEquals ((int) uncompressed.getDataSize(),
200  (int) original.getDataSize());
201 
202  if (original.getDataSize() == uncompressed.getDataSize())
203  expect (memcmp (uncompressed.getData(),
204  original.getData(),
205  original.getDataSize()) == 0);
206  }
207  }
208 };
209 
210 static GZIPTests gzipTests;
211 
212 #endif
213 
214 } // 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 bool write(const void *dataToWrite, size_t numberOfBytes)=0
Writes a block of data to the stream.
int nextInt() noexcept
Returns the next random 32 bit integer.
Definition: juce_Random.cpp:78
GZIPCompressorOutputStream(OutputStream &destStream, int compressionLevel=-1, int windowBits=0)
Creates a compression stream.
A stream which uses zlib to compress the data written into it.
This is a base class for classes that perform a unit test.
Definition: juce_UnitTest.h:73
bool write(const void *, size_t) override
Writes a block of data to the stream.
const void * getData() const noexcept
Returns a pointer to the data that has been written to the stream.
The base class for streams that write data to some kind of destination.
bool setPosition(int64) override
Tries to move the stream&#39;s output position.
size_t getDataSize() const noexcept
Returns the number of bytes of data that have been written to the stream.
A random number generator.
Definition: juce_Random.h:38
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.
int64 getPosition() override
Returns the stream&#39;s current position.
Allows a block of data to be accessed as a stream.