source: roaraudio/libroar/vio_zlib.c @ 5438:4eb05969f66c

Last change on this file since 5438:4eb05969f66c was 5388:e5cc8e03a3e1, checked in by phi, 12 years ago

Added support for refcount based VIOs as well as dynamically allocated VIOs (non-stack or global VIOs) (Closes: #127)

File size: 15.9 KB
Line 
1//vio_gzip.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2011-2012
5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "libroar.h"
37
38#ifdef ROAR_HAVE_LIBZ
39
40#include <zlib.h>
41
42struct roar_vio_gzip {
43 struct roar_vio_calls * next;
44 struct roar_buffer * outbuf, * inbuf;
45 int compressor_error, decompressor_error;
46 int compressor_flush;
47 int compressor_used;
48 z_stream compressor, decompressor;
49 gz_header gz_compressorheader, gz_decompressorheader;
50};
51
52static void * _zalloc(voidpf opaque, uInt items, uInt size) {
53 (void)opaque;
54 return roar_mm_calloc(items, size);
55}
56
57static void _zfree(voidpf opaque, voidpf address) {
58 (void)opaque;
59 roar_mm_free(address);
60}
61
62static void _set_error (int error) {
63 int raerror = ROAR_ERROR_UNKNOWN;
64
65 switch (error) {
66  case Z_OK:            raerror = ROAR_ERROR_NONE;       break;
67  case Z_STREAM_END:    raerror = ROAR_ERROR_NODATA;     break;
68  case Z_NEED_DICT:     raerror = ROAR_ERROR_INVAL;      break;
69  case Z_ERRNO:         roar_err_from_errno();           break;
70  case Z_STREAM_ERROR:  raerror = ROAR_ERROR_INVAL;      break;
71  case Z_DATA_ERROR:    raerror = ROAR_ERROR_BADCKSUM;   break;
72  case Z_MEM_ERROR:     raerror = ROAR_ERROR_NOMEM;      break;
73  case Z_BUF_ERROR:     raerror = ROAR_ERROR_FAULT;      break;
74  case Z_VERSION_ERROR: raerror = ROAR_ERROR_BADVERSION; break;
75 }
76
77 ROAR_DBG("_set_error(error=%i): raerror=%s", error, roar_error2str(raerror));
78 roar_err_set(raerror);
79}
80
81static int _init(struct roar_vio_gzip * self, struct roar_vio_calls * dst, int level, int gzip) {
82 int ret;
83
84 ROAR_DBG("_init(self=%p, dst=%p, level=%i, gzip=%i) = ?", self, dst, level, gzip);
85
86 if ( self == NULL ) {
87  roar_err_set(ROAR_ERROR_FAULT);
88  return -1;
89 }
90
91 ROAR_DBG("_init(self=%p, dst=%p, level=%i, gzip=%i) = ?", self, dst, level, gzip);
92
93 if ( level == -1 ) {
94  level = Z_DEFAULT_COMPRESSION;
95 }
96
97 memset(self, 0, sizeof(struct roar_vio_gzip));
98
99 self->next   = dst;
100
101 self->outbuf = NULL;
102 self->inbuf  = NULL;
103
104 self->compressor_error    = ROAR_ERROR_NONE;
105 self->decompressor_error  = ROAR_ERROR_NONE;
106
107 self->compressor_flush    = Z_SYNC_FLUSH;
108 self->compressor_used     = 0;
109
110 self->compressor.zalloc   = _zalloc;
111 self->compressor.zfree    = _zfree;
112 self->compressor.opaque   = NULL;
113 self->compressor.next_in  = NULL;
114 self->compressor.next_out = NULL;
115
116 self->decompressor.zalloc   = _zalloc;
117 self->decompressor.zfree    = _zfree;
118 self->decompressor.opaque   = NULL;
119 self->decompressor.next_in  = NULL;
120 self->decompressor.next_out = NULL;
121
122 ROAR_DBG("_init(self=%p, dst=%p, level=%i, gzip=%i) = ?", self, dst, level, gzip);
123
124 // for the magic numbers: see the zlib.h header file. There are no const for them.
125 if ( (ret = deflateInit2(&(self->compressor), level, Z_DEFLATED, 15 + (gzip ? 16 : 0), 8, Z_DEFAULT_STRATEGY)) != Z_OK ) {
126  _set_error(ret);
127  return -1;
128 }
129
130 ROAR_DBG("_init(self=%p, dst=%p, level=%i, gzip=%i) = ?", self, dst, level, gzip);
131
132 if ( (ret = inflateInit2(&(self->decompressor), 15+32)) != Z_OK ) {
133  deflateEnd(&(self->compressor));
134  _set_error(ret);
135  return -1;
136 }
137
138 ROAR_DBG("_init(self=%p, dst=%p, level=%i, gzip=%i) = ?", self, dst, level, gzip);
139
140 // gzheader is descriped in RFC1952.
141 memset(&(self->gz_compressorheader), 0, sizeof(self->gz_compressorheader));
142 self->gz_compressorheader.os   = 255; // os='unknown'
143 self->gz_compressorheader.hcrc = 0;   // for compatibility
144
145 memset(&(self->gz_decompressorheader), 0, sizeof(self->gz_decompressorheader));
146 self->gz_decompressorheader.os   = 255; // os='unknown'
147 self->gz_decompressorheader.hcrc = 0;   // for compatibility
148
149 if ( gzip ) {
150  if ( (ret = deflateSetHeader(&(self->compressor), &(self->gz_compressorheader))) != Z_OK ) {
151   deflateEnd(&(self->compressor));
152   inflateEnd(&(self->decompressor));
153   _set_error(ret);
154   return -1;
155  }
156 }
157
158 ROAR_DBG("_init(self=%p, dst=%p, level=%i, gzip=%i) = 0", self, dst, level, gzip);
159
160 return 0;
161}
162
163static ssize_t roar_vio_zlib_read    (struct roar_vio_calls * vio, void *buf, size_t count) {
164 struct roar_vio_gzip * self = vio->inst;
165 struct roar_buffer * leftbuf;
166 void * leftbufdata;
167 size_t buflen;
168 ssize_t len;
169 size_t have = 0;
170 int ret;
171 unsigned char inbuf[1024];
172
173 ROAR_DBG("roar_vio_zlib_read(vio=%p, buf=%p, count=%llu) = ?", vio, buf, (long long unsigned)count);
174
175 if ( self->decompressor_error != ROAR_ERROR_NONE ) {
176  roar_err_set(self->decompressor_error);
177  return -1;
178 }
179
180 ROAR_DBG("roar_vio_zlib_read(vio=%p, buf=%p, count=%llu) = ?", vio, buf, (long long unsigned)count);
181
182 while ( self->inbuf != NULL ) {
183  ROAR_DBG("roar_vio_zlib_read(vio=%p, buf=%p, count=%llu): self->inbuf=%p", vio, buf, (long long unsigned)count, self->inbuf);
184  if ( roar_buffer_get_data(self->inbuf, &leftbufdata) == -1 )
185   return -1;
186  if ( roar_buffer_get_len(self->inbuf, &buflen) == -1 )
187   return -1;
188
189  ROAR_DBG("roar_vio_zlib_read(vio=%p, buf=%p, count=%llu) = ?", vio, buf, (long long unsigned)count, self->inbuf);
190
191  self->decompressor.next_out  = buf;
192  self->decompressor.avail_out = count;
193
194  self->decompressor.next_in  = leftbufdata;
195  self->decompressor.avail_in = buflen;
196
197  ROAR_DBG("roar_vio_zlib_read(vio=%p, buf=%p, count=%llu): in: %llu Bytes, out: count Bytes.", vio, buf, (long long unsigned)count, (long long unsigned int)buflen);
198
199  ret = inflate(&(self->decompressor), Z_NO_FLUSH);
200
201  ROAR_DBG("roar_vio_zlib_read(vio=%p, buf=%p, count=%llu): inflate() returned %i", vio, buf, (long long unsigned)count, ret);
202
203  len    = count - self->decompressor.avail_out;
204
205  if ( ret == Z_STREAM_END ) {
206   count = len;
207   ret = Z_OK;
208  }
209
210  if ( ret != Z_OK ) {
211   if ( len == 0 ) {
212    _set_error(ret);
213    return -1;
214   } else {
215    have += len;
216    return have;
217   }
218  }
219
220  buf   += len;
221  have  += len;
222  count -= len;
223
224  if ( len == (ssize_t)buflen ) {
225   ret = roar_buffer_next(&(self->inbuf));
226  } else {
227   ret = roar_buffer_set_offset(self->inbuf, len);
228  }
229
230  if ( ret == -1 ) {
231   roar_err_set((self->decompressor_error = ROAR_ERROR_LOSTSYNC));
232   return -1;
233  }
234
235  if ( count == 0 )
236   return have;
237 }
238
239 ROAR_DBG("roar_vio_zlib_read(vio=%p, buf=%p, count=%llu) = ?", vio, buf, (long long unsigned)count);
240
241 self->decompressor.next_out  = buf;
242 self->decompressor.avail_out = count;
243
244 self->decompressor.next_in  = NULL;
245 self->decompressor.avail_in = 0;
246
247 while (self->decompressor.avail_out > 0) {
248  ROAR_DBG("roar_vio_zlib_read(vio=%p, buf=%p, count=%llu): generating new output...", vio, buf, (long long unsigned)count);
249
250  if ( self->decompressor.avail_in == 0 ) {
251   ROAR_DBG("roar_vio_zlib_read(vio=%p, buf=%p, count=%llu): reading more data", vio, buf, (long long unsigned)count);
252
253   len = roar_vio_read(self->next, inbuf, sizeof(inbuf));
254   if ( len == -1 ) {
255    have += count - self->decompressor.avail_out;
256    if ( have == 0 ) {
257     // error is still set (by roar_vio_read()).
258     return -1;
259    } else {
260     return 0;
261    }
262   } else if ( len == 0 ) {
263    break;
264   }
265
266   ROAR_DBG("roar_vio_zlib_read(vio=%p, buf=%p, count=%llu): len=%llu", vio, buf, (long long unsigned)count, (long long unsigned)len);
267
268   self->decompressor.next_in  = inbuf;
269   self->decompressor.avail_in = len;
270  }
271
272  ret = inflate(&(self->decompressor), Z_NO_FLUSH);
273  ROAR_DBG("roar_vio_zlib_read(vio=%p, buf=%p, count=%llu): inflate() returned %i", vio, buf, (long long unsigned)count, ret);
274
275  if ( ret == Z_STREAM_END )
276   ret = Z_OK;
277
278  if ( ret != Z_OK ) {
279   if ( (count - self->decompressor.avail_out) == 0 ) {
280    _set_error(ret);
281    return -1;
282   } else {
283    break;
284   }
285  }
286
287  ROAR_DBG("roar_vio_zlib_read(vio=%p, buf=%p, count=%llu) = ?", vio, buf, (long long unsigned)count);
288 }
289
290 if ( self->decompressor.avail_in != 0 ) {
291  if ( roar_buffer_new_data(&leftbuf, self->decompressor.avail_in, &leftbufdata) == -1 ) {
292   roar_err_set((self->decompressor_error = ROAR_ERROR_LOSTSYNC));
293   return -1;
294  }
295
296  memcpy(leftbufdata, self->decompressor.next_in, self->decompressor.avail_in);
297
298  if ( self->inbuf == NULL ) {
299   self->inbuf = leftbuf;
300  } else {
301   if ( roar_buffer_moveinto(self->inbuf, &leftbuf) == -1 ) {
302    roar_buffer_free(leftbuf);
303    roar_err_set((self->decompressor_error = ROAR_ERROR_LOSTSYNC));
304    return -1;
305   }
306  }
307 }
308
309 have += count - self->decompressor.avail_out;
310
311 ROAR_DBG("roar_vio_zlib_read(vio=%p, buf=%p, count=%llu) = %llu", vio, buf, (long long unsigned)count, (long long unsigned)have);
312
313 return have;
314}
315
316static ssize_t roar_vio_zlib_write   (struct roar_vio_calls * vio, void *buf, size_t count) {
317 struct roar_vio_gzip * self = vio->inst;
318 struct roar_buffer * leftbuf;
319 void * leftbufdata;
320 size_t outlen;
321 size_t buflen;
322 char outbuf[1024];
323 ssize_t len;
324 int ret;
325
326 ROAR_DBG("roar_vio_zlib_write(vio=%p, buf=%p, count=%llu) = ?", vio, buf, (long long unsigned)count);
327
328 self->compressor_used = 1;
329
330 if ( self->compressor_error != ROAR_ERROR_NONE ) {
331  roar_err_set(self->compressor_error);
332  return -1;
333 }
334
335 ROAR_DBG("roar_vio_zlib_write(vio=%p, buf=%p, count=%llu) = ?", vio, buf, (long long unsigned)count);
336
337 while (self->outbuf != NULL) {
338  if ( roar_buffer_get_data(self->outbuf, &leftbufdata) == -1 )
339   return -1;
340  if ( roar_buffer_get_len(self->outbuf, &buflen) == -1 )
341   return -1;
342
343  len = roar_vio_write(self->next, leftbufdata, buflen);
344  if ( len == -1 ) {
345   return -1;
346  } else if ( len == (ssize_t)buflen ) {
347   if ( roar_buffer_next(&(self->outbuf)) == -1 ) {
348    roar_err_set((self->compressor_error = ROAR_ERROR_LOSTSYNC));
349    return -1;
350   }
351
352   
353  } else {
354   if ( roar_buffer_set_offset(self->outbuf, len) == -1 ) {
355    roar_err_set((self->compressor_error = ROAR_ERROR_LOSTSYNC));
356    return -1;
357   }
358
359   return 0;
360  }
361 }
362
363 ROAR_DBG("roar_vio_zlib_write(vio=%p, buf=%p, count=%llu) = ?", vio, buf, (long long unsigned)count);
364
365 self->compressor.next_in  = buf;
366 self->compressor.avail_in = count;
367
368 while (self->compressor.avail_in || count == 0) {
369  self->compressor.next_out  = (unsigned char *)outbuf;
370  self->compressor.avail_out = sizeof(outbuf);
371  outlen = self->compressor.total_out;
372
373  ret = deflate(&(self->compressor), count == 0 ? self->compressor_flush : Z_NO_FLUSH);
374
375  outlen = self->compressor.total_out - outlen;
376
377  ROAR_DBG("roar_vio_zlib_write(vio=%p, buf=%p, count=%llu): deflate() returned %i", vio, buf, (long long unsigned)count, ret);
378 ROAR_DBG("roar_vio_zlib_write(vio=%p, buf=%p, count=%llu): outlen=%llu", vio, buf, (long long unsigned)count, (long long unsigned int)outlen);
379
380  if ( count != 0 && ret != Z_OK ) {
381   len = count - self->compressor.avail_in;
382   if ( len != 0 ) {
383    return len;
384   } else {
385    _set_error(ret);
386    return -1;
387   }
388  }
389
390  if ( outlen != 0 ) {
391   len = roar_vio_write(self->next, outbuf, outlen);
392
393   if ( len < (ssize_t)outlen ) {
394    if ( roar_buffer_new_data(&leftbuf, outlen - len, &leftbufdata) == -1 ) {
395     roar_err_set((self->compressor_error = ROAR_ERROR_LOSTSYNC));
396     return -1;
397    }
398
399    memcpy(leftbufdata, outbuf+len, outlen - len);
400
401    if ( self->outbuf == NULL ) {
402     self->outbuf = leftbuf;
403    } else {
404     if ( roar_buffer_moveinto(self->outbuf, &leftbuf) == -1 ) {
405      roar_buffer_free(leftbuf);
406      roar_err_set((self->compressor_error = ROAR_ERROR_LOSTSYNC));
407      return -1;
408     }
409    }
410    break;
411   }
412  }
413
414  ROAR_DBG("roar_vio_zlib_write(vio=%p, buf=%p, count=%llu) = ?", vio, buf, (long long unsigned)count);
415
416  if ( count == 0 && (
417         (self->compressor_flush == Z_FINISH && ret == Z_STREAM_END) ||
418         (self->compressor_flush != Z_FINISH && ret == Z_BUF_ERROR)   ) )
419   return 0;
420
421  ROAR_DBG("roar_vio_zlib_write(vio=%p, buf=%p, count=%llu) = ?", vio, buf, (long long unsigned)count);
422 }
423
424 len = count - self->compressor.avail_in;
425
426 ROAR_DBG("roar_vio_zlib_write(vio=%p, buf=%p, count=%llu) = %llu", vio, buf, (long long unsigned)count, (long long unsigned int)len);
427
428 return len;
429}
430
431static roar_off_t   roar_vio_zlib_lseek   (struct roar_vio_calls * vio, roar_off_t offset, int whence) {
432 (void)vio, (void)offset, (void)whence;
433 roar_err_set(ROAR_ERROR_NOSYS);
434 return (roar_off_t)-1;
435}
436
437static int     roar_vio_zlib_sync    (struct roar_vio_calls * vio) {
438 struct roar_vio_gzip * self = vio->inst;
439
440 if ( self->compressor_used )
441  if ( self->compressor_error == ROAR_ERROR_NONE )
442   if ( roar_vio_zlib_write(vio, NULL, 0) == -1 )
443    return -1;
444
445 roar_err_set(ROAR_ERROR_NOSYS);
446 return -1;
447}
448
449static int     roar_vio_zlib_ctl     (struct roar_vio_calls * vio, roar_vio_ctl_t cmd, void * data) {
450 struct roar_vio_gzip * self;
451
452 if ( vio == NULL ) {
453  roar_err_set(ROAR_ERROR_FAULT);
454  return -1;
455 }
456
457 self = vio->inst;
458
459 switch (cmd) {
460  case ROAR_VIO_CTL_GET_NAME:
461    if ( data == NULL )
462     return -1;
463
464    *(char**)data = "zlib";
465    return 0;
466   break;
467  case ROAR_VIO_CTL_GET_NEXT:
468    *(struct roar_vio_calls **)data = self->next;
469    return 0;
470   break;
471  case ROAR_VIO_CTL_GET_FH:
472  case ROAR_VIO_CTL_GET_READ_FH:
473  case ROAR_VIO_CTL_GET_WRITE_FH:
474  case ROAR_VIO_CTL_GET_SELECT_FH:
475  case ROAR_VIO_CTL_GET_SELECT_READ_FH:
476  case ROAR_VIO_CTL_GET_SELECT_WRITE_FH:
477    roar_err_set(ROAR_ERROR_NOTSUP);
478    return -1;
479   break;
480  case ROAR_VIO_CTL_NONBLOCK:
481    return roar_vio_ctl(self->next, cmd, data);
482   break;
483  default:
484    roar_err_set(ROAR_ERROR_BADRQC);
485    return -1;
486 }
487}
488
489static int     roar_vio_zlib_close   (struct roar_vio_calls * vio) {
490 struct roar_vio_gzip * self;
491
492 if ( vio == NULL ) {
493  roar_err_set(ROAR_ERROR_FAULT);
494  return -1;
495 }
496
497 self = vio->inst;
498
499 self->compressor_flush = Z_FINISH;
500
501 roar_vio_zlib_sync(vio);
502
503 deflateEnd(&(self->compressor));
504 inflateEnd(&(self->decompressor));
505
506 if ( self->outbuf != NULL )
507  roar_buffer_free(self->outbuf);
508 if ( self->inbuf != NULL )
509  roar_buffer_free(self->inbuf);
510
511 roar_mm_free(self);
512
513 return 0;
514}
515
516int roar_vio_open_zlib(struct roar_vio_calls * calls, struct roar_vio_calls * dst, int level, int gzip) {
517 struct roar_vio_gzip * self;
518 int err;
519
520 ROAR_DBG("roar_vio_open_zlib(calls=%p, dst=%p, level=%i, gzip=%i) = ?", calls, dst, level, gzip);
521
522 if ( calls == NULL || dst == NULL ) {
523  roar_err_set(ROAR_ERROR_FAULT);
524  return -1;
525 }
526
527 self = roar_mm_malloc(sizeof(struct roar_vio_gzip));
528
529 if ( _init(self, dst, level, gzip) == -1 ) {
530  err = roar_error;
531  roar_mm_free(self);
532  roar_err_set(err);
533  ROAR_DBG("roar_vio_open_zlib(calls=%p, dst=%p, level=%i, gzip=%i) = -1 // error=%s", calls, dst, level, gzip, roar_error2str(err));
534  return -1;
535 }
536
537 ROAR_DBG("roar_vio_open_zlib(calls=%p, dst=%p, level=%i, gzip=%i) = ?", calls, dst, level, gzip);
538
539 memset(calls, 0, sizeof(struct roar_vio_calls));
540 calls->flags      = ROAR_VIO_FLAGS_NONE;
541 calls->refc       = 1;
542
543 calls->inst       = self;
544 calls->read       = roar_vio_zlib_read;
545 calls->write      = roar_vio_zlib_write;
546 calls->lseek      = roar_vio_zlib_lseek;
547 calls->sync       = roar_vio_zlib_sync;
548 calls->ctl        = roar_vio_zlib_ctl;
549 calls->close      = roar_vio_zlib_close;
550
551 ROAR_DBG("roar_vio_open_zlib(calls=%p, dst=%p, level=%i, gzip=%i) = 0", calls, dst, level, gzip);
552
553 return 0;
554}
555
556#endif
557
558//ll
Note: See TracBrowser for help on using the repository browser.