view 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 source

// 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;
}