/* $Id: compress.c,v 1.9 1999/06/25 06:15:19 levitte Exp $ */

#include "gnu_extras.h"

#include <lib$routines.h>
#include <starlet.h>
#include "fish.h"
#include "util.h"
#include "compress.h"
#include "fishmsg.h"

static ssh_iob in_iob = { 0, 0 };
static ssh_iob out_iob = { 0, 0 };

void compress_init(ssh_iob *iob, int level)
{
    int err;

    if (iob == 0) {
	iob = &out_iob;
	iob->c_level = level;
    }

    if (iob->zstream == 0)
	iob->zstream = xmalloc(sizeof(z_stream));

    iob->zstream->zalloc = (alloc_func)0;
    iob->zstream->zfree = (free_func)0;
    iob->zstream->opaque = (voidpf)0;

    err = deflateInit(iob->zstream, iob->c_level);
    switch(err) {
    case Z_OK:
	break;
    case Z_MEM_ERROR:
	ssh_F_memfull();
	break;
    case Z_STREAM_ERROR:
	ssh_F_invclev();
	break;
    default:
	ssh_F_comprerr();
	break;
    }
}

void compress_deinit(ssh_iob *iob)
{
    if (iob == 0) {
	iob = &out_iob;
    }

    deflateEnd(iob->zstream);

    xfree(iob->zstream);
}

void decompress_init(ssh_iob *iob)
{
    int err;

    if (iob == 0) {
	iob = &in_iob;
    }

    if (iob->zstream == 0)
	iob->zstream = xmalloc(sizeof(z_stream));

    iob->zstream->zalloc = (alloc_func)0;
    iob->zstream->zfree = (free_func)0;
    iob->zstream->opaque = (voidpf)0;

    err = inflateInit(iob->zstream);
    switch(err) {
    case Z_OK:
	break;
    case Z_MEM_ERROR:
	ssh_F_memfull();
	break;
    default:
	ssh_F_comprerr();
	break;
    }
}

void decompress_deinit(ssh_iob *iob)
{
    if (iob == 0) {
	iob = &in_iob;
    }

    inflateEnd(iob->zstream);

    xfree(iob->zstream);
}

general_buffer *compress_buffer(ssh_iob *iob, void *inbuf, int l)
{
    general_buffer *buf = buf_init(0);
    unsigned char internal_buf[4096];

    if (!buf) {
	ssh_F_memfull();
	return 0;
    }

    if (l == 0)
	return buf;

    if (iob == 0) {
	iob = &out_iob;
    }

    iob->zstream->next_in = inbuf;
    iob->zstream->avail_in = l;

    iob->zstream->next_out = internal_buf;
    iob->zstream->avail_out = sizeof internal_buf;

    do {
	int err; 

	err = deflate(iob->zstream, Z_SYNC_FLUSH);
	switch(err) {
	case Z_OK:
	{
	    if (!buf_append_bytes(buf, internal_buf,
				  sizeof internal_buf
				  - iob->zstream->avail_out)) {
		buf_destroy(buf);
		ssh_F_memfull();
		return 0;
	    }

	    iob->zstream->next_out = internal_buf;
	    iob->zstream->avail_out = sizeof internal_buf;
	}
	    break;
	case Z_MEM_ERROR:
	    buf_destroy(buf);
	    ssh_F_memfull();
	    break;
	default:
	    buf_destroy(buf);
	    ssh_F_comprerr();
	    break;
	}
    } while(iob->zstream->avail_out == 0);

    return buf;
}

general_buffer *decompress_buffer(ssh_iob *iob, void *inbuf, int l)
{
    general_buffer *buf = buf_init(0);
    unsigned char internal_buf[4096];

    if (!buf) {
	ssh_F_memfull();
	return 0;
    }

    if (l == 0)
	return buf;

    if (iob == 0) {
	iob = &in_iob;
    }

    iob->zstream->next_in = inbuf;
    iob->zstream->avail_in = l;

    iob->zstream->next_out = internal_buf;
    iob->zstream->avail_out = sizeof internal_buf;

    do {
	int err; 

	err = inflate(iob->zstream, Z_SYNC_FLUSH);
	switch(err) {
	case Z_OK:
	{
	    if (!buf_append_bytes(buf, internal_buf,
				  sizeof internal_buf
				  - iob->zstream->avail_out)) {
		buf_destroy(buf);
		ssh_F_memfull();
		return 0;
	    }

	    iob->zstream->next_out = internal_buf;
	    iob->zstream->avail_out = sizeof internal_buf;
	}
	    break;
	case Z_BUF_ERROR: /* This is apparently what inflate will return when
			     it's done with the input */
	    return buf;
	case Z_MEM_ERROR:
	    buf_destroy(buf);
	    ssh_F_memfull();
	    break;
	default:
	    buf_destroy(buf);
	    ssh_F_comprerr();
	    break;
	}
    } while(1);

    /* Dummy, to make the compiler stay quiet */
    return buf;
}

/* Emacs local variables

Local variables:
eval: (set-c-style "BSD")
end:

*/
