source: roaraudio/libroar/vio_zlib.c @ 5229:d7e314825b8a

Last change on this file since 5229:d7e314825b8a was 4956:dc85aeaedd54, checked in by phi, 13 years ago

Use zlib for gzip and zlib format (Closes: #29)

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