"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libisofs/filters/gzip.c" (30 Jan 2021, 20011 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gzip.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (c) 2009 - 2011 Thomas Schmitt
    3  * 
    4  * This file is part of the libisofs project; you can redistribute it and/or 
    5  * modify it under the terms of the GNU General Public License version 2 
    6  * or later as published by the Free Software Foundation. 
    7  * See COPYING file for details.
    8  *
    9  * It implements a filter facility which can pipe a IsoStream into gzip
   10  * compression resp. uncompression, read its output and forward it as IsoStream
   11  * output to an IsoFile.
   12  * The gzip compression is done via zlib by Jean-loup Gailly and Mark Adler
   13  * who state in <zlib.h>:
   14  * "The data format used by the zlib library is described by RFCs (Request for
   15  *  Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
   16  *  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format)."
   17  *
   18  */
   19 
   20 #ifdef HAVE_CONFIG_H
   21 #include "../config.h"
   22 #endif
   23 
   24 #include "../libisofs.h"
   25 #include "../filter.h"
   26 #include "../fsource.h"
   27 #include "../util.h"
   28 #include "../stream.h"
   29 
   30 #include <sys/types.h>
   31 #include <sys/time.h>
   32 #include <sys/wait.h>
   33 #include <unistd.h>
   34 #include <stdio.h>
   35 #include <errno.h>
   36 #include <string.h>
   37 
   38 #ifdef Libisofs_with_zliB
   39 #include <zlib.h>
   40 #else
   41 /* If zlib is not available then this code is a dummy */
   42 #endif
   43 
   44 
   45 /*
   46  * A filter that encodes or decodes the content of gzip compressed files.
   47  */
   48 
   49 
   50 /* --------------------------- GzipFilterRuntime ------------------------- */
   51 
   52 
   53 /* Individual runtime properties exist only as long as the stream is opened.
   54  */
   55 typedef struct
   56 {
   57 
   58 #ifdef Libisofs_with_zliB
   59 
   60     z_stream strm; /* The zlib processing context */
   61 
   62 #endif
   63 
   64     char *in_buffer;
   65     char *out_buffer;
   66     int in_buffer_size;
   67     int out_buffer_size;
   68     char *rpt; /* out_buffer + read_bytes */
   69 
   70     off_t in_counter;
   71     off_t out_counter;
   72 
   73     int do_flush; /* flush mode for deflate() changes at end of input */
   74 
   75     int error_ret;
   76 
   77 } GzipFilterRuntime;
   78 
   79 #ifdef Libisofs_with_zliB
   80 
   81 static
   82 int gzip_running_destroy(GzipFilterRuntime **running, int flag)
   83 {
   84     GzipFilterRuntime *o= *running;
   85     if (o == NULL)
   86         return 0;
   87     if (o->in_buffer != NULL)
   88         free(o->in_buffer);
   89     if (o->out_buffer != NULL)
   90         free(o->out_buffer);
   91     free((char *) o);
   92     *running = NULL;
   93     return 1;
   94 }
   95 
   96 
   97 static
   98 int gzip_running_new(GzipFilterRuntime **running, int flag)
   99 {
  100     GzipFilterRuntime *o;
  101 
  102     *running = o = calloc(sizeof(GzipFilterRuntime), 1);
  103     if (o == NULL) {
  104         return ISO_OUT_OF_MEM;
  105     }
  106     memset(&(o->strm), 0, sizeof(o->strm));
  107     o->in_buffer = NULL;
  108     o->out_buffer = NULL;
  109     o->in_buffer_size = 0;
  110     o->out_buffer_size = 0;
  111     o->rpt = NULL;
  112     o->in_counter = 0;
  113     o->out_counter = 0;
  114     o->do_flush = Z_NO_FLUSH;
  115     o->error_ret = 1;
  116 
  117     o->in_buffer_size= 2048;
  118     o->out_buffer_size= 2048;
  119     o->in_buffer = calloc(o->in_buffer_size, 1);
  120     o->out_buffer = calloc(o->out_buffer_size, 1);
  121     if (o->in_buffer == NULL || o->out_buffer == NULL)
  122         goto failed;
  123     o->rpt = o->out_buffer;
  124     return 1;
  125 failed:
  126     gzip_running_destroy(running, 0);
  127     return -1;
  128 }
  129 #endif /* Libisofs_with_zliB */
  130 
  131 
  132 /* ---------------------------- GzipFilterStreamData --------------------- */
  133 
  134 
  135 /* Counts the number of active compression filters */
  136 static off_t gzip_ref_count = 0;
  137 
  138 /* Counts the number of active uncompression filters */
  139 static off_t gunzip_ref_count = 0;
  140 
  141 
  142 #ifdef Libisofs_with_zliB
  143 /* Parameter for deflateInit2() , see <zlib.h> */
  144 
  145 /* ??? get this from zisofs.c ziso_compression_level ?
  146  * ??? have an own global parameter API ?
  147  * For now level 6 seems to be a fine compromise between speed and size.
  148  */
  149 static int gzip_compression_level = 6;
  150 
  151 #endif /* Libisofs_with_zliB */
  152 
  153 
  154 /*
  155  * The data payload of an individual Gzip Filter IsoStream
  156  */
  157 /* IMPORTANT: Any change must be reflected by gzip_clone_stream() */
  158 typedef struct
  159 {
  160     IsoStream *orig;
  161 
  162     off_t size; /* -1 means that the size is unknown yet */
  163 
  164     GzipFilterRuntime *running; /* is non-NULL when open */
  165 
  166     ino_t id;
  167 
  168 } GzipFilterStreamData;
  169 
  170 
  171 
  172 #ifdef Libisofs_with_zliB
  173 
  174 /* Each individual GzipFilterStreamData needs a unique id number. */
  175 /* >>> This is very suboptimal:
  176        The counter can rollover.
  177 */
  178 static ino_t gzip_ino_id = 0;
  179 
  180 #endif /* Libisofs_with_zliB */
  181 
  182 
  183 static
  184 int gzip_stream_uncompress(IsoStream *stream, void *buf, size_t desired);
  185 
  186 
  187 /*
  188  * Methods for the IsoStreamIface of a Gzip Filter object.
  189  */
  190 
  191 /*
  192  * @param flag  bit0= original stream is not open
  193  */
  194 static
  195 int gzip_stream_close_flag(IsoStream *stream, int flag)
  196 {
  197 
  198 #ifdef Libisofs_with_zliB
  199 
  200     GzipFilterStreamData *data;
  201 
  202     if (stream == NULL) {
  203         return ISO_NULL_POINTER;
  204     }
  205     data = stream->data;
  206 
  207     if (data->running == NULL) {
  208         return 1;
  209     }
  210     if (stream->class->read == &gzip_stream_uncompress) {
  211         inflateEnd(&(data->running->strm));
  212     } else {
  213         deflateEnd(&(data->running->strm));
  214     }
  215     gzip_running_destroy(&(data->running), 0);
  216 
  217     if (flag & 1)
  218         return 1;
  219     return iso_stream_close(data->orig);
  220 
  221 #else
  222 
  223     return ISO_ZLIB_NOT_ENABLED;
  224 
  225 #endif
  226 
  227 }
  228 
  229 
  230 static
  231 int gzip_stream_close(IsoStream *stream)
  232 {
  233     return gzip_stream_close_flag(stream, 0);
  234 }
  235 
  236 
  237 /*
  238  * @param flag  bit0= do not run .get_size() if size is < 0
  239  */
  240 static
  241 int gzip_stream_open_flag(IsoStream *stream, int flag)
  242 {
  243 
  244 #ifdef Libisofs_with_zliB
  245 
  246     GzipFilterStreamData *data;
  247     GzipFilterRuntime *running = NULL;
  248     int ret;
  249     z_stream *strm;
  250 
  251     if (stream == NULL) {
  252         return ISO_NULL_POINTER;
  253     }
  254     data = (GzipFilterStreamData*) stream->data;
  255     if (data->running != NULL) {
  256         return ISO_FILE_ALREADY_OPENED;
  257     }
  258     if (data->size < 0 && !(flag & 1)) {
  259         /* Do the size determination run now, so that the size gets cached
  260            and .get_size() will not fail on an opened stream.
  261         */
  262         stream->class->get_size(stream);
  263     }
  264 
  265     ret = gzip_running_new(&running,
  266                            stream->class->read == &gzip_stream_uncompress);
  267     if (ret < 0) {
  268         return ret;
  269     }
  270     data->running = running;
  271 
  272     /* Start up zlib compression context */
  273     strm = &(running->strm);
  274     strm->zalloc = Z_NULL;
  275     strm->zfree = Z_NULL;
  276     strm->opaque = Z_NULL;
  277     if (stream->class->read == &gzip_stream_uncompress) {
  278         ret = inflateInit2(strm, 15 | 16);
  279     } else {
  280         ret = deflateInit2(strm, gzip_compression_level, Z_DEFLATED,
  281                            15 | 16, 8, Z_DEFAULT_STRATEGY);
  282     }
  283     if (ret != Z_OK)
  284         return ISO_ZLIB_COMPR_ERR;
  285     strm->next_out = (Bytef *) running->out_buffer;
  286     strm->avail_out = running->out_buffer_size;
  287 
  288     /* Open input stream */
  289     ret = iso_stream_open(data->orig);
  290     if (ret < 0) {
  291         return ret;
  292     }
  293 
  294     return 1;
  295 
  296 #else
  297 
  298     return ISO_ZLIB_NOT_ENABLED;
  299 
  300 #endif
  301 
  302 }
  303 
  304 
  305 static
  306 int gzip_stream_open(IsoStream *stream)
  307 {
  308     return gzip_stream_open_flag(stream, 0);
  309 }
  310 
  311 
  312 /*
  313  * @param flag bit1= uncompress rather than compress
  314  */
  315 static
  316 int gzip_stream_convert(IsoStream *stream, void *buf, size_t desired, int flag)
  317 {
  318 
  319 #ifdef Libisofs_with_zliB
  320 
  321     int ret, todo, cnv_ret, c_bytes;
  322     GzipFilterStreamData *data;
  323     GzipFilterRuntime *rng;
  324     size_t fill = 0;
  325     z_stream *strm;
  326 
  327     if (stream == NULL) {
  328         return ISO_NULL_POINTER;
  329     }
  330     data = stream->data;
  331     rng= data->running;
  332     if (rng == NULL) {
  333         return ISO_FILE_NOT_OPENED;
  334     }
  335     strm = &(rng->strm);
  336     if (rng->error_ret < 0) {
  337         return rng->error_ret;
  338     } else if (rng->error_ret == 0) {
  339         if (rng->out_buffer_size - strm->avail_out
  340             - (rng->rpt - rng->out_buffer) <= 0)
  341             return 0;
  342     }
  343 
  344     while (1) {
  345 
  346         /* Transfer eventual converted bytes from strm to buf */
  347         c_bytes = rng->out_buffer_size - strm->avail_out
  348                   - (rng->rpt - rng->out_buffer);
  349         if (c_bytes > 0) {
  350            todo = desired - fill;
  351            if (todo > c_bytes)
  352                todo = c_bytes;
  353            memcpy(((char *) buf) + fill, rng->rpt, todo);
  354            rng->rpt += todo;
  355            fill += todo;
  356            rng->out_counter += todo;
  357         }
  358 
  359         if (fill >= desired || rng->error_ret == 0)
  360            return fill;
  361 
  362         /* All buffered out data are consumed now */
  363         rng->rpt = rng->out_buffer;
  364         strm->next_out = (Bytef *) rng->out_buffer;
  365         strm->avail_out = rng->out_buffer_size;
  366 
  367         if (strm->avail_in == 0) {
  368             /* All pending input is consumed. Get new input. */
  369             ret = iso_stream_read(data->orig, rng->in_buffer,
  370                                   rng->in_buffer_size);
  371             if (ret < 0)
  372                 return (rng->error_ret = ret);
  373             if (ret == 0) {
  374                 if (flag & 2) {
  375                     /* Early input EOF */
  376                     return (rng->error_ret = ISO_ZLIB_EARLY_EOF);
  377                 } else {
  378                     /* Tell zlib by the next call that it is over */
  379                     rng->do_flush = Z_FINISH;
  380                 }
  381             }
  382             strm->next_in = (Bytef *) rng->in_buffer;
  383             strm->avail_in = ret;
  384             rng->in_counter += ret;
  385         }
  386 
  387         /* Submit input and fetch output until input is consumed */
  388         while (1) {
  389             if (flag & 2) {
  390                 cnv_ret = inflate(strm, rng->do_flush);
  391             } else {
  392                 cnv_ret = deflate(strm, rng->do_flush);
  393             }
  394             if (cnv_ret == Z_STREAM_ERROR || cnv_ret == Z_BUF_ERROR) {
  395                 return (rng->error_ret = ISO_ZLIB_COMPR_ERR);
  396             }
  397             if ((int) strm->avail_out < rng->out_buffer_size)
  398         break; /* output is available */
  399             if (strm->avail_in == 0) /* all pending input consumed */
  400         break;
  401         }
  402         if (cnv_ret == Z_STREAM_END)
  403             rng->error_ret = 0;
  404     }
  405     return fill;
  406 
  407 #else
  408 
  409     return ISO_ZLIB_NOT_ENABLED;
  410 
  411 #endif
  412 
  413 }
  414 
  415 static
  416 int gzip_stream_compress(IsoStream *stream, void *buf, size_t desired)
  417 {
  418     return gzip_stream_convert(stream, buf, desired, 0);
  419 }
  420 
  421 static
  422 int gzip_stream_uncompress(IsoStream *stream, void *buf, size_t desired)
  423 {
  424     return gzip_stream_convert(stream, buf, desired, 2);
  425 }
  426 
  427 
  428 static
  429 off_t gzip_stream_get_size(IsoStream *stream)
  430 {
  431     int ret, ret_close;
  432     off_t count = 0;
  433     GzipFilterStreamData *data;
  434     char buf[64 * 1024];
  435     size_t bufsize = 64 * 1024;
  436 
  437     if (stream == NULL) {
  438         return ISO_NULL_POINTER;
  439     }
  440     data = stream->data;
  441 
  442     if (data->size >= 0) {
  443         return data->size;
  444     }
  445 
  446     /* Run filter command and count output bytes */
  447     ret = gzip_stream_open_flag(stream, 1);
  448     if (ret < 0) {
  449         return ret;
  450     }
  451     while (1) {
  452         ret = stream->class->read(stream, buf, bufsize);
  453         if (ret <= 0)
  454     break;
  455         count += ret;
  456     }
  457     ret_close = gzip_stream_close(stream);
  458     if (ret < 0)
  459         return ret;
  460     if (ret_close < 0)
  461         return ret_close;
  462 
  463     data->size = count;
  464     return count;
  465 }
  466 
  467 
  468 static
  469 int gzip_stream_is_repeatable(IsoStream *stream)
  470 {
  471     /* Only repeatable streams are accepted as orig */
  472     return 1;
  473 }
  474 
  475 
  476 static
  477 void gzip_stream_get_id(IsoStream *stream, unsigned int *fs_id, 
  478                         dev_t *dev_id, ino_t *ino_id)
  479 {
  480     GzipFilterStreamData *data;
  481 
  482     data = stream->data;
  483     *fs_id = ISO_FILTER_FS_ID;
  484     *dev_id = ISO_FILTER_GZIP_DEV_ID;
  485     *ino_id = data->id;
  486 }
  487 
  488 
  489 static
  490 void gzip_stream_free(IsoStream *stream)
  491 {
  492     GzipFilterStreamData *data;
  493 
  494     if (stream == NULL) {
  495         return;
  496     }
  497     data = stream->data;
  498     if (data->running != NULL) {
  499         gzip_stream_close(stream);
  500     }
  501     if (stream->class->read == &gzip_stream_uncompress) {
  502         if (--gunzip_ref_count < 0)
  503             gunzip_ref_count = 0;
  504     } else {
  505         if (--gzip_ref_count < 0)
  506             gzip_ref_count = 0;
  507     }
  508     iso_stream_unref(data->orig);
  509     free(data);
  510 }
  511 
  512 
  513 static
  514 int gzip_update_size(IsoStream *stream)
  515 {
  516     /* By principle size is determined only once */
  517     return 1;
  518 }
  519 
  520 
  521 static
  522 IsoStream *gzip_get_input_stream(IsoStream *stream, int flag)
  523 {
  524     GzipFilterStreamData *data;
  525 
  526     if (stream == NULL) {
  527         return NULL;
  528     }
  529     data = stream->data;
  530     return data->orig;
  531 }
  532 
  533 
  534 static
  535 int gzip_clone_stream(IsoStream *old_stream, IsoStream **new_stream, int flag)
  536 {
  537 
  538 #ifdef Libisofs_with_zliB
  539 
  540     int ret;
  541     IsoStream *new_input_stream, *stream;
  542     GzipFilterStreamData *stream_data, *old_stream_data;
  543 
  544     if (flag)
  545         return ISO_STREAM_NO_CLONE; /* unknown option required */
  546 
  547     stream_data = calloc(1, sizeof(GzipFilterStreamData));
  548     if (stream_data == NULL)
  549         return ISO_OUT_OF_MEM;
  550     ret = iso_stream_clone_filter_common(old_stream, &stream,
  551                                          &new_input_stream, 0);
  552     if (ret < 0) {
  553         free((char *) stream_data);
  554         return ret;
  555     }
  556     old_stream_data = (GzipFilterStreamData *) old_stream->data;
  557     stream_data->orig = new_input_stream;
  558     stream_data->size = old_stream_data->size;
  559     stream_data->running = NULL;
  560     stream_data->id = ++gzip_ino_id;
  561     stream->data = stream_data;
  562     *new_stream = stream;
  563     return ISO_SUCCESS;
  564 
  565 #else /* Libisofs_with_zliB */
  566 
  567     return ISO_STREAM_NO_CLONE;
  568 
  569 #endif /* ! Libisofs_with_zliB */
  570 
  571 }
  572 
  573 static
  574 int gzip_cmp_ino(IsoStream *s1, IsoStream *s2);
  575 
  576 static
  577 int gzip_uncompress_cmp_ino(IsoStream *s1, IsoStream *s2);
  578 
  579 
  580 IsoStreamIface gzip_stream_compress_class = {
  581     4,
  582     "gzip",
  583     gzip_stream_open,
  584     gzip_stream_close,
  585     gzip_stream_get_size,
  586     gzip_stream_compress,
  587     gzip_stream_is_repeatable,
  588     gzip_stream_get_id,
  589     gzip_stream_free,
  590     gzip_update_size,
  591     gzip_get_input_stream,
  592     gzip_cmp_ino,
  593     gzip_clone_stream
  594 };
  595 
  596 
  597 IsoStreamIface gzip_stream_uncompress_class = {
  598     4,
  599     "pizg",
  600     gzip_stream_open,
  601     gzip_stream_close,
  602     gzip_stream_get_size,
  603     gzip_stream_uncompress,
  604     gzip_stream_is_repeatable,
  605     gzip_stream_get_id,
  606     gzip_stream_free,
  607     gzip_update_size,
  608     gzip_get_input_stream,
  609     gzip_uncompress_cmp_ino,
  610     gzip_clone_stream
  611 };
  612 
  613  
  614 static
  615 int gzip_cmp_ino(IsoStream *s1, IsoStream *s2)
  616 {
  617     /* This function may rely on being called by iso_stream_cmp_ino()
  618        only with s1, s2 which both point to it as their .cmp_ino() function.
  619        It would be a programming error to let any other than 
  620        gzip_stream_compress_class point to gzip_cmp_ino().
  621        This fallback endangers transitivity of iso_stream_cmp_ino().
  622     */
  623     if (s1->class != s2->class || (s1->class != &gzip_stream_compress_class &&
  624                                    s2->class != &gzip_stream_compress_class))
  625         return iso_stream_cmp_ino(s1, s2, 1);
  626 
  627     /* Both streams apply the same treatment to their input streams */
  628     return iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0),
  629                               iso_stream_get_input_stream(s2, 0), 0);
  630 }   
  631 
  632  
  633 static
  634 int gzip_uncompress_cmp_ino(IsoStream *s1, IsoStream *s2)
  635 {
  636     /* This function may rely on being called by iso_stream_cmp_ino()
  637        only with s1, s2 which both point to it as their .cmp_ino() function.
  638        It would be a programming error to let any other than 
  639        gzip_stream_uncompress_class point to gzip_uncompress_cmp_ino().
  640     */
  641     if (s1->class != s2->class ||
  642         (s1->class != &gzip_stream_uncompress_class &&
  643          s2->class != &gzip_stream_uncompress_class))
  644         return iso_stream_cmp_ino(s1, s2, 1);
  645 
  646     /* Both streams apply the same treatment to their input streams */
  647     return iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0),
  648                               iso_stream_get_input_stream(s2, 0), 0);
  649 }   
  650 
  651 
  652 /* ------------------------------------------------------------------------- */
  653 
  654 
  655 #ifdef Libisofs_with_zliB
  656 
  657 static
  658 void gzip_filter_free(FilterContext *filter)
  659 {
  660     /* no data are allocated */;
  661 }
  662 
  663 /*
  664  * @param flag bit1= Install a decompression filter
  665  */
  666 static
  667 int gzip_filter_get_filter(FilterContext *filter, IsoStream *original, 
  668                            IsoStream **filtered, int flag)
  669 {
  670     IsoStream *str;
  671     GzipFilterStreamData *data;
  672 
  673     if (filter == NULL || original == NULL || filtered == NULL) {
  674         return ISO_NULL_POINTER;
  675     }
  676 
  677     str = calloc(sizeof(IsoStream), 1);
  678     if (str == NULL) {
  679         return ISO_OUT_OF_MEM;
  680     }
  681     data = calloc(sizeof(GzipFilterStreamData), 1);
  682     if (data == NULL) {
  683         free(str);
  684         return ISO_OUT_OF_MEM;
  685     }
  686 
  687     /* These data items are not owned by this filter object */
  688     data->id = ++gzip_ino_id;
  689     data->orig = original;
  690     data->size = -1;
  691     data->running = NULL;
  692 
  693     /* get reference to the source */
  694     iso_stream_ref(data->orig);
  695 
  696     str->refcount = 1;
  697     str->data = data;
  698     if (flag & 2) {
  699         str->class = &gzip_stream_uncompress_class;
  700         gunzip_ref_count++;
  701     } else {
  702         str->class = &gzip_stream_compress_class;
  703         gzip_ref_count++;
  704     }
  705 
  706     *filtered = str;
  707 
  708     return ISO_SUCCESS;
  709 }
  710 
  711 /* To be called by iso_file_add_filter().
  712  * The FilterContext input parameter is not furtherly needed for the 
  713  * emerging IsoStream.
  714  */
  715 static
  716 int gzip_filter_get_compressor(FilterContext *filter, IsoStream *original, 
  717                                IsoStream **filtered)
  718 {
  719     return gzip_filter_get_filter(filter, original, filtered, 0);
  720 }
  721 
  722 static
  723 int gzip_filter_get_uncompressor(FilterContext *filter, IsoStream *original, 
  724                                  IsoStream **filtered)
  725 {
  726     return gzip_filter_get_filter(filter, original, filtered, 2);
  727 }
  728 
  729 
  730 /* Produce a parameter object suitable for iso_file_add_filter().
  731  * It may be disposed by free() after all those calls are made.
  732  *
  733  * This is quite a dummy as it does not carry individual data.
  734  * @param flag bit1= Install a decompression filter
  735  */
  736 static
  737 int gzip_create_context(FilterContext **filter, int flag)
  738 {
  739     FilterContext *f;
  740     
  741     *filter = f = calloc(1, sizeof(FilterContext));
  742     if (f == NULL) {
  743         return ISO_OUT_OF_MEM;
  744     }
  745     f->refcount = 1;
  746     f->version = 0;
  747     f->data = NULL;
  748     f->free = gzip_filter_free;
  749     if (flag & 2)
  750         f->get_filter = gzip_filter_get_uncompressor;
  751     else
  752         f->get_filter = gzip_filter_get_compressor;
  753     return ISO_SUCCESS;
  754 }
  755 
  756 #endif /* Libisofs_with_zliB */
  757 
  758 /*
  759  * @param flag bit0= if_block_reduction rather than if_reduction
  760  *             bit1= Install a decompression filter
  761  *             bit2= only inquire availability of gzip filtering
  762  *             bit3= do not inquire size
  763  */
  764 int gzip_add_filter(IsoFile *file, int flag)
  765 {
  766 
  767 #ifdef Libisofs_with_zliB
  768 
  769     int ret;
  770     FilterContext *f = NULL;
  771     IsoStream *stream;
  772     off_t original_size = 0, filtered_size = 0;
  773 
  774     if (flag & 4)
  775         return 2;
  776 
  777     original_size = iso_file_get_size(file);
  778 
  779     ret = gzip_create_context(&f, flag & 2);
  780     if (ret < 0) {
  781         return ret;
  782     }
  783     ret = iso_file_add_filter(file, f, 0);
  784     free(f);
  785     if (ret < 0) {
  786         return ret;
  787     }
  788     if (flag & 8) /* size will be filled in by caller */
  789         return ISO_SUCCESS;
  790 
  791     /* Run a full filter process getsize so that the size is cached */
  792     stream = iso_file_get_stream(file);
  793     filtered_size = iso_stream_get_size(stream);
  794     if (filtered_size < 0) {
  795         iso_file_remove_filter(file, 0);
  796         return filtered_size;
  797     }
  798     if ((filtered_size >= original_size ||
  799         ((flag & 1) && filtered_size / 2048 >= original_size / 2048))
  800         && !(flag & 2)){
  801         ret = iso_file_remove_filter(file, 0);
  802         if (ret < 0) {
  803             return ret;
  804         }
  805         return 2;
  806     }
  807     return ISO_SUCCESS;
  808 
  809 #else
  810 
  811     return ISO_ZLIB_NOT_ENABLED;
  812 
  813 #endif /* ! Libisofs_with_zliB */
  814 
  815 }
  816 
  817 
  818 /* API function */
  819 int iso_file_add_gzip_filter(IsoFile *file, int flag)
  820 {
  821     return gzip_add_filter(file, flag & ~8);
  822 }
  823 
  824 
  825 /* API function */
  826 int iso_gzip_get_refcounts(off_t *gzip_count, off_t *gunzip_count, int flag)
  827 {
  828     *gzip_count = gzip_ref_count;
  829     *gunzip_count = gunzip_ref_count;
  830     return ISO_SUCCESS;
  831 }
  832