gzip.c

00001 /*
00002  * Copyright (c) 2005-2012 by KoanLogic s.r.l. <http://www.koanlogic.com>
00003  * All rights reserved.
00004  *
00005  * This file is part of KLone, and as such it is subject to the license stated
00006  * in the LICENSE file which you have received as part of this distribution.
00007  *
00008  * $Id: gzip.c,v 1.25 2007/10/26 08:57:59 tho Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <u/libu.h>
00013 #include <klone/codec.h>
00014 #include <klone/cgzip.h>
00015 #include <klone/utils.h>
00016 
00017 #include <zlib.h>
00018 
00019 struct codec_gzip_s
00020 {
00021     codec_t codec;              /* parent structure block           */
00022     int action;                 /* GZIP_COMPRESS or GZIP_UNCOMPRESS */
00023     int err;                    /* last error code                  */
00024     z_stream zstr;              /* zlib internal structure          */
00025     int (*op)(z_streamp, int);  /* inflate or deflate               */
00026     int (*opEnd)(z_streamp);    /* inflateEnd or deflateEnd         */
00027     char dummy;                 /* ZLIB < 1.2 workaround dummy byte */
00028 };
00029 
00030 typedef struct codec_gzip_s codec_gzip_t;
00031 
00032 static ssize_t gzip_flush(codec_t *codec, char *dst, size_t *dcount)
00033 {
00034     codec_gzip_t *iz;
00035 
00036     dbg_return_if (codec == NULL, -1);
00037     dbg_return_if (dst == NULL, -1);
00038     dbg_return_if (dcount == NULL, -1);
00039 
00040     iz = (codec_gzip_t*)codec;
00041     
00042     /* can't set it to NULL even if zlib must not use it (avail_in == 0) */
00043     iz->zstr.next_in = (char*)0xDEADBEEF;
00044     iz->zstr.avail_in = 0;
00045 
00046 #if !defined(ZLIB_VERNUM) || ZLIB_VERNUM < 0x1200
00047     /* zlib < 1.2.0 workaround: push a dummy byte at the end of the 
00048        stream when inflating (see zlib ChangeLog) */
00049     if(iz->action == GZIP_UNCOMPRESS && iz->dummy == 0)
00050     { 
00051         iz->zstr.next_in = &iz->dummy; /* dummy byte */
00052         iz->zstr.avail_in = 1; 
00053         iz->dummy++;
00054     }
00055 #endif
00056 
00057     iz->zstr.next_out = dst;
00058     iz->zstr.avail_out = *dcount;
00059 
00060     /* should be Z_STREAM_END while uncompressing */
00061     if(iz->err != Z_STREAM_END)
00062     {
00063         iz->err = iz->op(&iz->zstr, 
00064             iz->action == GZIP_COMPRESS ? Z_FINISH : Z_NO_FLUSH);
00065         dbg_err_if(iz->err != Z_OK && iz->err != Z_STREAM_END);
00066     } 
00067 
00068     *dcount = *dcount - iz->zstr.avail_out;   /* written */
00069 
00070     return iz->err == Z_STREAM_END && *dcount == 0 ? 
00071         CODEC_FLUSH_COMPLETE : CODEC_FLUSH_CHUNK;
00072 err:
00073     u_dbg("%s", zError(iz->err));
00074     return -1;
00075 }
00076 
00077 static ssize_t gzip_transform(codec_t *codec, char *dst, size_t *dcount, 
00078         const char *src, size_t src_sz)
00079 {
00080     codec_gzip_t *iz;
00081     size_t consumed;
00082  
00083     dbg_return_if (codec == NULL, -1);
00084     dbg_return_if (src == NULL, -1);
00085     dbg_return_if (dst == NULL, -1); 
00086     dbg_return_if (dcount == NULL || *dcount == 0, -1);
00087     dbg_return_if (src_sz == 0, -1);
00088 
00089     iz = (codec_gzip_t*)codec;
00090     
00091     iz->zstr.next_out = dst;
00092     iz->zstr.avail_out = *dcount;
00093 
00094     iz->zstr.next_in = (char*)src;
00095     iz->zstr.avail_in = src_sz;
00096 
00097     iz->err = iz->op(&iz->zstr, Z_NO_FLUSH);
00098     dbg_err_if(iz->err != Z_OK && iz->err != Z_STREAM_END);
00099 
00100     consumed = src_sz - iz->zstr.avail_in;  /* consumed */
00101     *dcount = *dcount - iz->zstr.avail_out; /* written */
00102 
00103     return consumed; /* # of consumed input bytes */
00104 err:
00105     u_dbg("%s", zError(iz->err));
00106     return -1;
00107 }
00108 
00109 static int gzip_free(codec_t *codec)
00110 {
00111     codec_gzip_t *iz;
00112     int err;
00113 
00114     nop_return_if (codec == NULL, 0);
00115     
00116     iz = (codec_gzip_t*)codec;
00117     dbg_err_if((err = iz->opEnd(&iz->zstr)) != Z_OK);
00118     U_FREE(iz);
00119 
00120     return 0;
00121 err:
00122     u_dbg("%s", zError(err));
00123     return ~0;
00124 }
00125 
00142 int codec_gzip_create(int op, codec_t **piz)
00143 {
00144     codec_gzip_t *iz = NULL;
00145 
00146     dbg_return_if (piz == NULL, ~0);
00147 
00148     iz = u_zalloc(sizeof(codec_gzip_t));
00149     dbg_err_if(iz == NULL);
00150 
00151     iz->codec.transform = gzip_transform;
00152     iz->codec.flush = gzip_flush;
00153     iz->codec.free = gzip_free;
00154     iz->action = op; 
00155 
00156     switch(op)
00157     {
00158     case GZIP_COMPRESS:
00159         iz->op = deflate;
00160         iz->opEnd = deflateEnd;
00161         dbg_err_if(deflateInit2(&iz->zstr, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
00162                     -MAX_WBITS, 8, Z_DEFAULT_STRATEGY));
00163         break;
00164     case GZIP_UNCOMPRESS:
00165         iz->op = inflate;
00166         iz->opEnd = inflateEnd;
00167         dbg_err_if(inflateInit2(&iz->zstr, -MAX_WBITS) != Z_OK);
00168         break;
00169     default:
00170         dbg_err_if("bad gzip op");
00171     }
00172 
00173     *piz = (codec_t*)iz;
00174 
00175     return 0;
00176 err:
00177     U_FREE(iz);
00178     return ~0;
00179 }
00180 

←Products
Copyright © 2005-2012 - KoanLogic S.r.l. - All rights reserved