2 * Used by System.IO.Compression.DeflateStream
5 * Gonzalo Paniagua Javier (gonzalo@novell.com)
7 * (c) Copyright 2009 Novell, Inc.
11 #include <mono/metadata/debug-helpers.h>
12 #include <mono/jit/jit.h>
29 typedef unsigned int guint
;
31 typedef unsigned short gushort
;
33 typedef unsigned long gulong
;
34 typedef void * gpointer
;
35 typedef const void * gconstpointer
;
37 typedef unsigned char guchar
;
39 /* Types defined in terms of the stdint.h */
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
;
49 typedef double gdouble
;
50 typedef int32_t gboolean
;
52 #define BUFFER_SIZE 4096
53 #define ARGUMENT_ERROR -10
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
);
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
);
83 z_alloc (void *opaque
, unsigned int nitems
, unsigned int item_size
)
85 return z_malloc0 (nitems
* item_size
);
89 z_free (void *opaque
, void *ptr
)
95 CreateZStream (gint compress
, guchar gzip
, read_write_func func
, void *gchandle
)
104 #if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1204)
105 /* Older versions of zlib do not support raw deflate or gzip */
109 z
= z_new0 (z_stream
, 1);
111 retval
= deflateInit2 (z
, Z_DEFAULT_COMPRESSION
, Z_DEFLATED
, gzip
? 31 : -15, 8, Z_DEFAULT_STRATEGY
);
113 retval
= inflateInit2 (z
, gzip
? 31 : -15);
116 if (retval
!= Z_OK
) {
122 result
= z_new0 (ZStream
, 1);
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;
135 CloseZStream (ZStream
*zstream
)
141 return ARGUMENT_ERROR
;
144 if (zstream
->compress
) {
145 if (zstream
->stream
->total_in
> 0) {
147 status
= deflate (zstream
->stream
, Z_FINISH
);
148 flush_status
= flush_internal (zstream
, TRUE
);
149 if (flush_status
== MONO_EXCEPTION
) {
150 status
= flush_status
;
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
);
159 inflateEnd (zstream
->stream
);
161 free (zstream
->buffer
);
162 free (zstream
->stream
);
163 memset (zstream
, 0, sizeof (ZStream
));
169 write_to_managed (ZStream
*stream
)
173 MonoObject
*result
, *exception
;
174 MonoMethod
*unmanagedWrite
= GetReadOrWriteCallback(stream
->compress
, stream
->gchandle
);
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
;
184 args
[2] = &stream
->gchandle
;
187 result
= mono_runtime_invoke(unmanagedWrite
, NULL
, args
, &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
);
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
)
210 flush_internal (ZStream
*stream
, gboolean is_final
)
214 if (!stream
->compress
)
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
)
222 return write_to_managed (stream
);
226 Flush (ZStream
*stream
)
228 return flush_internal (stream
, FALSE
);
232 ReadZStream (ZStream
*stream
, guchar
*buffer
, gint length
)
237 MonoObject
*result
, *exception
;
238 MonoMethod
*unmanagedRead
= GetReadOrWriteCallback(stream
->compress
, stream
->gchandle
);
241 if (stream
== NULL
|| buffer
== NULL
|| length
< 0)
242 return ARGUMENT_ERROR
;
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
;
259 result
= mono_runtime_invoke(unmanagedRead
, NULL
, args
, &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
);
267 return MONO_EXCEPTION
;
269 n
= *(int*)mono_object_unbox (result
);
271 stream
->total_in
+= n
;
272 zs
->next_in
= stream
->buffer
;
276 if (zs
->avail_in
== 0 && zs
->total_in
== 0)
279 status
= inflate (stream
->stream
, Z_SYNC_FLUSH
);
280 if (status
== Z_STREAM_END
) {
283 } else if (status
== Z_BUF_ERROR
&& stream
->total_in
== zs
->total_in
) {
284 if (zs
->avail_in
!= 0) {
288 } else if (status
!= Z_OK
) {
292 return length
- zs
->avail_out
;
296 WriteZStream (ZStream
*stream
, guchar
*buffer
, gint length
)
302 if (stream
== NULL
|| buffer
== NULL
|| length
< 0)
303 return ARGUMENT_ERROR
;
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
)
320 if (zs
->avail_out
== 0) {
321 n
= write_to_managed (stream
);
330 GetReadOrWriteCallback (gint compress
, void *gchandle
)
332 MonoObject
* callback
= mono_gchandle_get_target ((guint32
)gchandle
);
334 fprintf(stderr
, "Error: zlib-helper - Callback target not found.\n");
338 MonoClass
* klass
= mono_object_get_class(callback
);
340 fprintf(stderr
, "Error: zlib-helper - Callback class not found.\n");
344 MonoMethod
* read_write_method
= NULL
;
345 MonoMethodDesc
* desc
= NULL
;
346 if (compress
== 1) { // compress stream
347 desc
= mono_method_desc_new(":UnmanagedWrite", FALSE
);
349 fprintf(stderr
, "Error: zlib-helper - MethodDesc for UnmanagedWrite not found.\n");
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");
359 desc
= mono_method_desc_new(":UnmanagedRead", FALSE
);
361 fprintf(stderr
, "Error: zlib-helper - MethodDesc for UnmanagedRead not found.\n");
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");
370 mono_method_desc_free (desc
);
371 return read_write_method
;