Bump to mono/corefx@e79cf5b
[mono-project.git] / support / zlib-helper.c
blob2dba149ea3ff057a2657b00751f3c4563426ad07
1 /*
2 * Used by System.IO.Compression.DeflateStream
4 * Author:
5 * Gonzalo Paniagua Javier (gonzalo@novell.com)
7 * (c) Copyright 2009 Novell, Inc.
8 */
9 #include <config.h>
10 #if defined (HAVE_SYS_ZLIB)
11 #include <zlib.h>
12 #else
13 #include "zlib.h"
14 #endif
16 #include <glib.h>
17 #include <string.h>
18 #include <stdlib.h>
20 #ifndef MONO_API
21 #define MONO_API
22 #endif
24 #ifndef TRUE
25 #define FALSE 0
26 #define TRUE 1
27 #endif
29 #define BUFFER_SIZE 4096
30 #define ARGUMENT_ERROR -10
31 #define IO_ERROR -11
32 #define MONO_EXCEPTION -12
34 #define z_new0(type) ((type *) calloc (sizeof (type), 1))
36 typedef gint (*read_write_func) (guchar *buffer, gint length, void *gchandle);
37 struct _ZStream {
38 z_stream *stream;
39 guchar *buffer;
40 read_write_func func;
41 void *gchandle;
42 guchar compress;
43 guchar eof;
44 guint32 total_in;
46 typedef struct _ZStream ZStream;
48 // FIXME? Names should start "mono"?
49 MONO_API ZStream *CreateZStream (gint compress, guchar gzip, read_write_func func, void *gchandle);
50 MONO_API gint CloseZStream (ZStream *zstream);
51 MONO_API gint Flush (ZStream *stream);
52 MONO_API gint ReadZStream (ZStream *stream, guchar *buffer, gint length);
53 MONO_API gint WriteZStream (ZStream *stream, guchar *buffer, gint length);
54 static gint flush_internal (ZStream *stream, gboolean is_final);
56 static void *
57 z_alloc (void *opaque, unsigned int nitems, unsigned int item_size)
59 return calloc (nitems, item_size);
62 static void
63 z_free (void *opaque, void *ptr)
65 free (ptr);
68 ZStream *
69 CreateZStream (gint compress, guchar gzip, read_write_func func, void *gchandle)
71 z_stream *z;
72 gint retval;
73 ZStream *result;
75 if (func == NULL)
76 return NULL;
78 z = z_new0 (z_stream);
79 if (compress) {
80 retval = deflateInit2 (z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, gzip ? 31 : -15, 8, Z_DEFAULT_STRATEGY);
81 } else {
82 retval = inflateInit2 (z, gzip ? 31 : -15);
85 if (retval != Z_OK) {
86 free (z);
87 return NULL;
89 z->zalloc = z_alloc;
90 z->zfree = z_free;
91 result = z_new0 (ZStream);
92 result->stream = z;
93 result->func = func;
94 result->gchandle = gchandle;
95 result->compress = compress;
96 result->buffer = (guchar*)malloc (BUFFER_SIZE);
97 result->stream->next_out = result->buffer;
98 result->stream->avail_out = BUFFER_SIZE;
99 result->stream->total_in = 0;
100 return result;
103 gint
104 CloseZStream (ZStream *zstream)
106 gint status;
107 gint flush_status;
109 if (zstream == NULL)
110 return ARGUMENT_ERROR;
112 status = 0;
113 if (zstream->compress) {
114 if (zstream->stream->total_in > 0) {
115 do {
116 status = deflate (zstream->stream, Z_FINISH);
117 flush_status = flush_internal (zstream, TRUE);
118 if (flush_status == MONO_EXCEPTION) {
119 status = flush_status;
120 break;
122 } while (status == Z_OK); /* We want Z_STREAM_END or error here here */
123 if (status == Z_STREAM_END)
124 status = flush_status;
126 deflateEnd (zstream->stream);
127 } else {
128 inflateEnd (zstream->stream);
130 free (zstream->buffer);
131 free (zstream->stream);
132 memset (zstream, 0, sizeof (ZStream));
133 free (zstream);
134 return status;
137 static gint
138 write_to_managed (ZStream *stream)
140 gint n;
141 z_stream *zs;
143 zs = stream->stream;
144 if (zs->avail_out != BUFFER_SIZE) {
145 n = stream->func (stream->buffer, BUFFER_SIZE - zs->avail_out, stream->gchandle);
146 zs->next_out = stream->buffer;
147 zs->avail_out = BUFFER_SIZE;
148 if (n == MONO_EXCEPTION)
149 return n;
150 if (n < 0)
151 return IO_ERROR;
153 return 0;
156 static gint
157 flush_internal (ZStream *stream, gboolean is_final)
159 gint status;
161 if (!stream->compress)
162 return 0;
164 if (!is_final && stream->stream->avail_in != 0) {
165 status = deflate (stream->stream, Z_PARTIAL_FLUSH);
166 if (status != Z_OK && status != Z_STREAM_END)
167 return status;
169 return write_to_managed (stream);
172 gint
173 Flush (ZStream *stream)
175 return flush_internal (stream, FALSE);
178 gint
179 ReadZStream (ZStream *stream, guchar *buffer, gint length)
181 gint n;
182 gint status;
183 z_stream *zs;
185 if (stream == NULL || buffer == NULL || length < 0)
186 return ARGUMENT_ERROR;
188 if (stream->eof)
189 return 0;
191 zs = stream->stream;
192 zs->next_out = buffer;
193 zs->avail_out = length;
194 while (zs->avail_out > 0) {
195 if (zs->avail_in == 0) {
196 n = stream->func (stream->buffer, BUFFER_SIZE, stream->gchandle);
197 n = n < 0 ? 0 : n;
198 stream->total_in += n;
199 zs->next_in = stream->buffer;
200 zs->avail_in = n;
203 if (zs->avail_in == 0 && zs->total_in == 0)
204 return 0;
206 status = inflate (stream->stream, Z_SYNC_FLUSH);
207 if (status == Z_STREAM_END) {
208 stream->eof = TRUE;
209 break;
210 } else if (status == Z_BUF_ERROR && stream->total_in == zs->total_in) {
211 if (zs->avail_in != 0) {
212 stream->eof = TRUE;
214 break;
215 } else if (status != Z_OK) {
216 return status;
219 return length - zs->avail_out;
222 gint
223 WriteZStream (ZStream *stream, guchar *buffer, gint length)
225 gint n;
226 gint status;
227 z_stream *zs;
229 if (stream == NULL || buffer == NULL || length < 0)
230 return ARGUMENT_ERROR;
232 if (stream->eof)
233 return IO_ERROR;
235 zs = stream->stream;
236 zs->next_in = buffer;
237 zs->avail_in = length;
238 while (zs->avail_in > 0) {
239 if (zs->avail_out == 0) {
240 zs->next_out = stream->buffer;
241 zs->avail_out = BUFFER_SIZE;
243 status = deflate (stream->stream, Z_NO_FLUSH);
244 if (status != Z_OK && status != Z_STREAM_END)
245 return status;
247 if (zs->avail_out == 0) {
248 n = write_to_managed (stream);
249 if (n < 0)
250 return n;
253 return length;