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
23namespace juce
24{
25
27{
28public:
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
68private:
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
121GZIPCompressorOutputStream::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
139bool 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
151bool GZIPCompressorOutputStream::setPosition (int64 /*newPosition*/)
152{
153 jassertfalse; // can't do it!
154 return false;
155}
156
157//==============================================================================
158#if JUCE_UNIT_TESTS
159
160struct 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
206static GZIPTests gzipTests;
207
208#endif
209
210} // namespace juce
A stream which uses zlib to compress the data written into it.
GZIPCompressorOutputStream(OutputStream &destStream, int compressionLevel=-1, int windowBits=0)
Creates a compression stream.
bool setPosition(int64) override
Tries to move the stream's output position.
bool write(const void *, size_t) override
Writes a block of data to the stream.
void flush() override
Flushes and closes the stream.
int64 getPosition() override
Returns the stream's current position.
The base class for streams that write data to some kind of destination.
virtual bool write(const void *dataToWrite, size_t numberOfBytes)=0
Writes a block of data to the stream.
This is a base class for classes that perform a unit test.