2 * Used by System.IO.Compression.DeflateStream
5 * Gonzalo Paniagua Javier (gonzalo@novell.com)
7 * (c) Copyright 2009 Novell, Inc.
10 #if defined (HAVE_ZLIB)
29 #define BUFFER_SIZE 4096
30 #define ARGUMENT_ERROR -10
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
);
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
);
59 z_alloc (void *opaque
, unsigned int nitems
, unsigned int item_size
)
61 return z_malloc0 (nitems
* item_size
);
65 z_free (void *opaque
, void *ptr
)
71 CreateZStream (gint compress
, guchar gzip
, read_write_func func
, void *gchandle
)
80 #if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1204)
81 /* Older versions of zlib do not support raw deflate or gzip */
85 z
= z_new0 (z_stream
, 1);
87 retval
= deflateInit2 (z
, Z_DEFAULT_COMPRESSION
, Z_DEFLATED
, gzip
? 31 : -15, 8, Z_DEFAULT_STRATEGY
);
89 retval
= inflateInit2 (z
, gzip
? 31 : -15);
98 result
= z_new0 (ZStream
, 1);
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;
111 CloseZStream (ZStream
*zstream
)
117 return ARGUMENT_ERROR
;
120 if (zstream
->compress
) {
121 if (zstream
->stream
->total_in
> 0) {
123 status
= deflate (zstream
->stream
, Z_FINISH
);
124 flush_status
= flush_internal (zstream
, TRUE
);
125 if (flush_status
== MONO_EXCEPTION
) {
126 status
= flush_status
;
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
);
135 inflateEnd (zstream
->stream
);
137 free (zstream
->buffer
);
138 free (zstream
->stream
);
139 memset (zstream
, 0, sizeof (ZStream
));
145 write_to_managed (ZStream
*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
)
164 flush_internal (ZStream
*stream
, gboolean is_final
)
168 if (!stream
->compress
)
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
)
176 return write_to_managed (stream
);
180 Flush (ZStream
*stream
)
182 return flush_internal (stream
, FALSE
);
186 ReadZStream (ZStream
*stream
, guchar
*buffer
, gint length
)
192 if (stream
== NULL
|| buffer
== NULL
|| length
< 0)
193 return ARGUMENT_ERROR
;
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
);
205 stream
->total_in
+= n
;
206 zs
->next_in
= stream
->buffer
;
210 if (zs
->avail_in
== 0 && zs
->total_in
== 0)
213 status
= inflate (stream
->stream
, Z_SYNC_FLUSH
);
214 if (status
== Z_STREAM_END
) {
217 } else if (status
== Z_BUF_ERROR
&& stream
->total_in
== zs
->total_in
) {
218 if (zs
->avail_in
!= 0) {
222 } else if (status
!= Z_OK
) {
226 return length
- zs
->avail_out
;
230 WriteZStream (ZStream
*stream
, guchar
*buffer
, gint length
)
236 if (stream
== NULL
|| buffer
== NULL
|| length
< 0)
237 return ARGUMENT_ERROR
;
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
)
254 if (zs
->avail_out
== 0) {
255 n
= write_to_managed (stream
);