2010-06-17 Zoltan Varga <vargaz@gmail.com>
[mono.git] / support / zlib-helper.c
blob66b58663a5eb6beff5f7b34638bc2a01fbd65d3c
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_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 TRUE
21 #define FALSE 0
22 #define TRUE 1
23 #endif
25 #define BUFFER_SIZE 4096
26 #define ARGUMENT_ERROR -10
27 #define IO_ERROR -11
29 typedef gint (*read_write_func) (guchar *buffer, gint length, void *gchandle);
30 struct _ZStream {
31 z_stream *stream;
32 guchar *buffer;
33 read_write_func func;
34 void *gchandle;
35 guchar compress;
36 guchar eof;
38 typedef struct _ZStream ZStream;
40 ZStream *CreateZStream (gint compress, guchar gzip, read_write_func func, void *gchandle);
41 gint CloseZStream (ZStream *zstream);
42 gint Flush (ZStream *stream);
43 gint ReadZStream (ZStream *stream, guchar *buffer, gint length);
44 gint WriteZStream (ZStream *stream, guchar *buffer, gint length);
46 static void *
47 z_alloc (void *opaque, gsize nitems, gsize item_size)
49 return g_malloc0 (nitems * item_size);
52 static void
53 z_free (void *opaque, void *ptr)
55 g_free (ptr);
58 ZStream *
59 CreateZStream (gint compress, guchar gzip, read_write_func func, void *gchandle)
61 z_stream *z;
62 gint retval;
63 ZStream *result;
65 if (func == NULL)
66 return NULL;
68 #if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1204)
69 /* Older versions of zlib do not support raw deflate or gzip */
70 return NULL;
71 #endif
73 z = g_new0 (z_stream, 1);
74 if (compress) {
75 retval = deflateInit2 (z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, gzip ? 31 : -15, 8, Z_DEFAULT_STRATEGY);
76 } else {
77 retval = inflateInit2 (z, gzip ? 31 : -15);
80 if (retval != Z_OK) {
81 g_free (z);
82 return NULL;
84 z->zalloc = z_alloc;
85 z->zfree = z_free;
86 result = g_new0 (ZStream, 1);
87 result->stream = z;
88 result->func = func;
89 result->gchandle = gchandle;
90 result->compress = compress;
91 result->buffer = g_new (guchar, BUFFER_SIZE);
92 return result;
95 gint
96 CloseZStream (ZStream *zstream)
98 gint status;
99 gint flush_status;
101 if (zstream == NULL)
102 return ARGUMENT_ERROR;
104 status = 0;
105 if (zstream->compress) {
106 if (zstream->stream->total_in > 0) {
107 do {
108 status = deflate (zstream->stream, Z_FINISH);
109 flush_status = Flush (zstream);
110 } while (status == Z_OK); /* We want Z_STREAM_END or error here here */
111 if (status == Z_STREAM_END)
112 status = flush_status;
114 deflateEnd (zstream->stream);
115 } else {
116 inflateEnd (zstream->stream);
118 g_free (zstream->buffer);
119 g_free (zstream->stream);
120 memset (zstream, 0, sizeof (ZStream));
121 g_free (zstream);
122 return status;
125 static gint
126 write_to_managed (ZStream *stream)
128 gint n;
129 z_stream *zs;
131 zs = stream->stream;
132 if (zs->avail_out != BUFFER_SIZE) {
133 n = stream->func (stream->buffer, BUFFER_SIZE - zs->avail_out, stream->gchandle);
134 zs->next_out = stream->buffer;
135 zs->avail_out = BUFFER_SIZE;
136 if (n < 0)
137 return IO_ERROR;
139 return 0;
142 gint
143 Flush (ZStream *stream)
145 if (!stream->compress)
146 return 0;
148 return write_to_managed (stream);
151 gint
152 ReadZStream (ZStream *stream, guchar *buffer, gint length)
154 gint n;
155 gint status;
156 z_stream *zs;
158 if (stream == NULL || buffer == NULL || length < 0)
159 return ARGUMENT_ERROR;
161 if (stream->eof)
162 return 0;
164 zs = stream->stream;
165 zs->next_out = buffer;
166 zs->avail_out = length;
167 while (zs->avail_out > 0) {
168 if (zs->avail_in == 0) {
169 n = stream->func (stream->buffer, BUFFER_SIZE, stream->gchandle);
170 if (n <= 0) {
171 stream->eof = TRUE;
172 break;
174 zs->next_in = stream->buffer;
175 zs->avail_in = n;
178 status = inflate (stream->stream, Z_SYNC_FLUSH);
179 if (status == Z_STREAM_END) {
180 stream->eof = TRUE;
181 break;
182 } else if (status != Z_OK) {
183 return status;
186 return length - zs->avail_out;
189 gint
190 WriteZStream (ZStream *stream, guchar *buffer, gint length)
192 gint n;
193 gint status;
194 z_stream *zs;
196 if (stream == NULL || buffer == NULL || length < 0)
197 return ARGUMENT_ERROR;
199 if (stream->eof)
200 return IO_ERROR;
202 zs = stream->stream;
203 zs->next_in = buffer;
204 zs->avail_in = length;
205 while (zs->avail_in > 0) {
206 if (zs->avail_out == 0) {
207 zs->next_out = stream->buffer;
208 zs->avail_out = BUFFER_SIZE;
210 status = deflate (stream->stream, Z_NO_FLUSH);
211 if (status != Z_OK && status != Z_STREAM_END)
212 return status;
214 if (zs->avail_out == 0) {
215 n = write_to_managed (stream);
216 if (n < 0)
217 return n;
220 return length;