add spec file for monkeywrench
[mono-project/dkf.git] / support / zlib-helper.c
blob9a692792b1066d9ebfad4226b8c1b1a93f7e9c90
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);
30 struct _ZStream {
31 z_stream *stream;
32 guchar *buffer;
33 read_write_func func;
34 guchar compress;
35 guchar eof;
37 typedef struct _ZStream ZStream;
39 ZStream *CreateZStream (gint compress, guchar gzip, read_write_func func);
40 gint CloseZStream (ZStream *zstream);
41 gint Flush (ZStream *stream);
42 gint ReadZStream (ZStream *stream, guchar *buffer, gint length);
43 gint WriteZStream (ZStream *stream, guchar *buffer, gint length);
45 static void *
46 z_alloc (void *opaque, gsize nitems, gsize item_size)
48 return g_malloc0 (nitems * item_size);
51 static void
52 z_free (void *opaque, void *ptr)
54 g_free (ptr);
57 ZStream *
58 CreateZStream (gint compress, guchar gzip, read_write_func func)
60 z_stream *z;
61 gint retval;
62 ZStream *result;
64 if (func == NULL)
65 return NULL;
67 #if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1204)
68 /* Older versions of zlib do not support raw deflate or gzip */
69 return NULL;
70 #endif
72 z = g_new0 (z_stream, 1);
73 if (compress) {
74 retval = deflateInit2 (z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, gzip ? 31 : -15, 8, Z_DEFAULT_STRATEGY);
75 } else {
76 retval = inflateInit2 (z, gzip ? 31 : -15);
79 if (retval != Z_OK) {
80 g_free (z);
81 return NULL;
83 z->zalloc = z_alloc;
84 z->zfree = z_free;
85 result = g_new0 (ZStream, 1);
86 result->stream = z;
87 result->func = func;
88 result->compress = compress;
89 result->buffer = g_new (guchar, BUFFER_SIZE);
90 return result;
93 gint
94 CloseZStream (ZStream *zstream)
96 gint status;
97 gint flush_status;
99 if (zstream == NULL)
100 return ARGUMENT_ERROR;
102 status = 0;
103 if (zstream->compress) {
104 if (zstream->stream->total_out) {
105 status = deflate (zstream->stream, Z_FINISH);
106 flush_status = Flush (zstream);
107 if (status == Z_OK || status == Z_STREAM_END)
108 status = flush_status;
110 deflateEnd (zstream->stream);
111 } else {
112 inflateEnd (zstream->stream);
114 g_free (zstream->buffer);
115 g_free (zstream->stream);
116 memset (zstream, 0, sizeof (ZStream));
117 g_free (zstream);
118 return status;
121 static gint
122 write_to_managed (ZStream *stream)
124 gint n;
125 z_stream *zs;
127 zs = stream->stream;
128 if (zs->avail_out != BUFFER_SIZE) {
129 n = stream->func (stream->buffer, BUFFER_SIZE - zs->avail_out);
130 zs->next_out = stream->buffer;
131 zs->avail_out = BUFFER_SIZE;
132 if (n < 0)
133 return IO_ERROR;
135 return 0;
138 gint
139 Flush (ZStream *stream)
141 if (!stream->compress)
142 return 0;
144 return write_to_managed (stream);
147 gint
148 ReadZStream (ZStream *stream, guchar *buffer, gint length)
150 gint n;
151 gint status;
152 z_stream *zs;
154 if (stream == NULL || buffer == NULL || length < 0)
155 return ARGUMENT_ERROR;
157 if (stream->eof)
158 return 0;
160 zs = stream->stream;
161 zs->next_out = buffer;
162 zs->avail_out = length;
163 while (zs->avail_out > 0) {
164 if (zs->avail_in == 0) {
165 n = stream->func (stream->buffer, BUFFER_SIZE);
166 if (n <= 0) {
167 stream->eof = TRUE;
168 break;
170 zs->next_in = stream->buffer;
171 zs->avail_in = n;
174 status = inflate (stream->stream, Z_SYNC_FLUSH);
175 if (status != Z_OK && status != Z_STREAM_END)
176 return status;
178 return length - zs->avail_out;
181 gint
182 WriteZStream (ZStream *stream, guchar *buffer, gint length)
184 gint n;
185 gint status;
186 z_stream *zs;
188 if (stream == NULL || buffer == NULL || length < 0)
189 return ARGUMENT_ERROR;
191 if (stream->eof)
192 return IO_ERROR;
194 zs = stream->stream;
195 zs->next_in = buffer;
196 zs->avail_in = length;
197 while (zs->avail_in > 0) {
198 if (zs->avail_out == 0) {
199 zs->next_out = stream->buffer;
200 zs->avail_out = BUFFER_SIZE;
202 status = deflate (stream->stream, Z_SYNC_FLUSH);
203 if (status != Z_OK && status != Z_STREAM_END)
204 return status;
206 if (zs->avail_out == 0) {
207 n = write_to_managed (stream);
208 if (n < 0)
209 return n;
212 return length;