Mercurial > projects > dynamin
diff dynamin/lodepng/zlib_codec.d @ 0:aa4efef0f0b1
Initial commit of code.
author | Jordan Miner <jminer7@gmail.com> |
---|---|
date | Mon, 15 Jun 2009 22:10:48 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dynamin/lodepng/zlib_codec.d Mon Jun 15 22:10:48 2009 -0500 @@ -0,0 +1,146 @@ +// Written in the D programming language +// www.digitalmars.com/d/ + +/// wraps zlib +module dynamin.lodepng.zlib_codec; +pragma(lib, "zlib"); + +version (Tango) +{ + import czlib = tango.io.compress.c.zlib; +} +else +{ + import czlib = etc.c.zlib; +} + +import dynamin.lodepng.util; + + +// buffered decompression of zlib streams, avoiding GC provocation where possible +struct DecodeStream +{ + // TODO: should be scope class for releasing zlib resources on scope exit + + // constructor: initialize with target, will be resized as needed + static DecodeStream create(ref ubyte[] dest) + { + DecodeStream result; + result.dest = dest; + + result.zlibStream.next_out = dest.ptr; + result.zlibStream.avail_out = dest.length; + result.zlibStream.avail_out = dest.length; //Z_BINARY + result.zlibStream.data_type = czlib.Z_BINARY; + + return result; + } + + ubyte[] opCall() + { + return dest; + } + + void opCall(in ubyte[] input) + { + zlibStream.next_in = input.ptr; + zlibStream.avail_in = input.length; + + if (!isInit) + { + isInit = true; + msg = czlib.inflateInit(&zlibStream); + if (msg) + { + czlib.inflateEnd(&zlibStream); + throw new Exception("");// TODO: toString(msg)); + } + } + + while(zlibStream.avail_in) + { + msg = czlib.inflate(&zlibStream, czlib.Z_NO_FLUSH); + + if (msg == czlib.Z_STREAM_END) + { + czlib.inflateEnd(&zlibStream); + hasEnded = true; + dest.length = zlibStream.total_out; + return; + } + else if (msg != czlib.Z_OK) + { + czlib.inflateEnd(&zlibStream); + throw new Exception("");// TODO: toString(zlibStream.msg)); + } + else if(zlibStream.avail_out == 0) + { + dest.length = dest.length * 2; + zlibStream.next_out = &dest[dest.length / 2]; + zlibStream.avail_out = dest.length / 2; + } + } + } + + bool isInit = false; + bool hasEnded = false; + + private + { + ubyte[] dest; + int msg = 0; + czlib.z_stream zlibStream; + } +} + +struct Encoder +{ + static Encoder create(ubyte strategy = czlib.Z_RLE, uint clevel = 9) + { + Encoder result; + result.level = clevel; + result.strategy = strategy; + return result; + } + ubyte[] opCall(in ubyte[] source) + { + ubyte[] result; + return this.opCall(source, result); + + } + ubyte[] opCall(in ubyte[] source, ref ubyte[] buffer) + { + if (source.length == 0) + { + buffer.length = 0; + return buffer; + } + + buffer.length = source.length / 4; + czlib.z_stream stream; + stream.next_in = source.ptr; + stream.avail_in = source.length; + stream.next_out = buffer.ptr; + stream.avail_out = buffer.length; + stream.data_type = czlib.Z_BINARY; + + czlib.deflateInit2(&stream, 9, czlib.Z_DEFLATED, 15, level, strategy); + auto msg = czlib.deflate(&stream, czlib.Z_FINISH); + while(msg != czlib.Z_STREAM_END) + { + buffer.length = buffer.length + buffer.length; + stream.next_out = &buffer[buffer.length / 2]; + stream.avail_out = buffer.length / 2; + msg = czlib.deflate(&stream, czlib.Z_FINISH); + } + + assert(msg == czlib.Z_STREAM_END); + buffer.length = stream.total_out; + czlib.deflateEnd(&stream); + + return buffer; + } + + private ubyte strategy = czlib.Z_RLE; + private ubyte level = 9; +}