Fix build on sparc64-linux-gnu.
[official-gcc.git] / libphobos / src / std / zlib.d
blobe6cce240fd589527ab61acfc160d5e1a6ac098bc
1 // Written in the D programming language.
3 /**
4 * Compress/decompress data using the $(HTTP www._zlib.net, _zlib library).
6 * Examples:
8 * If you have a small buffer you can use $(LREF compress) and
9 * $(LREF uncompress) directly.
11 * -------
12 * import std.zlib;
14 * auto src =
15 * "the quick brown fox jumps over the lazy dog\r
16 * the quick brown fox jumps over the lazy dog\r";
18 * ubyte[] dst;
19 * ubyte[] result;
21 * dst = compress(src);
22 * result = cast(ubyte[]) uncompress(dst);
23 * assert(result == src);
24 * -------
26 * When the data to be compressed doesn't fit in one buffer, use
27 * $(LREF Compress) and $(LREF UnCompress).
29 * -------
30 * import std.zlib;
31 * import std.stdio;
32 * import std.conv : to;
33 * import std.algorithm.iteration : map;
35 * UnCompress decmp = new UnCompress;
36 * foreach (chunk; stdin.byChunk(4096).map!(x => decmp.uncompress(x)))
37 * {
38 * chunk.to!string.write;
39 * }
41 * -------
43 * References:
44 * $(HTTP en.wikipedia.org/wiki/Zlib, Wikipedia)
46 * Copyright: Copyright Digital Mars 2000 - 2011.
47 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
48 * Authors: $(HTTP digitalmars.com, Walter Bright)
49 * Source: $(PHOBOSSRC std/_zlib.d)
51 /* Copyright Digital Mars 2000 - 2011.
52 * Distributed under the Boost Software License, Version 1.0.
53 * (See accompanying file LICENSE_1_0.txt or copy at
54 * http://www.boost.org/LICENSE_1_0.txt)
56 module std.zlib;
58 //debug=zlib; // uncomment to turn on debugging printf's
60 import etc.c.zlib;
62 // Values for 'mode'
64 enum
66 Z_NO_FLUSH = 0,
67 Z_SYNC_FLUSH = 2,
68 Z_FULL_FLUSH = 3,
69 Z_FINISH = 4,
72 /*************************************
73 * Errors throw a ZlibException.
76 class ZlibException : Exception
78 this(int errnum)
79 { string msg;
81 switch (errnum)
83 case Z_STREAM_END: msg = "stream end"; break;
84 case Z_NEED_DICT: msg = "need dict"; break;
85 case Z_ERRNO: msg = "errno"; break;
86 case Z_STREAM_ERROR: msg = "stream error"; break;
87 case Z_DATA_ERROR: msg = "data error"; break;
88 case Z_MEM_ERROR: msg = "mem error"; break;
89 case Z_BUF_ERROR: msg = "buf error"; break;
90 case Z_VERSION_ERROR: msg = "version error"; break;
91 default: msg = "unknown error"; break;
93 super(msg);
97 /**
98 * $(P Compute the Adler-32 checksum of a buffer's worth of data.)
100 * Params:
101 * adler = the starting checksum for the computation. Use 1
102 * for a new checksum. Use the output of this function
103 * for a cumulative checksum.
104 * buf = buffer containing input data
106 * Returns:
107 * A $(D uint) checksum for the provided input data and starting checksum
109 * See_Also:
110 * $(LINK http://en.wikipedia.org/wiki/Adler-32)
113 uint adler32(uint adler, const(void)[] buf)
115 import std.range : chunks;
116 foreach (chunk; (cast(ubyte[]) buf).chunks(0xFFFF0000))
118 adler = etc.c.zlib.adler32(adler, chunk.ptr, cast(uint) chunk.length);
120 return adler;
124 @system unittest
126 static ubyte[] data = [1,2,3,4,5,6,7,8,9,10];
128 uint adler = adler32(0u, data);
129 assert(adler == 0xdc0037);
132 @system unittest
134 static string data = "test";
136 uint adler = adler32(1, data);
137 assert(adler == 0x045d01c1);
141 * $(P Compute the CRC32 checksum of a buffer's worth of data.)
143 * Params:
144 * crc = the starting checksum for the computation. Use 0
145 * for a new checksum. Use the output of this function
146 * for a cumulative checksum.
147 * buf = buffer containing input data
149 * Returns:
150 * A $(D uint) checksum for the provided input data and starting checksum
152 * See_Also:
153 * $(LINK http://en.wikipedia.org/wiki/Cyclic_redundancy_check)
156 uint crc32(uint crc, const(void)[] buf)
158 import std.range : chunks;
159 foreach (chunk; (cast(ubyte[]) buf).chunks(0xFFFF0000))
161 crc = etc.c.zlib.crc32(crc, chunk.ptr, cast(uint) chunk.length);
163 return crc;
166 @system unittest
168 static ubyte[] data = [1,2,3,4,5,6,7,8,9,10];
170 uint crc;
172 debug(zlib) printf("D.zlib.crc32.unittest\n");
173 crc = crc32(0u, cast(void[]) data);
174 debug(zlib) printf("crc = %x\n", crc);
175 assert(crc == 0x2520577b);
179 * $(P Compress data)
181 * Params:
182 * srcbuf = buffer containing the data to compress
183 * level = compression level. Legal values are -1 .. 9, with -1 indicating
184 * the default level (6), 0 indicating no compression, 1 being the
185 * least compression and 9 being the most.
187 * Returns:
188 * the compressed data
191 ubyte[] compress(const(void)[] srcbuf, int level)
194 assert(-1 <= level && level <= 9);
196 body
198 import core.memory : GC;
199 auto destlen = srcbuf.length + ((srcbuf.length + 1023) / 1024) + 12;
200 auto destbuf = new ubyte[destlen];
201 auto err = etc.c.zlib.compress2(destbuf.ptr, &destlen, cast(ubyte *) srcbuf.ptr, srcbuf.length, level);
202 if (err)
204 GC.free(destbuf.ptr);
205 throw new ZlibException(err);
208 destbuf.length = destlen;
209 return destbuf;
212 /*********************************************
213 * ditto
216 ubyte[] compress(const(void)[] srcbuf)
218 return compress(srcbuf, Z_DEFAULT_COMPRESSION);
221 /*********************************************
222 * Decompresses the data in srcbuf[].
223 * Params:
224 * srcbuf = buffer containing the compressed data.
225 * destlen = size of the uncompressed data.
226 * It need not be accurate, but the decompression will be faster
227 * if the exact size is supplied.
228 * winbits = the base two logarithm of the maximum window size.
229 * Returns: the decompressed data.
232 void[] uncompress(const(void)[] srcbuf, size_t destlen = 0u, int winbits = 15)
234 import std.conv : to;
235 int err;
236 ubyte[] destbuf;
238 if (!destlen)
239 destlen = srcbuf.length * 2 + 1;
241 etc.c.zlib.z_stream zs;
242 zs.next_in = cast(typeof(zs.next_in)) srcbuf.ptr;
243 zs.avail_in = to!uint(srcbuf.length);
244 err = etc.c.zlib.inflateInit2(&zs, winbits);
245 if (err)
247 throw new ZlibException(err);
250 size_t olddestlen = 0u;
252 loop:
253 while (true)
255 destbuf.length = destlen;
256 zs.next_out = cast(typeof(zs.next_out)) &destbuf[olddestlen];
257 zs.avail_out = to!uint(destlen - olddestlen);
258 olddestlen = destlen;
260 err = etc.c.zlib.inflate(&zs, Z_NO_FLUSH);
261 switch (err)
263 case Z_OK:
264 destlen = destbuf.length * 2;
265 continue loop;
267 case Z_STREAM_END:
268 destbuf.length = zs.total_out;
269 err = etc.c.zlib.inflateEnd(&zs);
270 if (err != Z_OK)
271 throw new ZlibException(err);
272 return destbuf;
274 default:
275 etc.c.zlib.inflateEnd(&zs);
276 throw new ZlibException(err);
279 assert(0);
282 @system unittest
284 auto src =
285 "the quick brown fox jumps over the lazy dog\r
286 the quick brown fox jumps over the lazy dog\r
288 ubyte[] dst;
289 ubyte[] result;
291 //arrayPrint(src);
292 dst = compress(src);
293 //arrayPrint(dst);
294 result = cast(ubyte[]) uncompress(dst);
295 //arrayPrint(result);
296 assert(result == src);
299 @system unittest
301 ubyte[] src = new ubyte[1000000];
302 ubyte[] dst;
303 ubyte[] result;
305 src[] = 0x80;
306 dst = compress(src);
307 assert(dst.length*2 + 1 < src.length);
308 result = cast(ubyte[]) uncompress(dst);
309 assert(result == src);
313 void arrayPrint(ubyte[] array)
315 //printf("array %p,%d\n", cast(void*) array, array.length);
316 for (size_t i = 0; i < array.length; i++)
318 printf("%02x ", array[i]);
319 if (((i + 1) & 15) == 0)
320 printf("\n");
322 printf("\n\n");
326 /// the header format the compressed stream is wrapped in
327 enum HeaderFormat {
328 deflate, /// a standard zlib header
329 gzip, /// a gzip file format header
330 determineFromData /// used when decompressing. Try to automatically detect the stream format by looking at the data
333 /*********************************************
334 * Used when the data to be compressed is not all in one buffer.
337 class Compress
339 import std.conv : to;
341 private:
342 z_stream zs;
343 int level = Z_DEFAULT_COMPRESSION;
344 int inited;
345 immutable bool gzip;
347 void error(int err)
349 if (inited)
350 { deflateEnd(&zs);
351 inited = 0;
353 throw new ZlibException(err);
356 public:
359 * Constructor.
361 * Params:
362 * level = compression level. Legal values are 1 .. 9, with 1 being the least
363 * compression and 9 being the most. The default value is 6.
364 * header = sets the compression type to one of the options available
365 * in $(LREF HeaderFormat). Defaults to HeaderFormat.deflate.
367 * See_Also:
368 * $(LREF compress), $(LREF HeaderFormat)
370 this(int level, HeaderFormat header = HeaderFormat.deflate)
373 assert(1 <= level && level <= 9);
375 body
377 this.level = level;
378 this.gzip = header == HeaderFormat.gzip;
381 /// ditto
382 this(HeaderFormat header = HeaderFormat.deflate)
384 this.gzip = header == HeaderFormat.gzip;
387 ~this()
388 { int err;
390 if (inited)
392 inited = 0;
393 deflateEnd(&zs);
398 * Compress the data in buf and return the compressed data.
399 * Params:
400 * buf = data to compress
402 * Returns:
403 * the compressed data. The buffers returned from successive calls to this should be concatenated together.
406 const(void)[] compress(const(void)[] buf)
408 import core.memory : GC;
409 int err;
410 ubyte[] destbuf;
412 if (buf.length == 0)
413 return null;
415 if (!inited)
417 err = deflateInit2(&zs, level, Z_DEFLATED, 15 + (gzip ? 16 : 0), 8, Z_DEFAULT_STRATEGY);
418 if (err)
419 error(err);
420 inited = 1;
423 destbuf = new ubyte[zs.avail_in + buf.length];
424 zs.next_out = destbuf.ptr;
425 zs.avail_out = to!uint(destbuf.length);
427 if (zs.avail_in)
428 buf = zs.next_in[0 .. zs.avail_in] ~ cast(ubyte[]) buf;
430 zs.next_in = cast(typeof(zs.next_in)) buf.ptr;
431 zs.avail_in = to!uint(buf.length);
433 err = deflate(&zs, Z_NO_FLUSH);
434 if (err != Z_STREAM_END && err != Z_OK)
436 GC.free(destbuf.ptr);
437 error(err);
439 destbuf.length = destbuf.length - zs.avail_out;
440 return destbuf;
443 /***
444 * Compress and return any remaining data.
445 * The returned data should be appended to that returned by compress().
446 * Params:
447 * mode = one of the following:
448 * $(DL
449 $(DT Z_SYNC_FLUSH )
450 $(DD Syncs up flushing to the next byte boundary.
451 Used when more data is to be compressed later on.)
452 $(DT Z_FULL_FLUSH )
453 $(DD Syncs up flushing to the next byte boundary.
454 Used when more data is to be compressed later on,
455 and the decompressor needs to be restartable at this
456 point.)
457 $(DT Z_FINISH)
458 $(DD (default) Used when finished compressing the data. )
461 void[] flush(int mode = Z_FINISH)
464 assert(mode == Z_FINISH || mode == Z_SYNC_FLUSH || mode == Z_FULL_FLUSH);
466 body
468 import core.memory : GC;
469 ubyte[] destbuf;
470 ubyte[512] tmpbuf = void;
471 int err;
473 if (!inited)
474 return null;
476 /* may be zs.avail_out+<some constant>
477 * zs.avail_out is set nonzero by deflate in previous compress()
479 //tmpbuf = new void[zs.avail_out];
480 zs.next_out = tmpbuf.ptr;
481 zs.avail_out = tmpbuf.length;
483 while ( (err = deflate(&zs, mode)) != Z_STREAM_END)
485 if (err == Z_OK)
487 if (zs.avail_out != 0 && mode != Z_FINISH)
488 break;
489 else if (zs.avail_out == 0)
491 destbuf ~= tmpbuf;
492 zs.next_out = tmpbuf.ptr;
493 zs.avail_out = tmpbuf.length;
494 continue;
496 err = Z_BUF_ERROR;
498 GC.free(destbuf.ptr);
499 error(err);
501 destbuf ~= tmpbuf[0 .. (tmpbuf.length - zs.avail_out)];
503 if (mode == Z_FINISH)
505 err = deflateEnd(&zs);
506 inited = 0;
507 if (err)
508 error(err);
510 return destbuf;
514 /******
515 * Used when the data to be decompressed is not all in one buffer.
518 class UnCompress
520 import std.conv : to;
522 private:
523 z_stream zs;
524 int inited;
525 int done;
526 size_t destbufsize;
528 HeaderFormat format;
530 void error(int err)
532 if (inited)
533 { inflateEnd(&zs);
534 inited = 0;
536 throw new ZlibException(err);
539 public:
542 * Construct. destbufsize is the same as for D.zlib.uncompress().
544 this(uint destbufsize)
546 this.destbufsize = destbufsize;
549 /** ditto */
550 this(HeaderFormat format = HeaderFormat.determineFromData)
552 this.format = format;
555 ~this()
556 { int err;
558 if (inited)
560 inited = 0;
561 inflateEnd(&zs);
563 done = 1;
567 * Decompress the data in buf and return the decompressed data.
568 * The buffers returned from successive calls to this should be concatenated
569 * together.
571 const(void)[] uncompress(const(void)[] buf)
574 assert(!done);
576 body
578 import core.memory : GC;
579 int err;
580 ubyte[] destbuf;
582 if (buf.length == 0)
583 return null;
585 if (!inited)
587 int windowBits = 15;
588 if (format == HeaderFormat.gzip)
589 windowBits += 16;
590 else if (format == HeaderFormat.determineFromData)
591 windowBits += 32;
593 err = inflateInit2(&zs, windowBits);
594 if (err)
595 error(err);
596 inited = 1;
599 if (!destbufsize)
600 destbufsize = to!uint(buf.length) * 2;
601 destbuf = new ubyte[zs.avail_in * 2 + destbufsize];
602 zs.next_out = destbuf.ptr;
603 zs.avail_out = to!uint(destbuf.length);
605 if (zs.avail_in)
606 buf = zs.next_in[0 .. zs.avail_in] ~ cast(ubyte[]) buf;
608 zs.next_in = cast(ubyte*) buf.ptr;
609 zs.avail_in = to!uint(buf.length);
611 err = inflate(&zs, Z_NO_FLUSH);
612 if (err != Z_STREAM_END && err != Z_OK)
614 GC.free(destbuf.ptr);
615 error(err);
617 destbuf.length = destbuf.length - zs.avail_out;
618 return destbuf;
622 * Decompress and return any remaining data.
623 * The returned data should be appended to that returned by uncompress().
624 * The UnCompress object cannot be used further.
626 void[] flush()
629 assert(!done);
633 assert(done);
635 body
637 import core.memory : GC;
638 ubyte[] extra;
639 ubyte[] destbuf;
640 int err;
642 done = 1;
643 if (!inited)
644 return null;
647 destbuf = new ubyte[zs.avail_in * 2 + 100];
648 zs.next_out = destbuf.ptr;
649 zs.avail_out = to!uint(destbuf.length);
651 err = etc.c.zlib.inflate(&zs, Z_NO_FLUSH);
652 if (err == Z_OK && zs.avail_out == 0)
654 extra ~= destbuf;
655 goto L1;
657 if (err != Z_STREAM_END)
659 GC.free(destbuf.ptr);
660 if (err == Z_OK)
661 err = Z_BUF_ERROR;
662 error(err);
664 destbuf = destbuf.ptr[0 .. zs.next_out - destbuf.ptr];
665 err = etc.c.zlib.inflateEnd(&zs);
666 inited = 0;
667 if (err)
668 error(err);
669 if (extra.length)
670 destbuf = extra ~ destbuf;
671 return destbuf;
675 /* ========================== unittest ========================= */
677 import std.random;
678 import std.stdio;
680 @system unittest // by Dave
682 debug(zlib) writeln("std.zlib.unittest");
684 bool CompressThenUncompress (void[] src)
686 ubyte[] dst = std.zlib.compress(src);
687 double ratio = (dst.length / cast(double) src.length);
688 debug(zlib) writef("src.length: %1$d, dst: %2$d, Ratio = %3$f", src.length, dst.length, ratio);
689 ubyte[] uncompressedBuf;
690 uncompressedBuf = cast(ubyte[]) std.zlib.uncompress(dst);
691 assert(src.length == uncompressedBuf.length);
692 assert(src == uncompressedBuf);
694 return true;
698 // smallish buffers
699 for (int idx = 0; idx < 25; idx++)
701 char[] buf = new char[uniform(0, 100)];
703 // Alternate between more & less compressible
704 foreach (ref char c; buf)
705 c = cast(char) (' ' + (uniform(0, idx % 2 ? 91 : 2)));
707 if (CompressThenUncompress(buf))
709 debug(zlib) writeln("; Success.");
711 else
713 return;
717 // larger buffers
718 for (int idx = 0; idx < 25; idx++)
720 char[] buf = new char[uniform(0, 1000/*0000*/)];
722 // Alternate between more & less compressible
723 foreach (ref char c; buf)
724 c = cast(char) (' ' + (uniform(0, idx % 2 ? 91 : 10)));
726 if (CompressThenUncompress(buf))
728 debug(zlib) writefln("; Success.");
730 else
732 return;
736 debug(zlib) writefln("PASSED std.zlib.unittest");
740 @system unittest // by Artem Rebrov
742 Compress cmp = new Compress;
743 UnCompress decmp = new UnCompress;
745 const(void)[] input;
746 input = "tesatdffadf";
748 const(void)[] buf = cmp.compress(input);
749 buf ~= cmp.flush();
750 const(void)[] output = decmp.uncompress(buf);
752 //writefln("input = '%s'", cast(char[]) input);
753 //writefln("output = '%s'", cast(char[]) output);
754 assert( output[] == input[] );
757 @system unittest
759 static assert(__traits(compiles, etc.c.zlib.gzclose(null))); // bugzilla 15457