OpenShot Library | libopenshot-audio  0.2.0
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 = (uInt) dataSize;
85  stream.avail_out = (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 #if JUCE_UNIT_TESTS
159 
160 struct GZIPTests : public UnitTest
161 {
162  GZIPTests() : UnitTest ("GZIP", "Compression") {}
163 
164  void runTest() override
165  {
166  beginTest ("GZIP");
167  Random rng = getRandom();
168 
169  for (int i = 100; --i >= 0;)
170  {
171  MemoryOutputStream original, compressed, uncompressed;
172 
173  {
174  GZIPCompressorOutputStream zipper (compressed, rng.nextInt (10));
175 
176  for (int j = rng.nextInt (100); --j >= 0;)
177  {
178  MemoryBlock data ((unsigned int) (rng.nextInt (2000) + 1));
179 
180  for (int k = (int) data.getSize(); --k >= 0;)
181  data[k] = (char) rng.nextInt (255);
182 
183  original << data;
184  zipper << data;
185  }
186  }
187 
188  {
189  MemoryInputStream compressedInput (compressed.getData(), compressed.getDataSize(), false);
190  GZIPDecompressorInputStream unzipper (compressedInput);
191 
192  uncompressed << unzipper;
193  }
194 
195  expectEquals ((int) uncompressed.getDataSize(),
196  (int) original.getDataSize());
197 
198  if (original.getDataSize() == uncompressed.getDataSize())
199  expect (memcmp (uncompressed.getData(),
200  original.getData(),
201  original.getDataSize()) == 0);
202  }
203  }
204 };
205 
206 static GZIPTests gzipTests;
207 
208 #endif
209 
210 } // namespace juce
juce::GZIPCompressorOutputStream::setPosition
bool setPosition(int64) override
Tries to move the stream's output position.
Definition: juce_GZIPCompressorOutputStream.cpp:151
juce::GZIPCompressorOutputStream
A stream which uses zlib to compress the data written into it.
Definition: juce_GZIPCompressorOutputStream.h:42
juce::OutputStream::write
virtual bool write(const void *dataToWrite, size_t numberOfBytes)=0
Writes a block of data to the stream.
juce::OutputStream
The base class for streams that write data to some kind of destination.
Definition: juce_OutputStream.h:41
juce::GZIPCompressorOutputStream::getPosition
int64 getPosition() override
Returns the stream's current position.
Definition: juce_GZIPCompressorOutputStream.cpp:146
juce::GZIPCompressorOutputStream::GZIPCompressorHelper
Definition: juce_GZIPCompressorOutputStream.cpp:26
juce::GZIPCompressorOutputStream::flush
void flush() override
Flushes and closes the stream.
Definition: juce_GZIPCompressorOutputStream.cpp:133
juce::GZIPCompressorOutputStream::~GZIPCompressorOutputStream
~GZIPCompressorOutputStream() override
Destructor.
Definition: juce_GZIPCompressorOutputStream.cpp:128
juce::UnitTest
This is a base class for classes that perform a unit test.
Definition: juce_UnitTest.h:73
juce::GZIPCompressorOutputStream::GZIPCompressorOutputStream
GZIPCompressorOutputStream(OutputStream &destStream, int compressionLevel=-1, int windowBits=0)
Creates a compression stream.
Definition: juce_GZIPCompressorOutputStream.cpp:116
juce::GZIPCompressorOutputStream::write
bool write(const void *, size_t) override
Writes a block of data to the stream.
Definition: juce_GZIPCompressorOutputStream.cpp:139