Merge pull request #16429 from vargaz/llvm-jit-module
[mono-project.git] / sdks / wasm / zlib-helper.c
blob39ccbecf03a90668257b6ed7a19fd37103b30261
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 <string.h>
11 #include <mono/metadata/debug-helpers.h>
12 #include <mono/jit/jit.h>
14 #include "zlib.h"
16 #ifndef MONO_API
17 #define MONO_API
18 #endif
20 #ifndef TRUE
21 #define FALSE 0
22 #define TRUE 1
23 #endif
26 * Basic data types
28 typedef int gint;
29 typedef unsigned int guint;
30 typedef short gshort;
31 typedef unsigned short gushort;
32 typedef long glong;
33 typedef unsigned long gulong;
34 typedef void * gpointer;
35 typedef const void * gconstpointer;
36 typedef char gchar;
37 typedef unsigned char guchar;
39 /* Types defined in terms of the stdint.h */
40 typedef int8_t gint8;
41 typedef uint8_t guint8;
42 typedef int16_t gint16;
43 typedef uint16_t guint16;
44 typedef int32_t gint32;
45 typedef uint32_t guint32;
46 typedef int64_t gint64;
47 typedef uint64_t guint64;
48 typedef float gfloat;
49 typedef double gdouble;
50 typedef int32_t gboolean;
52 #define BUFFER_SIZE 4096
53 #define ARGUMENT_ERROR -10
54 #define IO_ERROR -11
55 #define MONO_EXCEPTION -12
57 #define z_malloc(size) ((gpointer) malloc(size))
58 #define z_malloc0(size) ((gpointer) calloc(1,size))
59 #define z_new(type,size) ((type *) z_malloc (sizeof (type) * (size)))
60 #define z_new0(type,size) ((type *) z_malloc0 (sizeof (type)* (size)))
62 typedef gint (*read_write_func) (guchar *buffer, gint length, void *gchandle);
63 struct _ZStream {
64 z_stream *stream;
65 guchar *buffer;
66 read_write_func func;
67 void *gchandle;
68 guchar compress;
69 guchar eof;
70 guint32 total_in;
72 typedef struct _ZStream ZStream;
74 MONO_API ZStream *CreateZStream (gint compress, guchar gzip, read_write_func func, void *gchandle);
75 MONO_API gint CloseZStream (ZStream *zstream);
76 MONO_API gint Flush (ZStream *stream);
77 MONO_API gint ReadZStream (ZStream *stream, guchar *buffer, gint length);
78 MONO_API gint WriteZStream (ZStream *stream, guchar *buffer, gint length);
79 static gint flush_internal (ZStream *stream, gboolean is_final);
80 MonoMethod* GetReadOrWriteCallback (gint compress, void *gchandle);
82 static void *
83 z_alloc (void *opaque, unsigned int nitems, unsigned int item_size)
85 return z_malloc0 (nitems * item_size);
88 static void
89 z_free (void *opaque, void *ptr)
91 free (ptr);
94 ZStream *
95 CreateZStream (gint compress, guchar gzip, read_write_func func, void *gchandle)
97 z_stream *z;
98 gint retval;
99 ZStream *result;
101 if (func == NULL)
102 return NULL;
104 #if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1204)
105 /* Older versions of zlib do not support raw deflate or gzip */
106 return NULL;
107 #endif
109 z = z_new0 (z_stream, 1);
110 if (compress) {
111 retval = deflateInit2 (z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, gzip ? 31 : -15, 8, Z_DEFAULT_STRATEGY);
112 } else {
113 retval = inflateInit2 (z, gzip ? 31 : -15);
116 if (retval != Z_OK) {
117 free (z);
118 return NULL;
120 z->zalloc = z_alloc;
121 z->zfree = z_free;
122 result = z_new0 (ZStream, 1);
123 result->stream = z;
124 result->func = func;
125 result->gchandle = gchandle;
126 result->compress = compress;
127 result->buffer = z_new (guchar, BUFFER_SIZE);
128 result->stream->next_out = result->buffer;
129 result->stream->avail_out = BUFFER_SIZE;
130 result->stream->total_in = 0;
131 return result;
134 gint
135 CloseZStream (ZStream *zstream)
137 gint status;
138 gint flush_status;
140 if (zstream == NULL)
141 return ARGUMENT_ERROR;
143 status = 0;
144 if (zstream->compress) {
145 if (zstream->stream->total_in > 0) {
146 do {
147 status = deflate (zstream->stream, Z_FINISH);
148 flush_status = flush_internal (zstream, TRUE);
149 if (flush_status == MONO_EXCEPTION) {
150 status = flush_status;
151 break;
153 } while (status == Z_OK); /* We want Z_STREAM_END or error here here */
154 if (status == Z_STREAM_END)
155 status = flush_status;
157 deflateEnd (zstream->stream);
158 } else {
159 inflateEnd (zstream->stream);
161 free (zstream->buffer);
162 free (zstream->stream);
163 memset (zstream, 0, sizeof (ZStream));
164 free (zstream);
165 return status;
168 static gint
169 write_to_managed (ZStream *stream)
171 gint n;
172 z_stream *zs;
173 MonoObject *result, *exception;
174 MonoMethod *unmanagedWrite = GetReadOrWriteCallback(stream->compress, stream->gchandle);
175 void* args[3];
177 zs = stream->stream;
178 if (zs->avail_out != BUFFER_SIZE) {
180 //n = stream->func (stream->buffer, BUFFER_SIZE - zs->avail_out, stream->gchandle);
181 args[0] = &stream->buffer;
182 int length = BUFFER_SIZE - zs->avail_out;
183 args[1] = &length;
184 args[2] = &stream->gchandle;
185 exception = NULL;
187 result = mono_runtime_invoke(unmanagedWrite, NULL, args, &exception);
188 if (exception) {
189 MonoClass* eklass = mono_object_get_class((MonoObject*)exception);
190 MonoProperty* prop = mono_class_get_property_from_name(eklass, "Message");
191 MonoString *message = (MonoString*)mono_property_get_value(prop, exception, NULL, NULL);
192 char *p = mono_string_to_utf8 (message);
193 fprintf(stderr,"An exception was thrown in zlib-helper.c UnmanageWrite (IntPtr, int, IntPtr) - %s\n", p);
194 mono_free (p);
195 return MONO_EXCEPTION;
198 n = *(int*)mono_object_unbox (result);
199 zs->next_out = stream->buffer;
200 zs->avail_out = BUFFER_SIZE;
201 if (n == MONO_EXCEPTION)
202 return n;
203 if (n < 0)
204 return IO_ERROR;
206 return 0;
209 static gint
210 flush_internal (ZStream *stream, gboolean is_final)
212 gint status;
214 if (!stream->compress)
215 return 0;
217 if (!is_final && stream->stream->avail_in != 0) {
218 status = deflate (stream->stream, Z_PARTIAL_FLUSH);
219 if (status != Z_OK && status != Z_STREAM_END)
220 return status;
222 return write_to_managed (stream);
225 gint
226 Flush (ZStream *stream)
228 return flush_internal (stream, FALSE);
231 gint
232 ReadZStream (ZStream *stream, guchar *buffer, gint length)
234 gint n;
235 gint status;
236 z_stream *zs;
237 MonoObject *result, *exception;
238 MonoMethod *unmanagedRead = GetReadOrWriteCallback(stream->compress, stream->gchandle);
239 void* args[3];
241 if (stream == NULL || buffer == NULL || length < 0)
242 return ARGUMENT_ERROR;
244 if (stream->eof)
245 return 0;
247 zs = stream->stream;
248 zs->next_out = buffer;
249 zs->avail_out = length;
250 while (zs->avail_out > 0) {
251 if (zs->avail_in == 0) {
252 //n = stream->func (stream->buffer, BUFFER_SIZE, stream->gchandle);
253 args[0] = &stream->buffer;
254 int bufferLength = BUFFER_SIZE;
255 args[1] = &bufferLength;
256 args[2] = &stream->gchandle;
257 exception = NULL;
259 result = mono_runtime_invoke(unmanagedRead, NULL, args, &exception);
260 if (exception) {
261 MonoClass* eklass = mono_object_get_class((MonoObject*)exception);
262 MonoProperty* prop = mono_class_get_property_from_name(eklass, "Message");
263 MonoString *message = (MonoString*)mono_property_get_value(prop, exception, NULL, NULL);
264 char *p = mono_string_to_utf8 (message);
265 fprintf(stderr,"An exception was thrown in zlib-helper.c UnmanageRead (IntPtr, int, IntPtr) - %s\n", p);
266 mono_free (p);
267 return MONO_EXCEPTION;
269 n = *(int*)mono_object_unbox (result);
270 n = n < 0 ? 0 : n;
271 stream->total_in += n;
272 zs->next_in = stream->buffer;
273 zs->avail_in = n;
276 if (zs->avail_in == 0 && zs->total_in == 0)
277 return 0;
279 status = inflate (stream->stream, Z_SYNC_FLUSH);
280 if (status == Z_STREAM_END) {
281 stream->eof = TRUE;
282 break;
283 } else if (status == Z_BUF_ERROR && stream->total_in == zs->total_in) {
284 if (zs->avail_in != 0) {
285 stream->eof = TRUE;
287 break;
288 } else if (status != Z_OK) {
289 return status;
292 return length - zs->avail_out;
295 gint
296 WriteZStream (ZStream *stream, guchar *buffer, gint length)
298 gint n;
299 gint status;
300 z_stream *zs;
302 if (stream == NULL || buffer == NULL || length < 0)
303 return ARGUMENT_ERROR;
305 if (stream->eof)
306 return IO_ERROR;
308 zs = stream->stream;
309 zs->next_in = buffer;
310 zs->avail_in = length;
311 while (zs->avail_in > 0) {
312 if (zs->avail_out == 0) {
313 zs->next_out = stream->buffer;
314 zs->avail_out = BUFFER_SIZE;
316 status = deflate (stream->stream, Z_NO_FLUSH);
317 if (status != Z_OK && status != Z_STREAM_END)
318 return status;
320 if (zs->avail_out == 0) {
321 n = write_to_managed (stream);
322 if (n < 0)
323 return n;
326 return length;
329 MonoMethod*
330 GetReadOrWriteCallback (gint compress, void *gchandle)
332 MonoObject* callback = mono_gchandle_get_target ((guint32)gchandle);
333 if (!callback) {
334 fprintf(stderr, "Error: zlib-helper - Callback target not found.\n");
335 return NULL;
338 MonoClass* klass = mono_object_get_class(callback);
339 if (!klass) {
340 fprintf(stderr, "Error: zlib-helper - Callback class not found.\n");
341 return NULL;
344 MonoMethod* read_write_method = NULL;
345 MonoMethodDesc* desc = NULL;
346 if (compress == 1) { // compress stream
347 desc = mono_method_desc_new(":UnmanagedWrite", FALSE);
348 if (!desc) {
349 fprintf(stderr, "Error: zlib-helper - MethodDesc for UnmanagedWrite not found.\n");
350 return NULL;
352 read_write_method = mono_method_desc_search_in_class (desc, klass);
353 if (!read_write_method) {
354 fprintf(stderr, "Error: zlib-helper - Method UnmanagedWrite not found.\n");
355 return NULL;
358 else {
359 desc = mono_method_desc_new(":UnmanagedRead", FALSE);
360 if (!desc) {
361 fprintf(stderr, "Error: zlib-helper - MethodDesc for UnmanagedRead not found.\n");
362 return NULL;
364 read_write_method = mono_method_desc_search_in_class (desc, klass);
365 if (!read_write_method) {
366 fprintf(stderr, "Error: zlib-helper - Method UnmanagedRead not found.\n");
367 return NULL;
370 mono_method_desc_free (desc);
371 return read_write_method;