#include "zlib.h"
#endif
+#include <glib.h>
#include <string.h>
#include <stdlib.h>
+#ifndef MONO_API
+#define MONO_API
+#endif
+
#ifndef TRUE
#define FALSE 0
#define TRUE 1
#define ARGUMENT_ERROR -10
#define IO_ERROR -11
-typedef int (*read_write_func) (unsigned char *buffer, int length);
+#define z_malloc(size) ((gpointer) malloc(size))
+#define z_malloc0(size) ((gpointer) calloc(1,size))
+#define z_new(type,size) ((type *) z_malloc (sizeof (type) * (size)))
+#define z_new0(type,size) ((type *) z_malloc0 (sizeof (type)* (size)))
+
+typedef gint (*read_write_func) (guchar *buffer, gint length, void *gchandle);
struct _ZStream {
z_stream *stream;
- unsigned char *buffer;
+ guchar *buffer;
read_write_func func;
- unsigned char compress;
- unsigned char eof;
+ void *gchandle;
+ guchar compress;
+ guchar eof;
+ guint32 total_in;
};
typedef struct _ZStream ZStream;
-ZStream *CreateZStream (int compress, unsigned char gzip, read_write_func func);
-int CloseZStream (ZStream *zstream);
-int Flush (ZStream *stream);
-int ReadZStream (ZStream *stream, unsigned char *buffer, int length);
-int WriteZStream (ZStream *stream, unsigned char *buffer, int length);
+MONO_API ZStream *CreateZStream (gint compress, guchar gzip, read_write_func func, void *gchandle);
+MONO_API gint CloseZStream (ZStream *zstream);
+MONO_API gint Flush (ZStream *stream);
+MONO_API gint ReadZStream (ZStream *stream, guchar *buffer, gint length);
+MONO_API gint WriteZStream (ZStream *stream, guchar *buffer, gint length);
+static gint flush_internal (ZStream *stream, gboolean is_final);
+static void *
+z_alloc (void *opaque, unsigned int nitems, unsigned int item_size)
+{
+ return z_malloc0 (nitems * item_size);
+}
+
+static void
+z_free (void *opaque, void *ptr)
+{
+ free (ptr);
+}
ZStream *
-CreateZStream (int compress, unsigned char gzip, read_write_func func)
+CreateZStream (gint compress, guchar gzip, read_write_func func, void *gchandle)
{
z_stream *z;
- int retval;
+ gint retval;
ZStream *result;
if (func == NULL)
return NULL;
#endif
- z = (z_stream *) malloc (sizeof (z_stream));
- if (z == NULL)
- return NULL;
- memset (z, 0, sizeof (z_stream));
+ z = z_new0 (z_stream, 1);
if (compress) {
retval = deflateInit2 (z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, gzip ? 31 : -15, 8, Z_DEFAULT_STRATEGY);
} else {
free (z);
return NULL;
}
- result = malloc (sizeof (ZStream));
- memset (result, 0, sizeof (ZStream));
+ z->zalloc = z_alloc;
+ z->zfree = z_free;
+ result = z_new0 (ZStream, 1);
result->stream = z;
result->func = func;
+ result->gchandle = gchandle;
result->compress = compress;
- result->buffer = (unsigned char *) malloc (BUFFER_SIZE);
- if (result->buffer == NULL) {
- free (result);
- if (compress) {
- deflateEnd (z);
- } else {
- inflateEnd (z);
- }
- free (z);
- return NULL;
- }
- memset (result->buffer, 0, BUFFER_SIZE);
+ result->buffer = z_new (guchar, BUFFER_SIZE);
+ result->stream->next_out = result->buffer;
+ result->stream->avail_out = BUFFER_SIZE;
+ result->stream->total_in = 0;
return result;
}
-int
+gint
CloseZStream (ZStream *zstream)
{
- int status;
- int flush_status;
+ gint status;
+ gint flush_status;
if (zstream == NULL)
return ARGUMENT_ERROR;
status = 0;
if (zstream->compress) {
- status = deflate (zstream->stream, Z_FINISH);
- flush_status = Flush (zstream);
- if (status == Z_OK || status == Z_STREAM_END)
- status = flush_status;
+ if (zstream->stream->total_in > 0) {
+ do {
+ status = deflate (zstream->stream, Z_FINISH);
+ flush_status = flush_internal (zstream, TRUE);
+ } while (status == Z_OK); /* We want Z_STREAM_END or error here here */
+ if (status == Z_STREAM_END)
+ status = flush_status;
+ }
deflateEnd (zstream->stream);
} else {
inflateEnd (zstream->stream);
return status;
}
-static int
+static gint
write_to_managed (ZStream *stream)
{
- int n;
+ gint n;
z_stream *zs;
zs = stream->stream;
if (zs->avail_out != BUFFER_SIZE) {
- n = stream->func (stream->buffer, BUFFER_SIZE - zs->avail_out);
+ n = stream->func (stream->buffer, BUFFER_SIZE - zs->avail_out, stream->gchandle);
zs->next_out = stream->buffer;
- zs->avail_out = BUFFER_SIZE;
+ zs->avail_out = BUFFER_SIZE;
if (n < 0)
return IO_ERROR;
}
return 0;
}
-int
-Flush (ZStream *stream)
+static gint
+flush_internal (ZStream *stream, gboolean is_final)
{
+ gint status;
+
if (!stream->compress)
return 0;
+ if (!is_final && stream->stream->avail_in != 0) {
+ status = deflate (stream->stream, Z_PARTIAL_FLUSH);
+ if (status != Z_OK && status != Z_STREAM_END)
+ return status;
+ }
return write_to_managed (stream);
}
-int
-ReadZStream (ZStream *stream, unsigned char *buffer, int length)
+gint
+Flush (ZStream *stream)
{
- int n;
- int status;
+ return flush_internal (stream, FALSE);
+}
+
+gint
+ReadZStream (ZStream *stream, guchar *buffer, gint length)
+{
+ gint n;
+ gint status;
z_stream *zs;
if (stream == NULL || buffer == NULL || length < 0)
zs->avail_out = length;
while (zs->avail_out > 0) {
if (zs->avail_in == 0) {
- n = stream->func (stream->buffer, BUFFER_SIZE);
+ n = stream->func (stream->buffer, BUFFER_SIZE, stream->gchandle);
+ stream->total_in += n;
if (n <= 0) {
stream->eof = TRUE;
- break;
}
zs->next_in = stream->buffer;
- zs->avail_in = n;
+ zs->avail_in = n < 0 ? 0 : n;
}
+ if (zs->avail_in == 0 && (zs->total_in == 0 || stream->total_in == zs->total_in))
+ return Z_STREAM_END;
+
status = inflate (stream->stream, Z_SYNC_FLUSH);
- if (status != Z_OK && status != Z_STREAM_END)
+ if (status == Z_STREAM_END) {
+ stream->eof = TRUE;
+ break;
+ } else if (status != Z_OK) {
return status;
+ }
}
return length - zs->avail_out;
}
-int
-WriteZStream (ZStream *stream, unsigned char *buffer, int length)
+gint
+WriteZStream (ZStream *stream, guchar *buffer, gint length)
{
- int n;
- int status;
+ gint n;
+ gint status;
z_stream *zs;
if (stream == NULL || buffer == NULL || length < 0)
zs->next_out = stream->buffer;
zs->avail_out = BUFFER_SIZE;
}
- status = deflate (stream->stream, Z_SYNC_FLUSH);
+ status = deflate (stream->stream, Z_NO_FLUSH);
if (status != Z_OK && status != Z_STREAM_END)
return status;