phobos/std/zlib.d
2007-09-10 03:56:33 +00:00

463 lines
7.9 KiB
D

/* zlib.d
* A D interface to the zlib library, www.gzip.org/zlib
*/
module std.zlib;
//debug=zlib; // uncomment to turn on debugging printf's
private import etc.c.zlib;
// Values for 'mode'
enum
{
Z_NO_FLUSH = 0,
Z_SYNC_FLUSH = 2,
Z_FULL_FLUSH = 3,
Z_FINISH = 4,
}
/*************************************
* Errors throw a ZlibException.
*/
class ZlibException : Exception
{
this(int errnum)
{ char[] msg;
switch (errnum)
{
case Z_STREAM_END: msg = "stream end"; break;
case Z_NEED_DICT: msg = "need dict"; break;
case Z_ERRNO: msg = "errno"; break;
case Z_STREAM_ERROR: msg = "stream error"; break;
case Z_DATA_ERROR: msg = "data error"; break;
case Z_MEM_ERROR: msg = "mem error"; break;
case Z_BUF_ERROR: msg = "buf error"; break;
case Z_VERSION_ERROR: msg = "version error"; break;
default: msg = "unknown error"; break;
}
super(msg);
}
}
/**************************************************
*/
uint adler32(uint adler, void[] buf)
{
return etc.c.zlib.adler32(adler, cast(ubyte *)buf, buf.length);
}
unittest
{
static ubyte[] data = [1,2,3,4,5,6,7,8,9,10];
uint adler;
debug(zlib) printf("D.zlib.adler32.unittest\n");
adler = adler32(0u, cast(void[])data);
debug(zlib) printf("adler = %x\n", adler);
assert(adler == 0xdc0037);
}
/*********************************
*/
uint crc32(uint crc, void[] buf)
{
return etc.c.zlib.crc32(crc, cast(ubyte *)buf, buf.length);
}
unittest
{
static ubyte[] data = [1,2,3,4,5,6,7,8,9,10];
uint crc;
debug(zlib) printf("D.zlib.crc32.unittest\n");
crc = crc32(0u, cast(void[])data);
debug(zlib) printf("crc = %x\n", crc);
assert(crc == 0x2520577b);
}
/*********************************************
*/
void[] compress(void[] srcbuf, int level)
in
{
assert(-1 <= level && level <= 9);
}
body
{
int err;
void[] destbuf;
uint destlen;
destlen = srcbuf.length + ((srcbuf.length + 1023) / 1024) + 12;
destbuf = new void[destlen];
err = etc.c.zlib.compress2(cast(ubyte *)destbuf, &destlen, cast(ubyte *)srcbuf, srcbuf.length, level);
if (err)
{ delete destbuf;
throw new ZlibException(err);
}
destbuf.length = destlen;
return destbuf;
}
/*********************************************
*/
void[] compress(void[] buf)
{
return compress(buf, Z_DEFAULT_COMPRESSION);
}
/*********************************************
*/
void[] uncompress(void[] srcbuf)
{
return uncompress(srcbuf, 0, 15);
}
void[] uncompress(void[] srcbuf, uint destlen)
{
return uncompress(srcbuf, destlen, 15);
}
void[] uncompress(void[] srcbuf, uint destlen, int winbits)
{
int err;
void[] destbuf;
if (!destlen)
destlen = srcbuf.length * 2 + 1;
while (1)
{
etc.c.zlib.z_stream zs;
destbuf = new void[destlen];
zs.next_in = cast(ubyte*) srcbuf;
zs.avail_in = srcbuf.length;
zs.next_out = cast(ubyte*)destbuf;
zs.avail_out = destlen;
err = etc.c.zlib.inflateInit2(&zs, winbits);
if (err)
{ delete destbuf;
throw new ZlibException(err);
}
err = etc.c.zlib.inflate(&zs, Z_FINISH);
switch (err)
{
case Z_OK:
etc.c.zlib.inflateEnd(&zs);
destlen = destbuf.length * 2;
continue;
case Z_STREAM_END:
destbuf.length = zs.total_out;
err = etc.c.zlib.inflateEnd(&zs);
if (err != Z_OK)
goto Lerr;
return destbuf;
default:
etc.c.zlib.inflateEnd(&zs);
Lerr:
delete destbuf;
throw new ZlibException(err);
}
}
}
unittest
{
ubyte[] src = cast(ubyte[])
"the quick brown fox jumps over the lazy dog\r
the quick brown fox jumps over the lazy dog\r
";
ubyte[] dst;
ubyte[] result;
//arrayPrint(src);
dst = cast(ubyte[])compress(cast(void[])src);
//arrayPrint(dst);
result = cast(ubyte[])uncompress(cast(void[])dst);
//arrayPrint(result);
assert(result == src);
}
/+
void arrayPrint(ubyte[] array)
{
//printf("array %p,%d\n", (void*)array, array.length);
for (int i = 0; i < array.length; i++)
{
printf("%02x ", array[i]);
if (((i + 1) & 15) == 0)
printf("\n");
}
printf("\n\n");
}
+/
/*********************************************
*/
class Compress
{
private:
z_stream zs;
int level = Z_DEFAULT_COMPRESSION;
int inited;
void error(int err)
{
if (inited)
{ deflateEnd(&zs);
inited = 0;
}
throw new ZlibException(err);
}
public:
this()
{
}
this(int level)
in
{
assert(1 <= level && level <= 9);
}
body
{
this.level = level;
}
~this()
{ int err;
if (inited)
{
inited = 0;
err = deflateEnd(&zs);
if (err)
error(err);
}
}
void[] compress(void[] buf)
{ int err;
void[] destbuf;
if (buf.length == 0)
return null;
if (!inited)
{
err = deflateInit(&zs, level);
if (err)
error(err);
inited = 1;
}
destbuf = new void[zs.avail_in + buf.length];
zs.next_out = cast(ubyte*) destbuf;
zs.avail_out = destbuf.length;
if (zs.avail_in)
buf = cast(void[])zs.next_in[0 .. zs.avail_in] ~ buf;
zs.next_in = cast(ubyte*) buf;
zs.avail_in = buf.length;
err = deflate(&zs, Z_NO_FLUSH);
if (err != Z_STREAM_END && err != Z_OK)
{ delete destbuf;
error(err);
}
destbuf.length = zs.total_out;
return destbuf;
}
void[] flush()
{
return flush(Z_FINISH);
}
void[] flush(int mode)
in
{
assert(mode == Z_FINISH || mode == Z_SYNC_FLUSH || mode == Z_FULL_FLUSH);
}
body
{
void[] destbuf;
int err;
if (!inited)
return null;
destbuf = new void[zs.avail_in];
zs.next_out = cast(ubyte*) destbuf;
zs.avail_out = destbuf.length;
err = deflate(&zs, mode);
if (err != Z_STREAM_END)
{
delete destbuf;
if (err == Z_OK)
err = Z_BUF_ERROR;
error(err);
}
destbuf = cast(void[])((cast(ubyte *)destbuf)[0 .. zs.next_out - cast(ubyte*)destbuf]);
if (mode == Z_FINISH)
{
err = deflateEnd(&zs);
inited = 0;
if (err)
error(err);
}
return destbuf;
}
}
class UnCompress
{
private:
z_stream zs;
int inited;
int done;
uint destbufsize;
void error(int err)
{
if (inited)
{ inflateEnd(&zs);
inited = 0;
}
throw new ZlibException(err);
}
public:
this()
{
}
this(uint destbufsize)
{
this.destbufsize = destbufsize;
}
~this()
{ int err;
if (inited)
{
inited = 0;
err = inflateEnd(&zs);
if (err)
error(err);
}
done = 1;
}
void[] uncompress(void[] buf)
in
{
assert(!done);
}
body
{ int err;
void[] destbuf;
if (buf.length == 0)
return null;
if (!inited)
{
err = inflateInit(&zs);
if (err)
error(err);
inited = 1;
}
if (!destbufsize)
destbufsize = buf.length * 2;
destbuf = new void[zs.avail_in * 2 + destbufsize];
zs.next_out = cast(ubyte*) destbuf;
zs.avail_out = destbuf.length;
if (zs.avail_in)
buf = cast(void[])zs.next_in[0 .. zs.avail_in] ~ buf;
zs.next_in = cast(ubyte*) buf;
zs.avail_in = buf.length;
err = inflate(&zs, Z_NO_FLUSH);
if (err != Z_STREAM_END && err != Z_OK)
{ delete destbuf;
error(err);
}
destbuf.length = zs.total_out;
return destbuf;
}
void[] flush()
in
{
assert(!done);
}
out
{
assert(done);
}
body
{
void[] extra;
void[] destbuf;
int err;
done = 1;
if (!inited)
return null;
L1:
destbuf = new void[zs.avail_in * 2 + 100];
zs.next_out = cast(ubyte*) destbuf;
zs.avail_out = destbuf.length;
err = etc.c.zlib.inflate(&zs, Z_NO_FLUSH);
if (err == Z_OK && zs.avail_out == 0)
{
extra ~= destbuf;
goto L1;
}
if (err != Z_STREAM_END)
{
delete destbuf;
if (err == Z_OK)
err = Z_BUF_ERROR;
error(err);
}
destbuf = cast(void[])((cast(ubyte*)destbuf)[0 .. zs.next_out - cast(ubyte*)destbuf]);
err = etc.c.zlib.inflateEnd(&zs);
inited = 0;
if (err)
error(err);
if (extra.length)
destbuf = extra ~ destbuf;
return destbuf;
}
}