"Fossies" - the Fresh Open Source Software Archive

Member "src/Common/libzip/zip_source_compress.c" (10 Oct 2018, 9779 Bytes) of package /windows/misc/VeraCrypt_1.23-Hotfix-2_Source.zip:


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 "zip_source_compress.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2   zip_source_compress.c -- (de)compression routines
    3   Copyright (C) 2017 Dieter Baron and Thomas Klausner
    4 
    5   This file is part of libzip, a library to manipulate ZIP archives.
    6   The authors can be contacted at <libzip@nih.at>
    7 
    8   Redistribution and use in source and binary forms, with or without
    9   modification, are permitted provided that the following conditions
   10   are met:
   11   1. Redistributions of source code must retain the above copyright
   12      notice, this list of conditions and the following disclaimer.
   13   2. Redistributions in binary form must reproduce the above copyright
   14      notice, this list of conditions and the following disclaimer in
   15      the documentation and/or other materials provided with the
   16      distribution.
   17   3. The names of the authors may not be used to endorse or promote
   18      products derived from this software without specific prior
   19      written permission.
   20 
   21   THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
   22   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   23   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
   25   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
   27   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   28   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   29   IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   30   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
   31   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32 */
   33 
   34 #include <limits.h>
   35 #include <stdlib.h>
   36 #include <string.h>
   37 
   38 #include "zipint.h"
   39 
   40 struct context {
   41     zip_error_t error;
   42 
   43     bool end_of_input;
   44     bool end_of_stream;
   45     bool can_store;
   46     bool is_stored; /* only valid if end_of_stream is true */
   47     bool compress;
   48     zip_int32_t method;
   49 
   50     zip_uint64_t size;
   51     zip_int64_t first_read;
   52     zip_uint8_t buffer[BUFSIZE];
   53 
   54     zip_compression_algorithm_t *algorithm;
   55     void *ud;
   56 };
   57 
   58 
   59 struct implementation {
   60     zip_uint16_t method;
   61     zip_compression_algorithm_t *compress;
   62     zip_compression_algorithm_t *decompress;
   63 };
   64 
   65 static struct implementation implementations[] = {
   66     {ZIP_CM_DEFLATE, &zip_algorithm_deflate_compress, &zip_algorithm_deflate_decompress},
   67 #if defined(HAVE_LIBBZ2)
   68     {ZIP_CM_BZIP2, &zip_algorithm_bzip2_compress, &zip_algorithm_bzip2_decompress},
   69 #endif
   70 };
   71 
   72 static size_t implementations_size = sizeof(implementations) / sizeof(implementations[0]);
   73 
   74 static zip_source_t *compression_source_new(zip_t *za, zip_source_t *src, zip_int32_t method, bool compress, int compression_flags);
   75 static zip_int64_t compress_callback(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);
   76 static void context_free(struct context *ctx);
   77 static struct context *context_new(zip_int32_t method, bool compress, int compression_flags, zip_compression_algorithm_t *algorithm);
   78 static zip_int64_t compress_read(zip_source_t *, struct context *, void *, zip_uint64_t);
   79 
   80 static zip_compression_algorithm_t *
   81 get_algorithm(zip_int32_t method, bool compress) {
   82     size_t i;
   83     zip_uint16_t real_method = ZIP_CM_ACTUAL(method);
   84 
   85     for (i = 0; i < implementations_size; i++) {
   86     if (implementations[i].method == real_method) {
   87         if (compress) {
   88         return implementations[i].compress;
   89         }
   90         else {
   91         return implementations[i].decompress;
   92         }
   93     }
   94     }
   95 
   96     return NULL;
   97 }
   98 
   99 bool
  100 zip_compression_method_supported(zip_int32_t method, bool compress) {
  101     if (method == ZIP_CM_STORE) {
  102     return true;
  103     }
  104     return get_algorithm(method, compress) != NULL;
  105 }
  106 
  107 zip_source_t *
  108 zip_source_compress(zip_t *za, zip_source_t *src, zip_int32_t method, int compression_flags) {
  109     return compression_source_new(za, src, method, true, compression_flags);
  110 }
  111 
  112 zip_source_t *
  113 zip_source_decompress(zip_t *za, zip_source_t *src, zip_int32_t method) {
  114     return compression_source_new(za, src, method, false, 0);
  115 }
  116 
  117 
  118 static zip_source_t *
  119 compression_source_new(zip_t *za, zip_source_t *src, zip_int32_t method, bool compress, int compression_flags) {
  120     struct context *ctx;
  121     zip_source_t *s2;
  122     zip_compression_algorithm_t *algorithm = NULL;
  123 
  124     if (src == NULL) {
  125     zip_error_set(&za->error, ZIP_ER_INVAL, 0);
  126     return NULL;
  127     }
  128 
  129     if ((algorithm = get_algorithm(method, compress)) == NULL) {
  130     zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
  131     return NULL;
  132     }
  133 
  134     if ((ctx = context_new(method, compress, compression_flags, algorithm)) == NULL) {
  135     zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
  136     return NULL;
  137     }
  138 
  139     if ((s2 = zip_source_layered(za, src, compress_callback, ctx)) == NULL) {
  140     context_free(ctx);
  141     return NULL;
  142     }
  143 
  144     return s2;
  145 }
  146 
  147 
  148 static struct context *
  149 context_new(zip_int32_t method, bool compress, int compression_flags, zip_compression_algorithm_t *algorithm) {
  150     struct context *ctx;
  151 
  152     if ((ctx = (struct context *)malloc(sizeof(*ctx))) == NULL) {
  153     return NULL;
  154     }
  155     zip_error_init(&ctx->error);
  156     ctx->can_store = compress ? ZIP_CM_IS_DEFAULT(method) : false;
  157     ctx->algorithm = algorithm;
  158     ctx->method = method;
  159     ctx->compress = compress;
  160     ctx->end_of_input = false;
  161     ctx->end_of_stream = false;
  162     ctx->is_stored = false;
  163 
  164     if ((ctx->ud = ctx->algorithm->allocate(ZIP_CM_ACTUAL(method), compression_flags, &ctx->error)) == NULL) {
  165     zip_error_fini(&ctx->error);
  166     free(ctx);
  167     return NULL;
  168     }
  169 
  170     return ctx;
  171 }
  172 
  173 
  174 static void
  175 context_free(struct context *ctx) {
  176     if (ctx == NULL) {
  177     return;
  178     }
  179 
  180     ctx->algorithm->deallocate(ctx->ud);
  181     zip_error_fini(&ctx->error);
  182 
  183     free(ctx);
  184 }
  185 
  186 
  187 static zip_int64_t
  188 compress_read(zip_source_t *src, struct context *ctx, void *data, zip_uint64_t len) {
  189     zip_compression_status_t ret;
  190     bool end;
  191     zip_int64_t n;
  192     zip_uint64_t out_offset;
  193     zip_uint64_t out_len;
  194 
  195     if (zip_error_code_zip(&ctx->error) != ZIP_ER_OK) {
  196     return -1;
  197     }
  198 
  199     if (len == 0 || ctx->end_of_stream) {
  200     return 0;
  201     }
  202 
  203     out_offset = 0;
  204 
  205     end = false;
  206     while (!end && out_offset < len) {
  207     out_len = len - out_offset;
  208     ret = ctx->algorithm->process(ctx->ud, (zip_uint8_t *)data + out_offset, &out_len);
  209 
  210     if (ret != ZIP_COMPRESSION_ERROR) {
  211         out_offset += out_len;
  212     }
  213 
  214     switch (ret) {
  215     case ZIP_COMPRESSION_END:
  216         ctx->end_of_stream = true;
  217 
  218         if (!ctx->end_of_input) {
  219         /* TODO: garbage after stream, or compression ended before all data read */
  220         }
  221 
  222         if (ctx->first_read < 0) {
  223         /* we got end of processed stream before reading any input data */
  224         zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
  225         end = true;
  226         break;
  227         }
  228         if (ctx->can_store && (zip_uint64_t)ctx->first_read <= out_offset) {
  229         ctx->is_stored = true;
  230         ctx->size = (zip_uint64_t)ctx->first_read;
  231         memcpy(data, ctx->buffer, ctx->size);
  232         return (zip_int64_t)ctx->size;
  233         }
  234         end = true;
  235         break;
  236 
  237     case ZIP_COMPRESSION_OK:
  238         break;
  239 
  240     case ZIP_COMPRESSION_NEED_DATA:
  241         if (ctx->end_of_input) {
  242         /* TODO: error: stream not ended, but no more input */
  243         end = true;
  244         break;
  245         }
  246 
  247         if ((n = zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) {
  248         _zip_error_set_from_source(&ctx->error, src);
  249         end = true;
  250         break;
  251         }
  252         else if (n == 0) {
  253         ctx->end_of_input = true;
  254         ctx->algorithm->end_of_input(ctx->ud);
  255         if (ctx->first_read < 0) {
  256             ctx->first_read = 0;
  257         }
  258         }
  259         else {
  260         if (ctx->first_read >= 0) {
  261             /* we overwrote a previously filled ctx->buffer */
  262             ctx->can_store = false;
  263         }
  264         else {
  265             ctx->first_read = n;
  266         }
  267 
  268         ctx->algorithm->input(ctx->ud, ctx->buffer, (zip_uint64_t)n);
  269         }
  270         break;
  271 
  272     case ZIP_COMPRESSION_ERROR:
  273         /* error set by algorithm */
  274         if (zip_error_code_zip(&ctx->error) == ZIP_ER_OK) {
  275         zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
  276         }
  277         end = true;
  278         break;
  279     }
  280     }
  281 
  282     if (out_offset > 0) {
  283     ctx->can_store = false;
  284     ctx->size += out_offset;
  285     return (zip_int64_t)out_offset;
  286     }
  287 
  288     return (zip_error_code_zip(&ctx->error) == ZIP_ER_OK) ? 0 : -1;
  289 }
  290 
  291 
  292 static zip_int64_t
  293 compress_callback(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
  294     struct context *ctx;
  295 
  296     ctx = (struct context *)ud;
  297 
  298     switch (cmd) {
  299     case ZIP_SOURCE_OPEN:
  300     ctx->size = 0;
  301     ctx->end_of_input = false;
  302     ctx->end_of_stream = false;
  303     ctx->is_stored = false;
  304     ctx->first_read = -1;
  305 
  306     if (!ctx->algorithm->start(ctx->ud)) {
  307         return -1;
  308     }
  309 
  310     return 0;
  311 
  312     case ZIP_SOURCE_READ:
  313     return compress_read(src, ctx, data, len);
  314 
  315     case ZIP_SOURCE_CLOSE:
  316     if (!ctx->algorithm->end(ctx->ud)) {
  317         return -1;
  318     }
  319     return 0;
  320 
  321     case ZIP_SOURCE_STAT: {
  322     zip_stat_t *st;
  323 
  324     st = (zip_stat_t *)data;
  325 
  326     if (ctx->compress) {
  327         if (ctx->end_of_stream) {
  328         st->comp_method = ctx->is_stored ? ZIP_CM_STORE : ZIP_CM_ACTUAL(ctx->method);
  329         st->comp_size = ctx->size;
  330         st->valid |= ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD;
  331         }
  332         else {
  333         st->valid &= ~(ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD);
  334         }
  335     }
  336     else {
  337         st->comp_method = ZIP_CM_STORE;
  338         st->valid |= ZIP_STAT_COMP_METHOD;
  339         if (ctx->end_of_stream) {
  340         st->size = ctx->size;
  341         st->valid |= ZIP_STAT_SIZE;
  342         }
  343         else {
  344         st->valid &= ~ZIP_STAT_SIZE;
  345         }
  346     }
  347     }
  348     return 0;
  349 
  350     case ZIP_SOURCE_GET_COMPRESSION_FLAGS:
  351     return ctx->is_stored ? 0 : ctx->algorithm->compression_flags(ctx->ud);
  352 
  353     case ZIP_SOURCE_ERROR:
  354     return zip_error_to_data(&ctx->error, data, len);
  355 
  356     case ZIP_SOURCE_FREE:
  357     context_free(ctx);
  358     return 0;
  359 
  360     case ZIP_SOURCE_SUPPORTS:
  361     return ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_GET_COMPRESSION_FLAGS, -1);
  362 
  363     default:
  364     zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
  365     return -1;
  366     }
  367 }