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 }