root/ext/zip/lib/zip_source_buffer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zip_source_buffer
  2. zip_source_buffer_create
  3. read_data
  4. buffer_free
  5. buffer_new
  6. buffer_new_read
  7. buffer_new_write
  8. buffer_read
  9. buffer_seek
  10. buffer_write

   1 /*
   2   zip_source_buffer.c -- create zip data source from buffer
   3   Copyright (C) 1999-2016 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 <stdlib.h>
  35 #include <string.h>
  36 
  37 #include "zipint.h"
  38 
  39 #ifndef WRITE_FRAGMENT_SIZE
  40 #define WRITE_FRAGMENT_SIZE 64*1024
  41 #endif
  42 
  43 struct buffer {
  44     zip_uint64_t fragment_size;         /* size of each fragment */
  45 
  46     zip_uint8_t **fragments;            /* pointers to fragments */
  47     zip_uint64_t nfragments;            /* number of allocated fragments */
  48     zip_uint64_t fragments_capacity;    /* size of fragments (number of pointers) */
  49     zip_uint64_t size;                  /* size of data in bytes */
  50     zip_uint64_t offset;                /* current offset */
  51     int free_data;
  52 };
  53 
  54 typedef struct buffer buffer_t;
  55 
  56 struct read_data {
  57     zip_error_t error;
  58     time_t mtime;
  59     buffer_t *in;
  60     buffer_t *out;
  61 };
  62 
  63 static void buffer_free(buffer_t *buffer);
  64 static buffer_t *buffer_new(zip_uint64_t fragment_size);
  65 static buffer_t *buffer_new_read(const void *data, zip_uint64_t length, int free_data);
  66 static buffer_t *buffer_new_write(zip_uint64_t fragment_size);
  67 static zip_int64_t buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length);
  68 static int buffer_seek(buffer_t *buffer, void *data, zip_uint64_t len, zip_error_t *error);
  69 static zip_int64_t buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *);
  70 
  71 static zip_int64_t read_data(void *, void *, zip_uint64_t, zip_source_cmd_t);
  72 
  73 
  74 ZIP_EXTERN zip_source_t *
  75 zip_source_buffer(zip_t *za, const void *data, zip_uint64_t len, int freep)
  76 {
  77     if (za == NULL)
  78         return NULL;
  79 
  80     return zip_source_buffer_create(data, len, freep, &za->error);
  81 }
  82 
  83 
  84 ZIP_EXTERN zip_source_t *
  85 zip_source_buffer_create(const void *data, zip_uint64_t len, int freep, zip_error_t *error)
  86 {
  87     struct read_data *ctx;
  88     zip_source_t *zs;
  89 
  90     if (data == NULL && len > 0) {
  91         zip_error_set(error, ZIP_ER_INVAL, 0);
  92         return NULL;
  93     }
  94 
  95     if ((ctx=(struct read_data *)malloc(sizeof(*ctx))) == NULL) {
  96         zip_error_set(error, ZIP_ER_MEMORY, 0);
  97         return NULL;
  98     }
  99 
 100     if ((ctx->in = buffer_new_read(data, len, freep)) == NULL) {
 101         zip_error_set(error, ZIP_ER_MEMORY, 0);
 102         free(ctx);
 103         return NULL;
 104     }
 105 
 106     ctx->out = NULL;
 107     ctx->mtime = time(NULL);
 108     zip_error_init(&ctx->error);
 109     
 110     if ((zs=zip_source_function_create(read_data, ctx, error)) == NULL) {
 111         buffer_free(ctx->in);
 112         free(ctx);
 113         return NULL;
 114     }
 115 
 116     return zs;
 117 }
 118 
 119 
 120 static zip_int64_t
 121 read_data(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd)
 122 {
 123     struct read_data *ctx = (struct read_data *)state;
 124 
 125     switch (cmd) {
 126         case ZIP_SOURCE_BEGIN_WRITE:
 127             if ((ctx->out = buffer_new_write(WRITE_FRAGMENT_SIZE)) == NULL) {
 128                 zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
 129                 return -1;
 130             }
 131             return 0;
 132 
 133         case ZIP_SOURCE_CLOSE:
 134             return 0;
 135             
 136         case ZIP_SOURCE_COMMIT_WRITE:
 137             buffer_free(ctx->in);
 138             ctx->in = ctx->out;
 139             ctx->out = NULL;
 140             return 0;
 141 
 142         case ZIP_SOURCE_ERROR:
 143             return zip_error_to_data(&ctx->error, data, len);
 144             
 145         case ZIP_SOURCE_FREE:
 146             buffer_free(ctx->in);
 147             buffer_free(ctx->out);
 148             free(ctx);
 149             return 0;
 150             
 151         case ZIP_SOURCE_OPEN:
 152             ctx->in->offset = 0;
 153             return 0;
 154         
 155         case ZIP_SOURCE_READ:
 156             if (len > ZIP_INT64_MAX) {
 157                 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
 158                 return -1;
 159             }
 160             return buffer_read(ctx->in, data, len);
 161         
 162         case ZIP_SOURCE_REMOVE:
 163         {
 164             buffer_t *empty = buffer_new_read(NULL, 0, 0);
 165             if (empty == 0) {
 166                 zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
 167                 return -1;
 168             }
 169         
 170             buffer_free(ctx->in);
 171             ctx->in = empty;
 172             return 0;
 173         }
 174 
 175         case ZIP_SOURCE_ROLLBACK_WRITE:
 176             buffer_free(ctx->out);
 177             ctx->out = NULL;
 178             return 0;
 179 
 180         case ZIP_SOURCE_SEEK:
 181             return buffer_seek(ctx->in, data, len, &ctx->error);
 182 
 183         case ZIP_SOURCE_SEEK_WRITE:
 184             return buffer_seek(ctx->out, data, len, &ctx->error);
 185        
 186         case ZIP_SOURCE_STAT:
 187         {
 188             zip_stat_t *st;
 189             
 190             if (len < sizeof(*st)) {
 191                 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
 192                 return -1;
 193             }
 194 
 195             st = (zip_stat_t *)data;
 196 
 197             zip_stat_init(st);
 198             st->mtime = ctx->mtime;
 199             st->size = ctx->in->size;
 200             st->comp_size = st->size;
 201             st->comp_method = ZIP_CM_STORE;
 202             st->encryption_method = ZIP_EM_NONE;
 203             st->valid = ZIP_STAT_MTIME|ZIP_STAT_SIZE|ZIP_STAT_COMP_SIZE|ZIP_STAT_COMP_METHOD|ZIP_STAT_ENCRYPTION_METHOD;
 204             
 205             return sizeof(*st);
 206         }
 207 
 208         case ZIP_SOURCE_SUPPORTS:
 209             return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_WRITE, -1);
 210             
 211         case ZIP_SOURCE_TELL:
 212             if (ctx->in->offset > ZIP_INT64_MAX) {
 213                 zip_error_set(&ctx->error, ZIP_ER_TELL, EOVERFLOW);
 214                 return -1;
 215             }
 216             return (zip_int64_t)ctx->in->offset;
 217                 
 218             
 219         case ZIP_SOURCE_TELL_WRITE:
 220             if (ctx->out->offset > ZIP_INT64_MAX) {
 221                 zip_error_set(&ctx->error, ZIP_ER_TELL, EOVERFLOW);
 222                 return -1;
 223             }
 224             return (zip_int64_t)ctx->out->offset;
 225 
 226         case ZIP_SOURCE_WRITE:
 227             if (len > ZIP_INT64_MAX) {
 228                 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
 229                 return -1;
 230             }
 231             return buffer_write(ctx->out, data, len, &ctx->error);
 232 
 233         default:
 234             zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
 235             return -1;
 236     }
 237 }
 238 
 239 
 240 static void
 241 buffer_free(buffer_t *buffer)
 242 {
 243     if (buffer == NULL) {
 244         return; 
 245     }
 246 
 247     if (buffer->free_data) {
 248         zip_uint64_t i;
 249 
 250         for (i=0; i < buffer->nfragments; i++) {
 251             free(buffer->fragments[i]);
 252         }
 253     }
 254     free(buffer->fragments);
 255     free(buffer);
 256 }
 257 
 258 
 259 static buffer_t *
 260 buffer_new(zip_uint64_t fragment_size)
 261 {
 262     buffer_t *buffer;
 263 
 264     if ((buffer = malloc(sizeof(*buffer))) == NULL) {
 265         return NULL;
 266     }
 267 
 268     buffer->fragment_size = fragment_size;
 269     buffer->offset = 0;
 270     buffer->free_data = 0;
 271     buffer->nfragments = 0;
 272     buffer->fragments_capacity = 0;
 273     buffer->fragments = NULL;
 274     buffer->size = 0;
 275 
 276     return buffer;
 277 }
 278 
 279 
 280 static buffer_t *
 281 buffer_new_read(const void *data, zip_uint64_t length, int free_data)
 282 {
 283     buffer_t *buffer;
 284 
 285     if ((buffer = buffer_new(length)) == NULL) {
 286         return NULL;
 287     }
 288 
 289     buffer->size = length;
 290 
 291     if (length > 0) {
 292         if ((buffer->fragments = malloc(sizeof(*(buffer->fragments)))) == NULL) {
 293             buffer_free(buffer);
 294             return NULL;
 295         }
 296         buffer->fragments_capacity = 1;
 297 
 298         buffer->nfragments = 1;
 299         buffer->fragments[0] = (zip_uint8_t *)data;
 300         buffer->free_data = free_data;
 301     }
 302 
 303     return buffer;
 304 }
 305 
 306 
 307 static buffer_t *
 308 buffer_new_write(zip_uint64_t fragment_size)
 309 {
 310     buffer_t *buffer;
 311 
 312     if ((buffer = buffer_new(fragment_size)) == NULL) {
 313         return NULL;
 314     }
 315 
 316     if ((buffer->fragments = malloc(sizeof(*(buffer->fragments)))) == NULL) {
 317         buffer_free(buffer);
 318         return NULL;
 319     }
 320     buffer->fragments_capacity = 1;
 321     buffer->nfragments = 0;
 322     buffer->free_data = 1;
 323 
 324     return buffer;
 325 }
 326 
 327 
 328 static zip_int64_t
 329 buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length)
 330 {
 331     zip_uint64_t n, i, fragment_offset;
 332 
 333     length = ZIP_MIN(length, buffer->size - buffer->offset);
 334 
 335     if (length == 0) {
 336         return 0;
 337     }
 338     if (length > ZIP_INT64_MAX) {
 339         return -1;
 340     }
 341 
 342     i = buffer->offset / buffer->fragment_size;
 343     fragment_offset = buffer->offset % buffer->fragment_size;
 344     n = 0;
 345     while (n < length) {
 346         zip_uint64_t left = ZIP_MIN(length - n, buffer->fragment_size - fragment_offset);
 347         
 348         memcpy(data + n, buffer->fragments[i] + fragment_offset, left);
 349 
 350         n += left;
 351         i++;
 352         fragment_offset = 0;
 353     }
 354 
 355     buffer->offset += n;
 356     return (zip_int64_t)n;
 357 }
 358 
 359 
 360 static int
 361 buffer_seek(buffer_t *buffer, void *data, zip_uint64_t len, zip_error_t *error)
 362 {
 363     zip_int64_t new_offset = zip_source_seek_compute_offset(buffer->offset, buffer->size, data, len, error);
 364     
 365     if (new_offset < 0) {
 366         return -1;
 367     }
 368     
 369     buffer->offset = (zip_uint64_t)new_offset;
 370     return 0;
 371 }
 372 
 373 
 374 static zip_int64_t
 375 buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *error)
 376 {
 377     zip_uint64_t n, i, fragment_offset;
 378     zip_uint8_t **fragments;
 379 
 380     if (buffer->offset + length + buffer->fragment_size - 1 < length) {
 381         zip_error_set(error, ZIP_ER_INVAL, 0);
 382         return -1;
 383     }
 384 
 385     /* grow buffer if needed */
 386     if (buffer->offset + length > buffer->nfragments * buffer->fragment_size) {
 387         zip_uint64_t needed_fragments = (buffer->offset + length + buffer->fragment_size - 1) / buffer->fragment_size;
 388         
 389         if (needed_fragments > buffer->fragments_capacity) {
 390             zip_uint64_t new_capacity = buffer->fragments_capacity;
 391 
 392             while (new_capacity < needed_fragments) {
 393                 new_capacity *= 2;
 394             }
 395 
 396             fragments = realloc(buffer->fragments, new_capacity * sizeof(*fragments));
 397 
 398             if (fragments == NULL) {
 399                 zip_error_set(error, ZIP_ER_MEMORY, 0);
 400                 return -1;
 401             }
 402 
 403             buffer->fragments = fragments;
 404             buffer->fragments_capacity = new_capacity;
 405         }
 406 
 407         while (buffer->nfragments < needed_fragments) {
 408             if ((buffer->fragments[buffer->nfragments] = malloc(buffer->fragment_size)) == NULL) {
 409                 zip_error_set(error, ZIP_ER_MEMORY, 0);
 410                 return -1;
 411             }
 412             buffer->nfragments++;
 413         }
 414     }
 415 
 416     i = buffer->offset / buffer->fragment_size;
 417     fragment_offset = buffer->offset % buffer->fragment_size;
 418     n = 0;
 419     while (n < length) {
 420         zip_uint64_t left = ZIP_MIN(length - n, buffer->fragment_size - fragment_offset);
 421                 
 422         memcpy(buffer->fragments[i] + fragment_offset, data + n, left);
 423 
 424         n += left;
 425         i++;
 426         fragment_offset = 0;
 427     }
 428 
 429     buffer->offset += n;
 430     if (buffer->offset > buffer->size) {
 431         buffer->size = buffer->offset;
 432     }
 433 
 434     return (zip_int64_t)n;
 435 }

/* [<][>][^][v][top][bottom][index][help] */