root/ext/zip/lib/zip_extra_field.c

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

DEFINITIONS

This source file includes following definitions.
  1. _zip_ef_clone
  2. _zip_ef_delete_by_id
  3. _zip_ef_free
  4. _zip_ef_get_by_id
  5. _zip_ef_merge
  6. _zip_ef_new
  7. _zip_ef_parse
  8. _zip_ef_remove_internal
  9. _zip_ef_size
  10. _zip_ef_write
  11. _zip_read_local_ef

   1 /*
   2   zip_extra_field.c -- manipulate extra fields
   3   Copyright (C) 2012-2015 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 
  35 
  36 #include "zipint.h"
  37 
  38 #include <errno.h>
  39 #include <stdlib.h>
  40 #include <string.h>
  41 
  42 
  43 
  44 struct zip_extra_field *
  45 _zip_ef_clone(const struct zip_extra_field *ef, struct zip_error *error)
  46 {
  47     struct zip_extra_field *head, *prev, *def;
  48     
  49     head = prev = NULL;
  50     
  51     while (ef) {
  52         if ((def=_zip_ef_new(ef->id, ef->size, ef->data, ef->flags)) == NULL) {
  53             _zip_error_set(error, ZIP_ER_MEMORY, 0);
  54             _zip_ef_free(head);
  55             return NULL;
  56         }
  57         
  58         if (head == NULL)
  59             head = def;
  60         if (prev)
  61             prev->next = def;
  62         prev = def;
  63 
  64         ef = ef->next;
  65     }
  66     
  67     return head;
  68 }
  69 
  70 
  71 struct zip_extra_field *
  72 _zip_ef_delete_by_id(struct zip_extra_field *ef, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags)
  73 {
  74     struct zip_extra_field *head, *prev;
  75     int i;
  76 
  77     i = 0;
  78     head = ef;
  79     prev = NULL;
  80     for (; ef; ef=(prev ? prev->next : head)) {
  81         if ((ef->flags & flags & ZIP_EF_BOTH) && ((ef->id == id) || (id == ZIP_EXTRA_FIELD_ALL))) {
  82             if (id_idx == ZIP_EXTRA_FIELD_ALL || i == id_idx) {
  83                 ef->flags &= ~(flags & ZIP_EF_BOTH);
  84                 if ((ef->flags & ZIP_EF_BOTH) == 0) {
  85                     if (prev)
  86                         prev->next = ef->next;
  87                     else
  88                         head = ef->next;
  89                     ef->next = NULL;
  90                     _zip_ef_free(ef);
  91 
  92                     if (id_idx == ZIP_EXTRA_FIELD_ALL)
  93                         continue;
  94                 }
  95             }
  96             
  97             i++;
  98             if (i > id_idx)
  99                 break;
 100         }
 101         prev = ef;
 102     }
 103 
 104     return head;
 105 }
 106 
 107 
 108 
 109 
 110 void
 111 _zip_ef_free(struct zip_extra_field *ef)
 112 {
 113     struct zip_extra_field *ef2;
 114 
 115     while (ef) {
 116         ef2 = ef->next;
 117         free(ef->data);
 118         free(ef);
 119         ef = ef2;
 120     }
 121 }
 122 
 123 
 124 
 125 const zip_uint8_t *
 126 _zip_ef_get_by_id(const struct zip_extra_field *ef, zip_uint16_t *lenp, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags, struct zip_error *error)
 127 {
 128     static const zip_uint8_t empty[1] = { '\0' };
 129     
 130     int i;
 131 
 132     i = 0;
 133     for (; ef; ef=ef->next) {
 134         if (ef->id == id && (ef->flags & flags & ZIP_EF_BOTH)) {
 135             if (i < id_idx) {
 136                 i++;
 137                 continue;
 138             }
 139 
 140             if (lenp)
 141                 *lenp = ef->size;
 142             if (ef->size > 0)
 143                 return ef->data;
 144             else
 145                 return empty;
 146         }
 147     }
 148 
 149     _zip_error_set(error, ZIP_ER_NOENT, 0);
 150     return NULL;
 151 }
 152 
 153 
 154 
 155 struct zip_extra_field *
 156 _zip_ef_merge(struct zip_extra_field *to, struct zip_extra_field *from)
 157 {
 158     struct zip_extra_field *ef2, *tt, *tail;
 159     int duplicate;
 160 
 161     if (to == NULL)
 162         return from;
 163 
 164     for (tail=to; tail->next; tail=tail->next)
 165         ;
 166 
 167     for (; from; from=ef2) {
 168         ef2 = from->next;
 169 
 170         duplicate = 0;
 171         for (tt=to; tt; tt=tt->next) {
 172             if (tt->id == from->id && tt->size == from->size && memcmp(tt->data, from->data, tt->size) == 0) {
 173                 tt->flags |= (from->flags & ZIP_EF_BOTH);
 174                 duplicate = 1;
 175                 break;
 176             }
 177         }
 178 
 179         from->next = NULL;
 180         if (duplicate)
 181             _zip_ef_free(from);
 182         else
 183             tail = tail->next = from;
 184     }
 185 
 186     return to;
 187 }
 188 
 189 
 190 
 191 struct zip_extra_field *
 192 _zip_ef_new(zip_uint16_t id, zip_uint16_t size, const zip_uint8_t *data, zip_flags_t flags)
 193 {
 194     struct zip_extra_field *ef;
 195 
 196     if ((ef=(struct zip_extra_field *)malloc(sizeof(*ef))) == NULL)
 197         return NULL;
 198 
 199     ef->next = NULL;
 200     ef->flags = flags;
 201     ef->id = id;
 202     ef->size = size;
 203     if (size > 0) {
 204         if ((ef->data=(zip_uint8_t *)_zip_memdup(data, size, NULL)) == NULL) {
 205             free(ef);
 206             return NULL;
 207         }
 208     }
 209     else
 210         ef->data = NULL;
 211 
 212     return ef;
 213 }
 214 
 215 
 216 
 217 struct zip_extra_field *
 218 _zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, struct zip_error *error)
 219 {
 220     struct zip_extra_field *ef, *ef2, *ef_head;
 221     const zip_uint8_t *p;
 222     zip_uint16_t fid, flen;
 223 
 224     ef_head = NULL;
 225     for (p=data; p<data+len; p+=flen) {
 226         if (p+4 > data+len) {
 227             _zip_error_set(error, ZIP_ER_INCONS, 0);
 228             _zip_ef_free(ef_head);
 229             return NULL;
 230         }
 231 
 232         fid = _zip_read2(&p);
 233         flen = _zip_read2(&p);
 234 
 235         if (p+flen > data+len) {
 236             _zip_error_set(error, ZIP_ER_INCONS, 0);
 237             _zip_ef_free(ef_head);
 238             return NULL;
 239         }
 240 
 241         if ((ef2=_zip_ef_new(fid, flen, p, flags)) == NULL) {
 242             _zip_error_set(error, ZIP_ER_MEMORY, 0);
 243             _zip_ef_free(ef_head);
 244             return NULL;
 245         }
 246 
 247         if (ef_head) {
 248             ef->next = ef2;
 249             ef = ef2;
 250         }
 251         else
 252             ef_head = ef = ef2;
 253     }
 254 
 255     return ef_head;
 256 }
 257 
 258 
 259 
 260 struct zip_extra_field *
 261 _zip_ef_remove_internal(struct zip_extra_field *ef)
 262 {
 263     struct zip_extra_field *ef_head;
 264     struct zip_extra_field *prev, *next;
 265     
 266     ef_head = ef;
 267     prev = NULL;
 268     
 269     while (ef) {
 270         if (ZIP_EF_IS_INTERNAL(ef->id)) {
 271             next = ef->next;
 272             if (ef_head == ef)
 273                 ef_head = next;
 274             ef->next = NULL;
 275             _zip_ef_free(ef);
 276             if (prev)
 277                 prev->next = next;
 278             ef = next;
 279         }
 280         else {
 281             prev = ef;
 282             ef = ef->next;
 283         }
 284     }
 285     
 286     return ef_head;
 287 }
 288 
 289 
 290 zip_uint16_t
 291 _zip_ef_size(const struct zip_extra_field *ef, zip_flags_t flags)
 292 {
 293     zip_uint16_t size;
 294 
 295     size = 0;
 296     for (; ef; ef=ef->next) {
 297         if (ef->flags & flags & ZIP_EF_BOTH)
 298             size += 4+ef->size;
 299     }
 300 
 301     return size;
 302 }
 303 
 304 
 305 
 306 void
 307 _zip_ef_write(const struct zip_extra_field *ef, zip_flags_t flags, FILE *f)
 308 {
 309     for (; ef; ef=ef->next) {
 310         if (ef->flags & flags & ZIP_EF_BOTH) {
 311             _zip_write2(ef->id, f);
 312             _zip_write2(ef->size, f);
 313             if (ef->size > 0)
 314                 fwrite(ef->data, ef->size, 1, f);
 315         }
 316     }
 317 }
 318 
 319 
 320 
 321 int
 322 _zip_read_local_ef(struct zip *za, zip_uint64_t idx)
 323 {
 324     struct zip_entry *e;
 325     unsigned char b[4];
 326     const unsigned char *p;
 327     zip_uint16_t fname_len, ef_len;
 328 
 329     if (idx >= za->nentry) {
 330         _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
 331         return -1;
 332     }
 333 
 334     e = za->entry+idx;
 335 
 336     if (e->orig == NULL || e->orig->local_extra_fields_read)
 337         return 0;
 338 
 339 
 340     if (fseeko(za->zp, (off_t)(e->orig->offset + 26), SEEK_SET) < 0) {
 341         _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
 342         return -1;
 343     }
 344 
 345     if (fread(b, sizeof(b), 1, za->zp) != 1) {
 346         _zip_error_set(&za->error, ZIP_ER_READ, errno);
 347         return -1;
 348     }
 349 
 350     p = b;
 351     fname_len = _zip_read2(&p);
 352     ef_len = _zip_read2(&p);
 353 
 354     if (ef_len > 0) {
 355         struct zip_extra_field *ef;
 356         zip_uint8_t *ef_raw;
 357 
 358         if (fseek(za->zp, fname_len, SEEK_CUR) < 0) {
 359             _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
 360             return -1;
 361         }
 362 
 363         ef_raw = _zip_read_data(NULL, za->zp, ef_len, 0, &za->error);
 364 
 365         if (ef_raw == NULL)
 366             return -1;
 367 
 368         if ((ef=_zip_ef_parse(ef_raw, ef_len, ZIP_EF_LOCAL, &za->error)) == NULL) {
 369             free(ef_raw);
 370             return -1;
 371         }
 372         free(ef_raw);
 373         
 374         ef = _zip_ef_remove_internal(ef);
 375         e->orig->extra_fields = _zip_ef_merge(e->orig->extra_fields, ef);
 376     }
 377 
 378     e->orig->local_extra_fields_read = 1;
 379     
 380     if (e->changes && e->changes->local_extra_fields_read == 0) {
 381         e->changes->extra_fields = e->orig->extra_fields;
 382         e->changes->local_extra_fields_read = 1;
 383     }
 384 
 385     return 0;
 386 }

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