2 * Used by System.IO.Compression.DeflateStream
5 * Gonzalo Paniagua Javier (gonzalo@novell.com)
7 * (c) Copyright 2009 Novell, Inc.
10 #if defined (HAVE_ZLIB)
25 #define BUFFER_SIZE 4096
26 #define ARGUMENT_ERROR -10
29 #define z_malloc(size) ((gpointer) malloc(size))
30 #define z_malloc0(size) ((gpointer) calloc(1,size))
31 #define z_new(type,size) ((type *) z_malloc (sizeof (type) * (size)))
32 #define z_new0(type,size) ((type *) z_malloc0 (sizeof (type)* (size)))
34 typedef gint (*read_write_func) (guchar *buffer, gint length, void *gchandle);
44 typedef struct _ZStream ZStream;
46 MONO_API ZStream *CreateZStream (gint compress, guchar gzip, read_write_func func, void *gchandle);
47 MONO_API gint CloseZStream (ZStream *zstream);
48 MONO_API gint Flush (ZStream *stream);
49 MONO_API gint ReadZStream (ZStream *stream, guchar *buffer, gint length);
50 MONO_API gint WriteZStream (ZStream *stream, guchar *buffer, gint length);
51 static gint flush_internal (ZStream *stream, gboolean is_final);
54 z_alloc (void *opaque, unsigned int nitems, unsigned int item_size)
56 return z_malloc0 (nitems * item_size);
60 z_free (void *opaque, void *ptr)
66 CreateZStream (gint compress, guchar gzip, read_write_func func, void *gchandle)
75 #if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1204)
76 /* Older versions of zlib do not support raw deflate or gzip */
80 z = z_new0 (z_stream, 1);
82 retval = deflateInit2 (z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, gzip ? 31 : -15, 8, Z_DEFAULT_STRATEGY);
84 retval = inflateInit2 (z, gzip ? 31 : -15);
93 result = z_new0 (ZStream, 1);
96 result->gchandle = gchandle;
97 result->compress = compress;
98 result->buffer = z_new (guchar, BUFFER_SIZE);
99 result->stream->next_out = result->buffer;
100 result->stream->avail_out = BUFFER_SIZE;
101 result->stream->total_in = 0;
106 CloseZStream (ZStream *zstream)
112 return ARGUMENT_ERROR;
115 if (zstream->compress) {
116 if (zstream->stream->total_in > 0) {
118 status = deflate (zstream->stream, Z_FINISH);
119 flush_status = flush_internal (zstream, TRUE);
120 } while (status == Z_OK); /* We want Z_STREAM_END or error here here */
121 if (status == Z_STREAM_END)
122 status = flush_status;
124 deflateEnd (zstream->stream);
126 inflateEnd (zstream->stream);
128 free (zstream->buffer);
129 free (zstream->stream);
130 memset (zstream, 0, sizeof (ZStream));
136 write_to_managed (ZStream *stream)
142 if (zs->avail_out != BUFFER_SIZE) {
143 n = stream->func (stream->buffer, BUFFER_SIZE - zs->avail_out, stream->gchandle);
144 zs->next_out = stream->buffer;
145 zs->avail_out = BUFFER_SIZE;
153 flush_internal (ZStream *stream, gboolean is_final)
157 if (!stream->compress)
160 if (!is_final && stream->stream->avail_in != 0) {
161 status = deflate (stream->stream, Z_PARTIAL_FLUSH);
162 if (status != Z_OK && status != Z_STREAM_END)
165 return write_to_managed (stream);
169 Flush (ZStream *stream)
171 return flush_internal (stream, FALSE);
175 ReadZStream (ZStream *stream, guchar *buffer, gint length)
181 if (stream == NULL || buffer == NULL || length < 0)
182 return ARGUMENT_ERROR;
188 zs->next_out = buffer;
189 zs->avail_out = length;
190 while (zs->avail_out > 0) {
191 if (zs->avail_in == 0) {
192 n = stream->func (stream->buffer, BUFFER_SIZE, stream->gchandle);
193 stream->total_in += n;
197 zs->next_in = stream->buffer;
198 zs->avail_in = n < 0 ? 0 : n;
201 if (zs->avail_in == 0 && (zs->total_in == 0 || stream->total_in == zs->total_in))
204 status = inflate (stream->stream, Z_SYNC_FLUSH);
205 if (status == Z_STREAM_END) {
208 } else if (status != Z_OK) {
212 return length - zs->avail_out;
216 WriteZStream (ZStream *stream, guchar *buffer, gint length)
222 if (stream == NULL || buffer == NULL || length < 0)
223 return ARGUMENT_ERROR;
229 zs->next_in = buffer;
230 zs->avail_in = length;
231 while (zs->avail_in > 0) {
232 if (zs->avail_out == 0) {
233 zs->next_out = stream->buffer;
234 zs->avail_out = BUFFER_SIZE;
236 status = deflate (stream->stream, Z_NO_FLUSH);
237 if (status != Z_OK && status != Z_STREAM_END)
240 if (zs->avail_out == 0) {
241 n = write_to_managed (stream);