[Wasm] Fix memory override in mono_wasm_add_assembly
[mono-project.git] / support / zlib-helper.c
blobdd5decb455b475ace5e7ee68fe74d20804f2c19a
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 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_malloc(size) ((gpointer) malloc(size))
35 #define z_malloc0(size) ((gpointer) calloc(1,size))
36 #define z_new(type,size) ((type *) z_malloc (sizeof (type) * (size)))
37 #define z_new0(type,size) ((type *) z_malloc0 (sizeof (type)* (size)))
39 typedef gint (*read_write_func) (guchar *buffer, gint length, void *gchandle);
40 struct _ZStream {
41 z_stream *stream;
42 guchar *buffer;
43 read_write_func func;
44 void *gchandle;
45 guchar compress;
46 guchar eof;
47 guint32 total_in;
49 typedef struct _ZStream ZStream;
51 MONO_API ZStream *CreateZStream (gint compress, guchar gzip, read_write_func func, void *gchandle);
52 MONO_API gint CloseZStream (ZStream *zstream);
53 MONO_API gint Flush (ZStream *stream);
54 MONO_API gint ReadZStream (ZStream *stream, guchar *buffer, gint length);
55 MONO_API gint WriteZStream (ZStream *stream, guchar *buffer, gint length);
56 static gint flush_internal (ZStream *stream, gboolean is_final);
58 static void *
59 z_alloc (void *opaque, unsigned int nitems, unsigned int item_size)
61 return z_malloc0 (nitems * item_size);
64 static void
65 z_free (void *opaque, void *ptr)
67 free (ptr);
70 ZStream *
71 CreateZStream (gint compress, guchar gzip, read_write_func func, void *gchandle)
73 z_stream *z;
74 gint retval;
75 ZStream *result;
77 if (func == NULL)
78 return NULL;
80 #if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1204)
81 /* Older versions of zlib do not support raw deflate or gzip */
82 return NULL;
83 #endif
85 z = z_new0 (z_stream, 1);
86 if (compress) {
87 retval = deflateInit2 (z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, gzip ? 31 : -15, 8, Z_DEFAULT_STRATEGY);
88 } else {
89 retval = inflateInit2 (z, gzip ? 31 : -15);
92 if (retval != Z_OK) {
93 free (z);
94 return NULL;
96 z->zalloc = z_alloc;
97 z->zfree = z_free;
98 result = z_new0 (ZStream, 1);
99 result->stream = z;
100 result->func = func;
101 result->gchandle = gchandle;
102 result->compress = compress;
103 result->buffer = z_new (guchar, BUFFER_SIZE);
104 result->stream->next_out = result->buffer;
105 result->stream->avail_out = BUFFER_SIZE;
106 result->stream->total_in = 0;
107 return result;
110 gint
111 CloseZStream (ZStream *zstream)
113 gint status;
114 gint flush_status;
116 if (zstream == NULL)
117 return ARGUMENT_ERROR;
119 status = 0;
120 if (zstream->compress) {
121 if (zstream->stream->total_in > 0) {
122 do {
123 status = deflate (zstream->stream, Z_FINISH);
124 flush_status = flush_internal (zstream, TRUE);
125 if (flush_status == MONO_EXCEPTION) {
126 status = flush_status;
127 break;
129 } while (status == Z_OK); /* We want Z_STREAM_END or error here here */
130 if (status == Z_STREAM_END)
131 status = flush_status;
133 deflateEnd (zstream->stream);
134 } else {
135 inflateEnd (zstream->stream);
137 free (zstream->buffer);
138 free (zstream->stream);
139 memset (zstream, 0, sizeof (ZStream));
140 free (zstream);
141 return status;
144 static gint
145 write_to_managed (ZStream *stream)
147 gint n;
148 z_stream *zs;
150 zs = stream->stream;
151 if (zs->avail_out != BUFFER_SIZE) {
152 n = stream->func (stream->buffer, BUFFER_SIZE - zs->avail_out, stream->gchandle);
153 zs->next_out = stream->buffer;
154 zs->avail_out = BUFFER_SIZE;
155 if (n == MONO_EXCEPTION)
156 return n;
157 if (n < 0)
158 return IO_ERROR;
160 return 0;
163 static gint
164 flush_internal (ZStream *stream, gboolean is_final)
166 gint status;
168 if (!stream->compress)
169 return 0;
171 if (!is_final && stream->stream->avail_in != 0) {
172 status = deflate (stream->stream, Z_PARTIAL_FLUSH);
173 if (status != Z_OK && status != Z_STREAM_END)
174 return status;
176 return write_to_managed (stream);
179 gint
180 Flush (ZStream *stream)
182 return flush_internal (stream, FALSE);
185 gint
186 ReadZStream (ZStream *stream, guchar *buffer, gint length)
188 gint n;
189 gint status;
190 z_stream *zs;
192 if (stream == NULL || buffer == NULL || length < 0)
193 return ARGUMENT_ERROR;
195 if (stream->eof)
196 return 0;
198 zs = stream->stream;
199 zs->next_out = buffer;
200 zs->avail_out = length;
201 while (zs->avail_out > 0) {
202 if (zs->avail_in == 0) {
203 n = stream->func (stream->buffer, BUFFER_SIZE, stream->gchandle);
204 n = n < 0 ? 0 : n;
205 stream->total_in += n;
206 zs->next_in = stream->buffer;
207 zs->avail_in = n;
210 if (zs->avail_in == 0 && zs->total_in == 0)
211 return 0;
213 status = inflate (stream->stream, Z_SYNC_FLUSH);
214 if (status == Z_STREAM_END) {
215 stream->eof = TRUE;
216 break;
217 } else if (status == Z_BUF_ERROR && stream->total_in == zs->total_in) {
218 if (zs->avail_in != 0) {
219 stream->eof = TRUE;
221 break;
222 } else if (status != Z_OK) {
223 return status;
226 return length - zs->avail_out;
229 gint
230 WriteZStream (ZStream *stream, guchar *buffer, gint length)
232 gint n;
233 gint status;
234 z_stream *zs;
236 if (stream == NULL || buffer == NULL || length < 0)
237 return ARGUMENT_ERROR;
239 if (stream->eof)
240 return IO_ERROR;
242 zs = stream->stream;
243 zs->next_in = buffer;
244 zs->avail_in = length;
245 while (zs->avail_in > 0) {
246 if (zs->avail_out == 0) {
247 zs->next_out = stream->buffer;
248 zs->avail_out = BUFFER_SIZE;
250 status = deflate (stream->stream, Z_NO_FLUSH);
251 if (status != Z_OK && status != Z_STREAM_END)
252 return status;
254 if (zs->avail_out == 0) {
255 n = write_to_managed (stream);
256 if (n < 0)
257 return n;
260 return length;