Merge branch 'master' of github.com:/mono/mono
[mono-project/dkf.git] / support / zlib-helper.c
blob6cfeb8c442c50f65645c9c611efb09f6149372fb
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);
45 static gint flush_internal (ZStream *stream, gboolean is_final);
47 static void *
48 z_alloc (void *opaque, gsize nitems, gsize item_size)
50 return g_malloc0 (nitems * item_size);
53 static void
54 z_free (void *opaque, void *ptr)
56 g_free (ptr);
59 ZStream *
60 CreateZStream (gint compress, guchar gzip, read_write_func func, void *gchandle)
62 z_stream *z;
63 gint retval;
64 ZStream *result;
66 if (func == NULL)
67 return NULL;
69 #if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1204)
70 /* Older versions of zlib do not support raw deflate or gzip */
71 return NULL;
72 #endif
74 z = g_new0 (z_stream, 1);
75 if (compress) {
76 retval = deflateInit2 (z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, gzip ? 31 : -15, 8, Z_DEFAULT_STRATEGY);
77 } else {
78 retval = inflateInit2 (z, gzip ? 31 : -15);
81 if (retval != Z_OK) {
82 g_free (z);
83 return NULL;
85 z->zalloc = z_alloc;
86 z->zfree = z_free;
87 result = g_new0 (ZStream, 1);
88 result->stream = z;
89 result->func = func;
90 result->gchandle = gchandle;
91 result->compress = compress;
92 result->buffer = g_new (guchar, BUFFER_SIZE);
93 return result;
96 gint
97 CloseZStream (ZStream *zstream)
99 gint status;
100 gint flush_status;
102 if (zstream == NULL)
103 return ARGUMENT_ERROR;
105 status = 0;
106 if (zstream->compress) {
107 if (zstream->stream->total_in > 0) {
108 do {
109 status = deflate (zstream->stream, Z_FINISH);
110 flush_status = flush_internal (zstream, TRUE);
111 } while (status == Z_OK); /* We want Z_STREAM_END or error here here */
112 if (status == Z_STREAM_END)
113 status = flush_status;
115 deflateEnd (zstream->stream);
116 } else {
117 inflateEnd (zstream->stream);
119 g_free (zstream->buffer);
120 g_free (zstream->stream);
121 memset (zstream, 0, sizeof (ZStream));
122 g_free (zstream);
123 return status;
126 static gint
127 write_to_managed (ZStream *stream)
129 gint n;
130 z_stream *zs;
132 zs = stream->stream;
133 if (zs->avail_out != BUFFER_SIZE) {
134 n = stream->func (stream->buffer, BUFFER_SIZE - zs->avail_out, stream->gchandle);
135 zs->next_out = stream->buffer;
136 zs->avail_out = BUFFER_SIZE;
137 if (n < 0)
138 return IO_ERROR;
140 return 0;
143 static gint
144 flush_internal (ZStream *stream, gboolean is_final)
146 gint status;
148 if (!stream->compress)
149 return 0;
151 if (!is_final) {
152 status = deflate (stream->stream, Z_PARTIAL_FLUSH);
153 if (status != Z_OK && status != Z_STREAM_END)
154 return status;
156 return write_to_managed (stream);
159 gint
160 Flush (ZStream *stream)
162 return flush_internal (stream, FALSE);
165 gint
166 ReadZStream (ZStream *stream, guchar *buffer, gint length)
168 gint n;
169 gint status;
170 z_stream *zs;
172 if (stream == NULL || buffer == NULL || length < 0)
173 return ARGUMENT_ERROR;
175 if (stream->eof)
176 return 0;
178 zs = stream->stream;
179 zs->next_out = buffer;
180 zs->avail_out = length;
181 while (zs->avail_out > 0) {
182 if (zs->avail_in == 0) {
183 n = stream->func (stream->buffer, BUFFER_SIZE, stream->gchandle);
184 if (n <= 0) {
185 stream->eof = TRUE;
186 break;
188 zs->next_in = stream->buffer;
189 zs->avail_in = n;
192 status = inflate (stream->stream, Z_SYNC_FLUSH);
193 if (status == Z_STREAM_END) {
194 stream->eof = TRUE;
195 break;
196 } else if (status != Z_OK) {
197 return status;
200 return length - zs->avail_out;
203 gint
204 WriteZStream (ZStream *stream, guchar *buffer, gint length)
206 gint n;
207 gint status;
208 z_stream *zs;
210 if (stream == NULL || buffer == NULL || length < 0)
211 return ARGUMENT_ERROR;
213 if (stream->eof)
214 return IO_ERROR;
216 zs = stream->stream;
217 zs->next_in = buffer;
218 zs->avail_in = length;
219 while (zs->avail_in > 0) {
220 if (zs->avail_out == 0) {
221 zs->next_out = stream->buffer;
222 zs->avail_out = BUFFER_SIZE;
224 status = deflate (stream->stream, Z_NO_FLUSH);
225 if (status != Z_OK && status != Z_STREAM_END)
226 return status;
228 if (zs->avail_out == 0) {
229 n = write_to_managed (stream);
230 if (n < 0)
231 return n;
234 return length;