1 /**
2 * Zlib Compressor
3 * 
4 * Copyright:
5 * (C) 2001 Peter J Jones
6 *     2001-2007 Jack Lloyd
7 * (C) 2014-2015 Etienne Cimon
8 *
9 * License:
10 * Botan is released under the Simplified BSD License (see LICENSE.md)
11 */
12 module botan.compression.zlib;
13 
14 import botan.constants;
15 static if (BOTAN_HAS_ZLIB):
16 
17 import botan.compression.compress;
18 import botan.utils.exceptn;
19 import etc.c.zlib;
20 import botan.algo_base.transform;
21 import botan.utils.types;
22 import core.exception;
23 import std.datetime;
24 import botan.utils.mem_ops;
25 
26 /**
27 * Zlib Compression
28 */
29 class ZlibCompression : StreamCompression, Transformation
30 {
31 public:
32     /**
33       * @param level how much effort to use on compressing (0 to 9);
34       *        higher levels are slower but tend to give better
35       *        compression
36       */
37     this(size_t level = 6)
38     {
39         m_level = level; 
40     }
41     
42     override string name() const { return "ZlibCompression"; }
43     
44 protected:
45     override CompressionStream makeStream() const
46     {
47         return new ZlibCompressionStream(m_level, 15);
48     }
49 
50     const size_t m_level;
51 
52     // interface fall-through
53     override void flush(ref SecureVector!ubyte buf, size_t offset) { super.flush(buf, offset); }
54     override string provider() const { return "core"; }
55     override size_t updateGranularity() const { return 1; }
56     override size_t minimumFinalSize() const { return 0; }    
57     override size_t defaultNonceLength() const { return 0; }    
58     override bool validNonceLength(size_t nonce_len) const { return nonce_len == 0; }
59     override SecureVector!ubyte startRaw(const(ubyte)* data, size_t data_len) { return super.startRaw(data, data_len); }
60     override void update(ref SecureVector!ubyte buf, size_t offset) { super.update(buf, offset); }
61     override void finish(ref SecureVector!ubyte buf, size_t offset) { super.finish(buf, offset); }
62     override size_t outputLength(size_t input_length) const { return super.outputLength(input_length); }
63     override void clear() { return super.clear(); }
64 }
65 
66 /**
67 * Zlib Decompression
68 */
69 class ZlibDecompression : StreamDecompression, Transformation
70 {
71 public:
72     override string name() const { return "ZlibDecompression"; }
73     
74 protected:
75     override CompressionStream makeStream() const
76     {
77         return new ZlibDecompressionStream(15);
78     }
79 
80     alias startRaw = StreamDecompression.startRaw;
81     // interface fall-through
82     override void flush(ref SecureVector!ubyte buf, size_t offset) { super.flush(buf, offset); }
83     override string provider() const { return "core"; }
84     override size_t updateGranularity() const { return 1; }
85     override size_t minimumFinalSize() const { return 0; }    
86     override size_t defaultNonceLength() const { return 0; }    
87     override bool validNonceLength(size_t nonce_len) const { return nonce_len == 0; }
88     override SecureVector!ubyte startRaw(const(ubyte)* data, size_t data_len) { return super.startRaw(data, data_len); }
89     override void update(ref SecureVector!ubyte buf, size_t offset) { super.update(buf, offset); }
90     override void finish(ref SecureVector!ubyte buf, size_t offset) { super.finish(buf, offset); }
91     override size_t outputLength(size_t input_length) const { return super.outputLength(input_length); }
92     override void clear() { return super.clear(); }
93 }
94 
95 /**
96 * Deflate Compression
97 */
98 class DeflateCompression : StreamCompression, Transformation
99 {
100 public:
101     /**
102       * @param level how much effort to use on compressing (0 to 9);
103       *        higher levels are slower but tend to give better
104       *        compression
105       */
106     this(size_t level = 6) 
107     { m_level = level; }
108     
109     override string name() const { return "DeflateCompression"; }
110     
111 protected:
112     override CompressionStream makeStream() const
113     {
114         return new DeflateCompressionStream(m_level, 15);
115     }
116 
117     const size_t m_level;
118     // interface fall-through
119     override void flush(ref SecureVector!ubyte buf, size_t offset) { super.flush(buf, offset); }
120     override string provider() const { return "core"; }
121     override size_t updateGranularity() const { return 1; }
122     override size_t minimumFinalSize() const { return 0; }    
123     override size_t defaultNonceLength() const { return 0; }    
124     override bool validNonceLength(size_t nonce_len) const { return nonce_len == 0; }
125     override SecureVector!ubyte startRaw(const(ubyte)* data, size_t data_len) { return super.startRaw(data, data_len); }
126     override void update(ref SecureVector!ubyte buf, size_t offset) { super.update(buf, offset); }
127     override void finish(ref SecureVector!ubyte buf, size_t offset) { super.finish(buf, offset); }
128     override size_t outputLength(size_t input_length) const { return super.outputLength(input_length); }
129     override void clear() { return super.clear(); }
130 }
131 
132 /**
133 * Deflate Decompression
134 */
135 class DeflateDecompression : StreamDecompression, Transformation
136 {
137 public:
138     override string name() const { return "DeflateDecompression"; }
139     
140 protected:
141     override CompressionStream makeStream() const
142     {
143         return new DeflateDecompressionStream(15);
144     }
145 
146     // interface fall-through
147     override void flush(ref SecureVector!ubyte buf, size_t offset) { super.flush(buf, offset); }
148     override string provider() const { return "core"; }
149     override size_t updateGranularity() const { return 1; }
150     override size_t minimumFinalSize() const { return 0; }    
151     override size_t defaultNonceLength() const { return 0; }    
152     override bool validNonceLength(size_t nonce_len) const { return nonce_len == 0; }
153     override SecureVector!ubyte startRaw(const(ubyte)* data, size_t data_len) { return super.startRaw(data, data_len); }
154     override void update(ref SecureVector!ubyte buf, size_t offset) { super.update(buf, offset); }
155     override void finish(ref SecureVector!ubyte buf, size_t offset) { super.finish(buf, offset); }
156     override size_t outputLength(size_t input_length) const { return super.outputLength(input_length); }
157     override void clear() { return super.clear(); }
158 }
159 
160 /**
161 * Gzip Compression
162 */
163 class GzipCompression : StreamCompression, Transformation
164 {
165 public:
166     /**
167       * @param level how much effort to use on compressing (0 to 9);
168       *        higher levels are slower but tend to give better
169       *        compression
170       */
171     this(size_t level = 6, ubyte os_code = 255)
172     {
173         m_level = level; 
174         m_os_code = os_code;
175     }
176     override string name() const { return "GzipCompression"; }
177     
178 protected:
179     override CompressionStream makeStream() const
180     {
181         return new GzipCompressionStream(m_level, 15, m_os_code);
182     }
183     
184     const size_t m_level;
185     const byte m_os_code;
186 
187     // interface fall-through
188     override void flush(ref SecureVector!ubyte buf, size_t offset) { super.flush(buf, offset); }
189     override string provider() const { return "core"; }
190     override size_t updateGranularity() const { return 1; }
191     override size_t minimumFinalSize() const { return 0; }    
192     override size_t defaultNonceLength() const { return 0; }    
193     override bool validNonceLength(size_t nonce_len) const { return nonce_len == 0; }
194     override SecureVector!ubyte startRaw(const(ubyte)* data, size_t data_len) { return super.startRaw(data, data_len); }
195     override void update(ref SecureVector!ubyte buf, size_t offset) { super.update(buf, offset); }
196     override void finish(ref SecureVector!ubyte buf, size_t offset) { super.finish(buf, offset); }
197     override size_t outputLength(size_t input_length) const { return super.outputLength(input_length); }
198     override void clear() { return super.clear(); }
199 }
200 
201 /**
202 * Gzip Decompression
203 */
204 class GzipDecompression : StreamCompression, Transformation
205 {
206 public:
207     override string name() const { return "GzipDecompression"; }
208     
209 protected:
210     override CompressionStream makeStream() const
211     {
212         return new GzipDecompressionStream(15);
213     }
214 
215     // interface fall-through
216     override void flush(ref SecureVector!ubyte buf, size_t offset) { super.flush(buf, offset); }
217     override string provider() const { return "core"; }
218     override size_t updateGranularity() const { return 1; }
219     override size_t minimumFinalSize() const { return 0; }    
220     override size_t defaultNonceLength() const { return 0; }    
221     override bool validNonceLength(size_t nonce_len) const { return nonce_len == 0; }
222     override SecureVector!ubyte startRaw(const(ubyte)* data, size_t data_len) { return super.startRaw(data, data_len); }
223     override void update(ref SecureVector!ubyte buf, size_t offset) { super.update(buf, offset); }
224     override void finish(ref SecureVector!ubyte buf, size_t offset) { super.finish(buf, offset); }
225     override size_t outputLength(size_t input_length) const { return super.outputLength(input_length); }
226     override void clear() { return super.clear(); }
227 }
228 
229 package:
230 
231 abstract class ZlibStream : ZlibStyleStream!(z_stream, ubyte), CompressionStream
232 {
233 public:
234     this()
235     {
236         streamp().opaque = cast(void*)alloc();
237         streamp().zalloc = &CompressionAllocInfo.malloc!uint;
238         streamp().zfree = &CompressionAllocInfo.free;
239     }
240     
241     override uint runFlag() const { return Z_NO_FLUSH; }
242     override uint flushFlag() const { return Z_FULL_FLUSH; }
243     override uint finishFlag() const { return Z_FINISH; }
244     
245     int computeWindowBits(int wbits, int wbits_offset) const
246     {
247         if (wbits_offset == -1)
248             return -wbits;
249         else
250             return wbits + wbits_offset;
251     }
252     // interface fall-through
253     override void nextIn(ubyte* b, size_t len) { super.nextIn(b, len); }    
254     override void nextOut(ubyte* b, size_t len) { super.nextOut(b, len); }    
255     override size_t availIn() const { return super.availIn(); }    
256     override size_t availOut() const { return super.availOut; }
257 }
258 
259 class ZlibCompressionStream : ZlibStream, CompressionStream
260 {
261 public:
262     this(size_t level, int wbits, int wbits_offset = 0)
263     {
264         wbits = computeWindowBits(wbits, wbits_offset);
265         
266         int rc = deflateInit2(streamp(), cast(int) level, Z_DEFLATED, wbits, 8, Z_DEFAULT_STRATEGY);
267         if (rc != Z_OK)
268             throw new Exception("zlib deflate initialization failed: " ~ rc.to!string);
269     }
270     
271     ~this()
272     {
273         deflateEnd(streamp());
274     }
275 
276 
277     override bool run(uint flags)
278     {
279         int rc = deflate(streamp(), flags);
280         
281         if (rc == Z_MEM_ERROR)
282             throw new InvalidMemoryOperationError();
283         else if (rc != Z_OK && rc != Z_STREAM_END)
284             throw new Exception("zlib deflate error");
285         
286         return (rc == Z_STREAM_END);
287     }
288 
289     // interface fall-through
290     override void nextIn(ubyte* b, size_t len) { super.nextIn(b, len); }    
291     override void nextOut(ubyte* b, size_t len) { super.nextOut(b, len); }    
292     override size_t availIn() const { return super.availIn(); }    
293     override size_t availOut() const { return super.availOut; }
294     override uint runFlag() const { return super.runFlag(); }
295     override uint flushFlag() const { return super.flushFlag(); }
296     override uint finishFlag() const { return super.finishFlag(); }
297 }
298 
299 class ZlibDecompressionStream : ZlibStream, CompressionStream
300 {
301 public:
302     this(int wbits, int wbits_offset = 0)
303     {
304         int rc = inflateInit2(streamp(), computeWindowBits(wbits, wbits_offset));
305         
306         if (rc == Z_MEM_ERROR)
307             throw new InvalidMemoryOperationError();
308         else if (rc != Z_OK)
309             throw new Exception("zlib inflate initialization failed");
310     }
311     
312     ~this()
313     {
314         inflateEnd(streamp());
315     }
316     
317     override bool run(uint flags)
318     {
319         int rc = inflate(streamp(), flags);
320         
321         if (rc == Z_MEM_ERROR)
322             throw new InvalidMemoryOperationError();
323         else if (rc != Z_OK && rc != Z_STREAM_END)
324             throw new Exception("zlib deflate error: " ~ rc.to!string);
325         
326         return (rc == Z_STREAM_END);
327     }
328     // interface fall-through
329     override void nextIn(ubyte* b, size_t len) { super.nextIn(b, len); }    
330     override void nextOut(ubyte* b, size_t len) { super.nextOut(b, len); }    
331     override size_t availIn() const { return super.availIn(); }    
332     override size_t availOut() const { return super.availOut; }
333     override uint runFlag() const { return super.runFlag(); }
334     override uint flushFlag() const { return super.flushFlag(); }
335     override uint finishFlag() const { return super.finishFlag(); }
336 }
337 
338 class DeflateCompressionStream : ZlibCompressionStream
339 {
340 public:
341     this(size_t level, int wbits)
342     {
343         super(level, wbits, -1);
344     }
345 }
346 
347 class DeflateDecompressionStream : ZlibDecompressionStream
348 {
349 public:
350     this(int wbits)
351     {
352         super(wbits, -1);
353     }
354 }
355 
356 class GzipCompressionStream : ZlibCompressionStream
357 {
358 public:
359     this(size_t level, int wbits, ubyte os_code)
360     {
361         super(level, wbits, 16);
362         clearMem(&m_header, 1);
363         m_header.os = os_code;
364         m_header.time = Clock.currTime(UTC()).toUnixTime();
365         
366         int rc = deflateSetHeader(streamp(), &m_header);
367         if (rc != Z_OK)
368             throw new Exception("setting gzip header failed");
369     }
370     
371 protected:
372     .gz_header m_header;
373 }
374 
375 class GzipDecompressionStream : ZlibDecompressionStream
376 {
377 public:
378     this(int wbits)
379     { super(wbits, 16); }
380 }