libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

unzip.c (45783B)


      1 /*
      2      This file is part of libextractor.
      3      Copyright (C) 2004, 2008, 2012, 2026 Vidyut Samanta and Christian Grothoff
      4 
      5      libextractor is free software; you can redistribute it and/or modify
      6      it under the terms of the GNU General Public License as published
      7      by the Free Software Foundation; either version 3, or (at your
      8      option) any later version.
      9 
     10      libextractor is distributed in the hope that it will be useful, but
     11      WITHOUT ANY WARRANTY; without even the implied warranty of
     12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13      General Public License for more details.
     14 
     15      You should have received a copy of the GNU General Public License
     16      along with libextractor; see the file COPYING.  If not, write to the
     17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18      Boston, MA 02110-1301, USA.
     19 */
     20 /**
     21  * @file common/unzip.c
     22  * @brief API to access ZIP archives
     23  * @author Christian Grothoff
     24  *
     25  * This code is based in part on
     26  * unzip 1.00 Copyright 1998-2003 Gilles Vollant
     27  * http://www.winimage.com/zLibDll"
     28  *
     29  *
     30  * The filenames for each file in a zipfile are stored in two locations.
     31  * There is one at the start of each entry, just before the compressed data,
     32  * and another at the end in a 'central directory structure'.
     33  *
     34  * In order to catch self-extracting executables, we scan backwards from the end
     35  * of the file looking for the central directory structure. The previous version
     36  * of this went forewards through the local headers, but that only works for plain
     37  * vanilla zip's and I don't feel like writing a special case for each of the dozen
     38  * self-extracting executable stubs.
     39  *
     40  * This assumes that the zip file is considered to be non-corrupt/non-truncated.
     41  * If it is truncated then it's not considered to be a zip and skipped.
     42  *
     43  * ZIP format description from appnote.iz and appnote.txt (more or less):
     44  *
     45  *   (this is why you always need to put in the last floppy if you span disks)
     46  *
     47  *   0- 3  end of central dir signature    4 bytes  (0x06054b50) P K ^E ^F
     48  *   4- 5  number of this disk             2 bytes
     49  *   6- 7  number of the disk with the
     50  *         start of the central directory  2 bytes
     51  *   8- 9  total number of entries in
     52  *         the central dir on this disk    2 bytes
     53  *  10-11  total number of entries in
     54  *         the central dir                 2 bytes
     55  *  12-15  size of the central directory   4 bytes
     56  *  16-19  offset of start of central
     57  *         directory with respect to
     58  *         the starting disk number        4 bytes
     59  *  20-21  zipfile comment length          2 bytes
     60  *  22-??  zipfile comment (variable size) max length 65536 bytes
     61  */
     62 #include "platform.h"
     63 #include <ctype.h>
     64 #include "extractor.h"
     65 #include "le_architecture.h"
     66 #include "unzip.h"
     67 
     68 #define CASESENSITIVITY (0)
     69 #define MAXFILENAME (256)
     70 
     71 #ifndef UNZ_BUFSIZE
     72 #define UNZ_BUFSIZE (16384)
     73 #endif
     74 
     75 #ifndef UNZ_MAXFILENAMEINZIP
     76 #define UNZ_MAXFILENAMEINZIP (256)
     77 #endif
     78 
     79 #define SIZECENTRALDIRITEM (0x2e)
     80 #define SIZEZIPLOCALHEADER (0x1e)
     81 
     82 
     83 /**
     84  * IO callbacks for access to the ZIP data.
     85  */
     86 struct FileFuncDefs
     87 {
     88   /**
     89    * Callback for reading @a size bytes from the ZIP archive into @a buf.
     90    * Returns the number of bytes actually copied, which is less than
     91    * @a size at the end of the archive.
     92    */
     93   size_t (*zread_file) (void *opaque, void *buf, size_t size);
     94 
     95   /**
     96    * Callback to obtain the current read offset in the ZIP archive,
     97    * -1 on error.
     98    */
     99   int64_t (*ztell_file) (void *opaque);
    100 
    101   /**
    102    * Callback for seeking to a different position in the ZIP archive.
    103    * Returns 0 on success.
    104    */
    105   int (*zseek_file) (void *opaque, int64_t offset, int whence);
    106 
    107   /**
    108    * Opaque argument to pass to all IO functions.
    109    */
    110   void *opaque;
    111 };
    112 
    113 
    114 /**
    115  * Macro to read using filefunc API.
    116  *
    117  * @param filefunc filefunc struct
    118  * @param buf where to write data
    119  * @param size number of bytes to read
    120  * @return number of bytes copied to buf
    121  */
    122 #define ZREAD(filefunc,buf,size) ((*((filefunc).zread_file))((filefunc).opaque, \
    123                                                              buf, size))
    124 
    125 /**
    126  * Macro to obtain current offset in file using filefunc API.
    127  *
    128  * @param filefunc filefunc struct
    129  * @return current offset in file
    130  */
    131 #define ZTELL(filefunc) ((*((filefunc).ztell_file))((filefunc).opaque))
    132 
    133 /**
    134  * Macro to seek using filefunc API.
    135  *
    136  * @param filefunc filefunc struct
    137  * @param pos position to seek
    138  * @param mode seek mode
    139  * @return 0 on success
    140  */
    141 #define ZSEEK(filefunc,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque, \
    142                                                              pos, mode))
    143 
    144 
    145 /**
    146  * Global data about the ZIPfile
    147  * These data comes from the end of central dir
    148  */
    149 struct GlobalInfo
    150 {
    151 
    152   /**
    153    * total number of entries in
    154    * the central dir on this disk  2 bytes
    155    */
    156   uint16_t number_entry;
    157 
    158   /**
    159    * size of the global comment of the zipfile  2 bytes
    160    */
    161   uint16_t size_comment;
    162 
    163   /**
    164    * offset of the global comment in the zipfile
    165    */
    166   uint64_t offset_comment;
    167 };
    168 
    169 
    170 /**
    171  * internal info about a file in zipfile
    172  */
    173 struct UnzipFileInfoInternal
    174 {
    175 
    176   /**
    177    * relative offset of local header 4 bytes
    178    */
    179   uint32_t offset_curfile;
    180 
    181 };
    182 
    183 
    184 /**
    185  * Information about a file in zipfile, when reading and
    186  * decompressing it
    187  */
    188 struct FileInZipReadInfo
    189 {
    190   /**
    191    * internal buffer for compressed data
    192    */
    193   char *read_buffer;
    194 
    195   /**
    196    * zLib stream structure for inflate
    197    */
    198   z_stream stream;
    199 
    200   /**
    201    * position in byte on the zipfile, for fseek
    202    */
    203   uint64_t pos_in_zipfile;
    204 
    205   /**
    206    * flag set if stream structure is initialised
    207    */
    208   int stream_initialised;
    209 
    210   /**
    211    * offset of the local extra field
    212    */
    213   uint64_t offset_local_extrafield;
    214 
    215   /**
    216    * size of the local extra field  2 bytes
    217    */
    218   uint16_t size_local_extrafield;
    219 
    220   /**
    221    * position in the local extra field in read
    222    */
    223   uint32_t pos_local_extrafield;
    224 
    225   /**
    226    * crc32 of all data uncompressed so far  4 bytes
    227    */
    228   uint32_t crc32;
    229 
    230   /**
    231    * crc32 we must obtain after decompress all  4 bytes
    232    */
    233   uint32_t crc32_wait;
    234 
    235   /**
    236    * number of bytes to be decompressed  4 bytes
    237    */
    238   uint32_t rest_read_compressed;
    239 
    240   /**
    241    * number of bytes to be obtained after decomp  4 bytes
    242    */
    243   uint32_t rest_read_uncompressed;
    244 
    245   /**
    246    * IO functions.
    247    */
    248   struct FileFuncDefs z_filefunc;
    249 
    250   /**
    251    * compression method (0==store)  2 bytes
    252    */
    253   uint16_t compression_method;
    254 
    255   /**
    256    * byte before the zipfile, (>0 for sfx)
    257    */
    258   uint64_t byte_before_the_zipfile;
    259 };
    260 
    261 
    262 /**
    263  * Handle for a ZIP archive.
    264  * contains internal information about the zipfile
    265  */
    266 struct EXTRACTOR_UnzipFile
    267 {
    268   /**
    269    * io structore of the zipfile
    270    */
    271   struct FileFuncDefs z_filefunc;
    272 
    273   /**
    274    * public global information
    275    */
    276   struct GlobalInfo gi;
    277 
    278   /**
    279    * byte before the zipfile, (>0 for sfx)
    280    */
    281   uint64_t byte_before_the_zipfile;
    282 
    283   /**
    284    * number of the current file in the zipfile
    285    */
    286   uint32_t num_file;
    287 
    288   /**
    289    * pos of the current file in the central dir
    290    */
    291   uint64_t pos_in_central_dir;
    292 
    293   /**
    294    * flag about the usability of the current file
    295    */
    296   int current_file_ok;
    297 
    298   /**
    299    * position of the beginning of the central dir
    300    */
    301   uint64_t central_pos;
    302 
    303   /**
    304    * size of the central directory  4 bytes
    305    */
    306   uint32_t size_central_dir;
    307 
    308   /**
    309    * offset of start of central directory with respect to the starting
    310    * disk number  4 bytes
    311    */
    312   uint32_t offset_central_dir;
    313 
    314   /**
    315    * public info about the current file in zip
    316    */
    317   struct EXTRACTOR_UnzipFileInfo cur_file_info;
    318 
    319   /**
    320    * private info about it
    321    */
    322   struct UnzipFileInfoInternal cur_file_info_internal;
    323 
    324   /**
    325    * structure about the current file if we are decompressing it
    326    */
    327   struct FileInZipReadInfo *pfile_in_zip_read;
    328 
    329   /**
    330    * Is the file encrypted?
    331    */
    332   int encrypted;
    333 };
    334 
    335 
    336 /**
    337  * Read a 16-bit little-endian field from the archive.
    338  *
    339  * The whole field is fetched with a single #ZREAD() and only then
    340  * byte-swapped, so a truncated archive can be recognised (the read is
    341  * short) instead of being papered over one byte at a time.  Note that
    342  * failure is reported as #EXTRACTOR_UNZIP_ERRNO and never as
    343  * #EXTRACTOR_UNZIP_EOF, which is numerically #EXTRACTOR_UNZIP_OK and so
    344  * would leave @a val untouched behind a successful-looking return.
    345  *
    346  * @param ffd functions for performing IO operations
    347  * @param[out] val set to the value that was read, untouched on error
    348  * @return #EXTRACTOR_UNZIP_OK on success, #EXTRACTOR_UNZIP_ERRNO if the
    349  *         field could not be read in full
    350  */
    351 static int
    352 read_uint16_from_ffd (const struct FileFuncDefs *ffd,
    353                       uint16_t *val)
    354 {
    355   uint16_t raw;
    356 
    357   if (sizeof (raw) != ZREAD (*ffd, &raw, sizeof (raw)))
    358     return EXTRACTOR_UNZIP_ERRNO;
    359   *val = LE_le16toh (raw);
    360   return EXTRACTOR_UNZIP_OK;
    361 }
    362 
    363 
    364 /**
    365  * Read a 32-bit little-endian field from the archive.
    366  *
    367  * See read_uint16_from_ffd() for why this reads the field in one go and
    368  * why it must not return #EXTRACTOR_UNZIP_EOF.
    369  *
    370  * @param ffd functions for performing IO operations
    371  * @param[out] val set to the value that was read, untouched on error
    372  * @return #EXTRACTOR_UNZIP_OK on success, #EXTRACTOR_UNZIP_ERRNO if the
    373  *         field could not be read in full
    374  */
    375 static int
    376 read_uint32_from_ffd (const struct FileFuncDefs *ffd,
    377                       uint32_t *val)
    378 {
    379   uint32_t raw;
    380 
    381   if (sizeof (raw) != ZREAD (*ffd, &raw, sizeof (raw)))
    382     return EXTRACTOR_UNZIP_ERRNO;
    383   *val = LE_le32toh (raw);
    384   return EXTRACTOR_UNZIP_OK;
    385 }
    386 
    387 
    388 #ifndef CASESENSITIVITYDEFAULT_NO
    389 #if ! defined(unix) && ! defined(CASESENSITIVITYDEFAULT_YES)
    390 #define CASESENSITIVITYDEFAULT_NO
    391 #endif
    392 #endif
    393 
    394 #ifdef  CASESENSITIVITYDEFAULT_NO
    395 #define CASESENSITIVITYDEFAULTVALUE 2
    396 #else
    397 #define CASESENSITIVITYDEFAULTVALUE 1
    398 #endif
    399 
    400 
    401 /**
    402  * Compare two filenames (fileName1, fileName2).
    403  *
    404  * @param filename1 name of first file
    405  * @param filename2 name of second file
    406  * @param iCaseSensitivity, use 1 for case sensitivity (like strcmp);
    407  *        2 for no case sensitivity (like strcmpi or strcasecmp); or
    408  *        0 for default of your operating system (like 1 on Unix, 2 on Windows)
    409  * @return 0 if names are equal
    410  */
    411 static int
    412 EXTRACTOR_common_unzip_string_file_name_compare (const char *fileName1,
    413                                                  const char *fileName2,
    414                                                  int iCaseSensitivity)
    415 {
    416   if (0 == iCaseSensitivity)
    417     iCaseSensitivity = CASESENSITIVITYDEFAULTVALUE;
    418   if (1 == iCaseSensitivity)
    419     return strcmp (fileName1,
    420                    fileName2);
    421   return strcasecmp (fileName1,
    422                      fileName2);
    423 }
    424 
    425 
    426 #ifndef BUFREADCOMMENT
    427 #define BUFREADCOMMENT (0x400)
    428 #endif
    429 
    430 
    431 /**
    432  * Locate the central directory in the ZIP file.
    433  *
    434  * @param ffd IO functions
    435  * @return offset of central directory, -1 on error
    436  */
    437 static int64_t
    438 locate_central_directory (const struct FileFuncDefs *ffd)
    439 {
    440   unsigned char buf[BUFREADCOMMENT + 4];
    441   int64_t file_size;
    442   int64_t back_read;
    443   int64_t max_back = 0xffff; /* maximum size of global comment */
    444 
    445   if (0 != ZSEEK (*ffd, 0, SEEK_END))
    446     return -1;
    447   if (0 > (file_size = ZTELL (*ffd)))
    448     return -1;
    449   if (max_back > file_size)
    450     max_back = file_size;
    451   back_read = 4;
    452   while (back_read < max_back)
    453   {
    454     size_t read_size;
    455     int64_t read_pos;
    456     int i;
    457 
    458     if (back_read + BUFREADCOMMENT > max_back)
    459       back_read = max_back;
    460     else
    461       back_read += BUFREADCOMMENT;
    462     read_pos = file_size - back_read;
    463     read_size = (size_t) (((BUFREADCOMMENT + 4) < (file_size - read_pos))
    464                           ? (BUFREADCOMMENT + 4)
    465                           : (file_size - read_pos));
    466     if (0 != ZSEEK (*ffd, read_pos, SEEK_SET))
    467       break;
    468     if (ZREAD (*ffd, buf, read_size) != read_size)
    469       break;
    470     i = (int) read_size - 3;
    471     while (i-- > 0)
    472       if ( (0x50 == (*(buf + i))) &&
    473            (0x4b == (*(buf + i + 1))) &&
    474            (0x05 == (*(buf + i + 2))) &&
    475            (0x06 == (*(buf + i + 3))) )
    476         return read_pos + i;
    477   }
    478   return -1;
    479 }
    480 
    481 
    482 /**
    483  * Translate date/time from Dos format to `struct
    484  * EXTRACTOR_UnzipDateTimeInfo` (readable more easilty)
    485  *
    486  * @param ulDosDate time in DOS format (input)
    487  * @param ptm where to write time in readable format
    488  */
    489 static void
    490 dos_date_to_tmu_date (uint32_t ulDosDate,
    491                       struct EXTRACTOR_UnzipDateTimeInfo*ptm)
    492 {
    493   uint32_t uDate;
    494 
    495   uDate = ulDosDate >> 16;
    496   ptm->tm_mday = (unsigned int) (uDate & 0x1f);
    497   ptm->tm_mon  = (unsigned int) ((((uDate) & 0x1E0) / 0x20) - 1);
    498   ptm->tm_year = (unsigned int) (((uDate & 0x0FE00) / 0x0200) + 1980);
    499   ptm->tm_hour = (unsigned int) ((ulDosDate & 0xF800) / 0x800);
    500   ptm->tm_min  = (unsigned int) ((ulDosDate & 0x7E0) / 0x20);
    501   ptm->tm_sec  = (unsigned int) (2 * (ulDosDate & 0x1f));
    502 }
    503 
    504 
    505 /**
    506  * Write info about the ZipFile in the *pglobal_info structure.
    507  * No preparation of the structure is needed.
    508  *
    509  * @param file zipfile to manipulate
    510  * @param pfile_info file information to initialize
    511  * @param pfile_info_internal internal file information to initialize
    512  * @param szFileName where to write the name of the current file
    513  * @param fileNameBufferSize number of bytes available in @a szFileName
    514  * @param extraField where to write extra data
    515  * @param extraFieldBufferSize number of bytes available in extraField
    516  * @param szComment where to write the comment on the current file
    517  * @param commentBufferSize number of bytes available in @a szComment
    518  * @return #EXTRACTOR_UNZIP_OK if there is no problem.
    519  */
    520 static int
    521 get_current_file_info (struct EXTRACTOR_UnzipFile *file,
    522                        struct EXTRACTOR_UnzipFileInfo *pfile_info,
    523                        struct UnzipFileInfoInternal *pfile_info_internal,
    524                        char *szFileName,
    525                        size_t fileNameBufferSize,
    526                        void *extraField,
    527                        size_t extraFieldBufferSize,
    528                        char *szComment,
    529                        size_t commentBufferSize)
    530 {
    531   struct EXTRACTOR_UnzipFileInfo file_info;
    532   struct UnzipFileInfoInternal file_info_internal;
    533   uint32_t uMagic;
    534   int64_t lSeek;
    535 
    536   if (NULL == file)
    537     return EXTRACTOR_UNZIP_PARAMERROR;
    538   if (0 != ZSEEK (file->z_filefunc,
    539                   (int64_t) (file->pos_in_central_dir
    540                              + file->byte_before_the_zipfile),
    541                   SEEK_SET))
    542     return EXTRACTOR_UNZIP_ERRNO;
    543 
    544   /* we check the magic */
    545   if (EXTRACTOR_UNZIP_OK !=
    546       read_uint32_from_ffd (&file->z_filefunc, &uMagic))
    547     return EXTRACTOR_UNZIP_ERRNO;
    548   if (0x02014b50 != uMagic)
    549     return EXTRACTOR_UNZIP_BADZIPFILE;
    550 
    551   if ( (EXTRACTOR_UNZIP_OK !=
    552         read_uint16_from_ffd (&file->z_filefunc,
    553                               &file_info.version)) ||
    554        (EXTRACTOR_UNZIP_OK !=
    555         read_uint16_from_ffd (&file->z_filefunc,
    556                               &file_info.version_needed)) ||
    557        (EXTRACTOR_UNZIP_OK !=
    558         read_uint16_from_ffd (&file->z_filefunc,
    559                               &file_info.flag)) ||
    560        (EXTRACTOR_UNZIP_OK !=
    561         read_uint16_from_ffd (&file->z_filefunc,
    562                               &file_info.compression_method)) ||
    563        (EXTRACTOR_UNZIP_OK !=
    564         read_uint32_from_ffd (&file->z_filefunc,
    565                               &file_info.dosDate)) )
    566     return EXTRACTOR_UNZIP_ERRNO;
    567   dos_date_to_tmu_date (file_info.dosDate,
    568                         &file_info.tmu_date);
    569   if ( (EXTRACTOR_UNZIP_OK !=
    570         read_uint32_from_ffd (&file->z_filefunc,
    571                               &file_info.crc)) ||
    572        (EXTRACTOR_UNZIP_OK !=
    573         read_uint32_from_ffd (&file->z_filefunc,
    574                               &file_info.compressed_size)) ||
    575        (EXTRACTOR_UNZIP_OK !=
    576         read_uint32_from_ffd (&file->z_filefunc,
    577                               &file_info.uncompressed_size)) ||
    578        (EXTRACTOR_UNZIP_OK !=
    579         read_uint16_from_ffd (&file->z_filefunc,
    580                               &file_info.size_filename)) ||
    581        (EXTRACTOR_UNZIP_OK !=
    582         read_uint16_from_ffd (&file->z_filefunc,
    583                               &file_info.size_file_extra)) ||
    584        (EXTRACTOR_UNZIP_OK !=
    585         read_uint16_from_ffd (&file->z_filefunc,
    586                               &file_info.size_file_comment)) ||
    587        (EXTRACTOR_UNZIP_OK !=
    588         read_uint16_from_ffd (&file->z_filefunc,
    589                               &file_info.disk_num_start)) ||
    590        (EXTRACTOR_UNZIP_OK !=
    591         read_uint16_from_ffd (&file->z_filefunc,
    592                               &file_info.internal_fa)) ||
    593        (EXTRACTOR_UNZIP_OK !=
    594         read_uint32_from_ffd (&file->z_filefunc,
    595                               &file_info.external_fa)) ||
    596        (EXTRACTOR_UNZIP_OK !=
    597         read_uint32_from_ffd (&file->z_filefunc,
    598                               &file_info_internal.offset_curfile)) )
    599     return EXTRACTOR_UNZIP_ERRNO;
    600 
    601   lSeek = file_info.size_filename;
    602   if (NULL != szFileName)
    603   {
    604     size_t uSizeRead;
    605 
    606     if (file_info.size_filename < fileNameBufferSize)
    607     {
    608       *(szFileName + file_info.size_filename) = '\0';
    609       uSizeRead = file_info.size_filename;
    610     }
    611     else
    612     {
    613       if (fileNameBufferSize > 0)
    614       {
    615         *(szFileName + fileNameBufferSize - 1) = '\0';
    616         uSizeRead = fileNameBufferSize - 1;
    617       }
    618       else
    619       {
    620         uSizeRead = 0;
    621       }
    622     }
    623     if ( (file_info.size_filename > 0) &&
    624          (fileNameBufferSize > 0) )
    625       if (uSizeRead !=
    626           ZREAD (file->z_filefunc,
    627                  szFileName,
    628                  uSizeRead))
    629         return EXTRACTOR_UNZIP_ERRNO;
    630     lSeek -= (int64_t) uSizeRead;
    631   }
    632 
    633   if (NULL != extraField)
    634   {
    635     size_t uSizeRead;
    636 
    637     if (file_info.size_file_extra<extraFieldBufferSize)
    638       uSizeRead = file_info.size_file_extra;
    639     else
    640       uSizeRead = extraFieldBufferSize;
    641 
    642     if (0 != lSeek)
    643     {
    644       if (0 !=
    645           ZSEEK (file->z_filefunc,
    646                  lSeek,
    647                  SEEK_CUR))
    648         return EXTRACTOR_UNZIP_ERRNO;
    649       lSeek = 0;
    650     }
    651     if ( (file_info.size_file_extra > 0) &&
    652          (extraFieldBufferSize > 0) &&
    653          (uSizeRead !=
    654           ZREAD (file->z_filefunc,
    655                  extraField,
    656                  uSizeRead)) )
    657       return EXTRACTOR_UNZIP_ERRNO;
    658     lSeek += (int64_t) file_info.size_file_extra - (int64_t) uSizeRead;
    659   }
    660   else
    661   {
    662     lSeek += file_info.size_file_extra;
    663   }
    664 
    665   if (NULL != szComment)
    666   {
    667     size_t uSizeRead;
    668 
    669     if (file_info.size_file_comment < commentBufferSize)
    670     {
    671       *(szComment + file_info.size_file_comment) = '\0';
    672       uSizeRead = file_info.size_file_comment;
    673     }
    674     else if (commentBufferSize > 0)
    675     {
    676       *(szComment + commentBufferSize - 1) = '\0';
    677       uSizeRead = commentBufferSize - 1;
    678     }
    679     else
    680     {
    681       /* Nothing fits, not even the terminator; without this branch
    682          `szComment[-1]` is written and `commentBufferSize - 1` wraps to
    683          ULONG_MAX.  Mirrors the guard the file name branch above has. */
    684       uSizeRead = 0;
    685     }
    686 
    687     if (0 != lSeek)
    688     {
    689       if (0 ==
    690           ZSEEK (file->z_filefunc,
    691                  lSeek,
    692                  SEEK_CUR))
    693         lSeek = 0;
    694       else
    695         return EXTRACTOR_UNZIP_ERRNO;
    696     }
    697     if ( (file_info.size_file_comment > 0) &&
    698          (commentBufferSize > 0) &&
    699          (uSizeRead !=
    700           ZREAD (file->z_filefunc,
    701                  szComment,
    702                  uSizeRead)) )
    703       return EXTRACTOR_UNZIP_ERRNO;
    704     lSeek += (int64_t) file_info.size_file_comment - (int64_t) uSizeRead;
    705   }
    706   else
    707   {
    708     lSeek += file_info.size_file_comment;
    709   }
    710 
    711   if (NULL != pfile_info)
    712     *pfile_info = file_info;
    713   if (NULL != pfile_info_internal)
    714     *pfile_info_internal = file_info_internal;
    715   return EXTRACTOR_UNZIP_OK;
    716 }
    717 
    718 
    719 /**
    720  * Set the current file of the zipfile to the first file.
    721  *
    722  * @param file zipfile to manipulate
    723  * @return UNZ_OK if there is no problem
    724  */
    725 int
    726 EXTRACTOR_common_unzip_go_to_first_file (struct EXTRACTOR_UnzipFile *file)
    727 {
    728   int err;
    729 
    730   if (NULL == file)
    731     return EXTRACTOR_UNZIP_PARAMERROR;
    732   file->pos_in_central_dir = file->offset_central_dir;
    733   file->num_file = 0;
    734   err = get_current_file_info (file,
    735                                &file->cur_file_info,
    736                                &file->cur_file_info_internal,
    737                                NULL, 0,
    738                                NULL, 0,
    739                                NULL, 0);
    740   file->current_file_ok = (EXTRACTOR_UNZIP_OK == err);
    741   return err;
    742 }
    743 
    744 
    745 /**
    746  * Open a Zip file.
    747  *
    748  * @param ffd IO functions
    749  * @return NULL on error
    750  */
    751 static struct EXTRACTOR_UnzipFile *
    752 unzip_open_using_ffd (struct FileFuncDefs *ffd)
    753 {
    754   struct EXTRACTOR_UnzipFile us;
    755   struct EXTRACTOR_UnzipFile *file;
    756   int64_t central_pos;
    757   int64_t offset_comment;
    758   uint32_t uL;
    759   uint16_t number_disk;          /* number of the current dist, used for
    760          spanning ZIP, unsupported, always 0*/
    761   uint16_t number_disk_with_CD;  /* number of the disk with central dir, used
    762          for spanning ZIP, unsupported, always 0*/
    763   uint16_t number_entry_CD;      /* total number of entries in
    764          the central dir
    765          (same than number_entry on nospan) */
    766 
    767   memset (&us, 0, sizeof(us));
    768   us.z_filefunc = *ffd;
    769   central_pos = locate_central_directory (&us.z_filefunc);
    770   if (0 > central_pos)
    771     return NULL;
    772   if (0 != ZSEEK (us.z_filefunc,
    773                   central_pos, SEEK_SET))
    774     return NULL;
    775 
    776   /* the signature, already checked */
    777   if (EXTRACTOR_UNZIP_OK !=
    778       read_uint32_from_ffd (&us.z_filefunc, &uL))
    779     return NULL;
    780 
    781   /* number of this disk */
    782   if (EXTRACTOR_UNZIP_OK !=
    783       read_uint16_from_ffd (&us.z_filefunc, &number_disk))
    784     return NULL;
    785 
    786   /* number of the disk with the start of the central directory */
    787   if (EXTRACTOR_UNZIP_OK !=
    788       read_uint16_from_ffd (&us.z_filefunc, &number_disk_with_CD))
    789     return NULL;
    790 
    791   /* total number of entries in the central dir on this disk */
    792   if (EXTRACTOR_UNZIP_OK !=
    793       read_uint16_from_ffd (&us.z_filefunc, &us.gi.number_entry))
    794     return NULL;
    795 
    796   /* total number of entries in the central dir */
    797   if (EXTRACTOR_UNZIP_OK !=
    798       read_uint16_from_ffd (&us.z_filefunc, &number_entry_CD))
    799     return NULL;
    800 
    801   if ( (number_entry_CD != us.gi.number_entry) ||
    802        (0 != number_disk_with_CD) ||
    803        (0 != number_disk) )
    804     return NULL;
    805 
    806   /* size of the central directory */
    807   if (EXTRACTOR_UNZIP_OK !=
    808       read_uint32_from_ffd (&us.z_filefunc, &us.size_central_dir))
    809     return NULL;
    810 
    811   /* offset of start of central directory with respect to the
    812      starting disk number */
    813   if (EXTRACTOR_UNZIP_OK !=
    814       read_uint32_from_ffd (&us.z_filefunc, &us.offset_central_dir))
    815     return NULL;
    816 
    817   /* zipfile comment length */
    818   if (EXTRACTOR_UNZIP_OK !=
    819       read_uint16_from_ffd (&us.z_filefunc, &us.gi.size_comment))
    820     return NULL;
    821   if (0 > (offset_comment = ZTELL (us.z_filefunc)))
    822     return NULL;
    823   us.gi.offset_comment = (uint64_t) offset_comment;
    824   if (central_pos < (int64_t) us.offset_central_dir + us.size_central_dir)
    825     return NULL;
    826 
    827   us.byte_before_the_zipfile = (uint64_t) central_pos
    828                                - ((uint64_t) us.offset_central_dir
    829                                   + us.size_central_dir);
    830   us.central_pos = (uint64_t) central_pos;
    831   us.pfile_in_zip_read = NULL;
    832   us.encrypted = 0;
    833 
    834   if (NULL == (file = malloc (sizeof(struct EXTRACTOR_UnzipFile))))
    835     return NULL;
    836   *file = us;
    837   EXTRACTOR_common_unzip_go_to_first_file (file);
    838   return file;
    839 }
    840 
    841 
    842 /**
    843  * Close the file in zip opened with #EXTRACTOR_common_unzip_open_current_file().
    844  *
    845  * @return #EXTRACTOR_UNZIP_CRCERROR if all the file was read but the CRC is not good
    846  */
    847 int
    848 EXTRACTOR_common_unzip_close_current_file (struct EXTRACTOR_UnzipFile *file)
    849 {
    850   struct FileInZipReadInfo*pfile_in_zip_read_info;
    851   int err = EXTRACTOR_UNZIP_OK;
    852 
    853   if (NULL == file)
    854     return EXTRACTOR_UNZIP_PARAMERROR;
    855   if (NULL == (pfile_in_zip_read_info = file->pfile_in_zip_read))
    856     return EXTRACTOR_UNZIP_PARAMERROR;
    857   if ( (0 == pfile_in_zip_read_info->rest_read_uncompressed) &&
    858        (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) )
    859     err = EXTRACTOR_UNZIP_CRCERROR;
    860   if (NULL != pfile_in_zip_read_info->read_buffer)
    861     free (pfile_in_zip_read_info->read_buffer);
    862   pfile_in_zip_read_info->read_buffer = NULL;
    863   if (pfile_in_zip_read_info->stream_initialised)
    864     inflateEnd (&pfile_in_zip_read_info->stream);
    865   pfile_in_zip_read_info->stream_initialised = 0;
    866   free (pfile_in_zip_read_info);
    867   file->pfile_in_zip_read = NULL;
    868   return err;
    869 }
    870 
    871 
    872 /**
    873  * Close a ZipFile.
    874  *
    875  * @param file zip file to close
    876  * @return #EXTRACTOR_UNZIP_OK if there is no problem.
    877  */
    878 int
    879 EXTRACTOR_common_unzip_close (struct EXTRACTOR_UnzipFile *file)
    880 {
    881   if (NULL == file)
    882     return EXTRACTOR_UNZIP_PARAMERROR;
    883   if (NULL != file->pfile_in_zip_read)
    884     EXTRACTOR_common_unzip_close_current_file (file);
    885   free (file);
    886   return EXTRACTOR_UNZIP_OK;
    887 }
    888 
    889 
    890 /**
    891  * Obtain the global comment from a ZIP file.
    892  *
    893  * @param file unzip file to inspect
    894  * @param comment where to copy the comment
    895  * @param comment_len maximum number of bytes available in comment
    896  * @return #EXTRACTOR_UNZIP_OK on success
    897  */
    898 int
    899 EXTRACTOR_common_unzip_get_global_comment (struct EXTRACTOR_UnzipFile *file,
    900                                            char *comment,
    901                                            size_t comment_len)
    902 {
    903   if (NULL == file)
    904     return EXTRACTOR_UNZIP_PARAMERROR;
    905   if (0 == comment_len)
    906     return EXTRACTOR_UNZIP_ERRNO; /* cannot 0-terminate, hence error */
    907   if (comment_len > file->gi.size_comment)
    908     comment_len = file->gi.size_comment + 1;
    909   if (0 !=
    910       ZSEEK (file->z_filefunc,
    911              (int64_t) file->gi.offset_comment,
    912              SEEK_SET))
    913     return EXTRACTOR_UNZIP_ERRNO;
    914   if (comment_len - 1 !=
    915       ZREAD (file->z_filefunc,
    916              comment,
    917              comment_len - 1))
    918     return EXTRACTOR_UNZIP_ERRNO;
    919   comment[comment_len - 1] = '\0';
    920   return EXTRACTOR_UNZIP_OK;
    921 }
    922 
    923 
    924 /**
    925  * Write info about the ZipFile in the *pglobal_info structure.
    926  * No preparation of the structure is needed.
    927  *
    928  * @param file zipfile to manipulate
    929  * @param pfile_info file information to initialize
    930  * @param szFileName where to write the name of the current file
    931  * @param fileNameBufferSize number of bytes available in szFileName
    932  * @param extraField where to write extra data
    933  * @param extraFieldBufferSize number of bytes available in extraField
    934  * @param szComment where to write the comment on the current file
    935  * @param commentBufferSize number of bytes available in szComment
    936  * @return #EXTRACTOR_UNZIP_OK if there is no problem.
    937  */
    938 int
    939 EXTRACTOR_common_unzip_get_current_file_info (
    940   struct EXTRACTOR_UnzipFile *file,
    941   struct EXTRACTOR_UnzipFileInfo *pfile_info,
    942   char *szFileName,
    943   size_t fileNameBufferSize,
    944   void *extraField,
    945   size_t extraFieldBufferSize,
    946   char *szComment,
    947   size_t commentBufferSize)
    948 {
    949   return get_current_file_info (file,
    950                                 pfile_info,
    951                                 NULL,
    952                                 szFileName,
    953                                 fileNameBufferSize,
    954                                 extraField,
    955                                 extraFieldBufferSize,
    956                                 szComment,
    957                                 commentBufferSize);
    958 }
    959 
    960 
    961 /**
    962  * Set the current file of the zipfile to the next file.
    963  *
    964  * @param file zipfile to manipulate
    965  * @return #EXTRACTOR_UNZIP_OK if there is no problem,
    966  *         #EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE if the actual file was the latest.
    967  */
    968 int
    969 EXTRACTOR_common_unzip_go_to_next_file (struct EXTRACTOR_UnzipFile *file)
    970 {
    971   int err;
    972 
    973   if (NULL == file)
    974     return EXTRACTOR_UNZIP_PARAMERROR;
    975   if (! file->current_file_ok)
    976     return EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE;
    977   if (file->num_file + 1 == file->gi.number_entry)
    978     return EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE;
    979   file->pos_in_central_dir += (uint64_t) SIZECENTRALDIRITEM
    980                               + file->cur_file_info.size_filename
    981                               + file->cur_file_info.size_file_extra
    982                               + file->cur_file_info.size_file_comment;
    983   file->num_file++;
    984   err = get_current_file_info (file,
    985                                &file->cur_file_info,
    986                                &file->cur_file_info_internal,
    987                                NULL, 0, NULL, 0, NULL, 0);
    988   file->current_file_ok = (EXTRACTOR_UNZIP_OK == err);
    989   return err;
    990 }
    991 
    992 
    993 /**
    994  * Try locate the file szFileName in the zipfile.
    995  *
    996  * @param file zipfile to manipulate
    997  * @param szFileName name to find
    998  * @param iCaseSensitivity, use 1 for case sensitivity (like strcmp);
    999  *        2 for no case sensitivity (like strcmpi or strcasecmp); or
   1000  *        0 for default of your operating system (like 1 on Unix, 2 on Windows)
   1001  * @return #EXTRACTOR_UNZIP_OK if the file is found. It becomes the current file.
   1002  *         #EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE if the file is not found
   1003  */
   1004 int
   1005 EXTRACTOR_common_unzip_go_find_local_file (struct EXTRACTOR_UnzipFile *file,
   1006                                            const char *szFileName,
   1007                                            int iCaseSensitivity)
   1008 {
   1009   int err;
   1010   /* We remember the 'current' position in the file so that we can jump
   1011    * back there if we fail.
   1012    */
   1013   struct EXTRACTOR_UnzipFileInfo cur_file_infoSaved;
   1014   struct UnzipFileInfoInternal cur_file_info_internalSaved;
   1015   uint32_t num_fileSaved;
   1016   uint64_t pos_in_central_dirSaved;
   1017 
   1018   if (NULL == file)
   1019     return EXTRACTOR_UNZIP_PARAMERROR;
   1020   if (strlen (szFileName) >= UNZ_MAXFILENAMEINZIP)
   1021     return EXTRACTOR_UNZIP_PARAMERROR;
   1022   if (! file->current_file_ok)
   1023     return EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE;
   1024 
   1025   /* Save the current state */
   1026   num_fileSaved = file->num_file;
   1027   pos_in_central_dirSaved = file->pos_in_central_dir;
   1028   cur_file_infoSaved = file->cur_file_info;
   1029   cur_file_info_internalSaved = file->cur_file_info_internal;
   1030   err = EXTRACTOR_common_unzip_go_to_first_file (file);
   1031 
   1032   while (EXTRACTOR_UNZIP_OK == err)
   1033   {
   1034     char szCurrentFileName[UNZ_MAXFILENAMEINZIP + 1];
   1035 
   1036     if (EXTRACTOR_UNZIP_OK !=
   1037         (err = EXTRACTOR_common_unzip_get_current_file_info (
   1038            file, NULL,
   1039            szCurrentFileName,
   1040            sizeof (szCurrentFileName)
   1041            - 1,
   1042            NULL, 0,
   1043            NULL, 0)))
   1044       break;
   1045     if (0 ==
   1046         EXTRACTOR_common_unzip_string_file_name_compare (szCurrentFileName,
   1047                                                          szFileName,
   1048                                                          iCaseSensitivity))
   1049       return EXTRACTOR_UNZIP_OK;
   1050     err = EXTRACTOR_common_unzip_go_to_next_file (file);
   1051   }
   1052 
   1053   /* We failed, so restore the state of the 'current file' to where we
   1054    * were.
   1055    */
   1056   file->num_file = num_fileSaved;
   1057   file->pos_in_central_dir = pos_in_central_dirSaved;
   1058   file->cur_file_info = cur_file_infoSaved;
   1059   file->cur_file_info_internal = cur_file_info_internalSaved;
   1060   return err;
   1061 }
   1062 
   1063 
   1064 /**
   1065  * Read bytes from the current file (must have been opened).
   1066  *
   1067  * @param buf contain buffer where data must be copied
   1068  * @param len the size of buf.
   1069  * @return the number of byte copied if some bytes are copied
   1070  *         0 if the end of file was reached
   1071  *         <0 with error code if there is an error
   1072  *        (#EXTRACTOR_UNZIP_ERRNO for IO error, or zLib error for uncompress error)
   1073  */
   1074 ssize_t
   1075 EXTRACTOR_common_unzip_read_current_file (struct EXTRACTOR_UnzipFile *file,
   1076                                           void *buf,
   1077                                           size_t len)
   1078 {
   1079   int err = EXTRACTOR_UNZIP_OK;
   1080   size_t iRead = 0;
   1081   struct FileInZipReadInfo *pfile_in_zip_read_info;
   1082 
   1083   if (NULL == file)
   1084     return EXTRACTOR_UNZIP_PARAMERROR;
   1085   if (NULL == (pfile_in_zip_read_info = file->pfile_in_zip_read))
   1086     return EXTRACTOR_UNZIP_PARAMERROR;
   1087   if (NULL == pfile_in_zip_read_info->read_buffer)
   1088     return EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE;
   1089   if (0 == len)
   1090     return 0;
   1091 
   1092   pfile_in_zip_read_info->stream.next_out = (Bytef *) buf;
   1093   pfile_in_zip_read_info->stream.avail_out = (uInt) len;
   1094   if (len > pfile_in_zip_read_info->rest_read_uncompressed)
   1095     pfile_in_zip_read_info->stream.avail_out =
   1096       (uInt) pfile_in_zip_read_info->rest_read_uncompressed;
   1097 
   1098   while (pfile_in_zip_read_info->stream.avail_out > 0)
   1099   {
   1100     if ( (0 == pfile_in_zip_read_info->stream.avail_in) &&
   1101          (pfile_in_zip_read_info->rest_read_compressed > 0) )
   1102     {
   1103       uInt uReadThis = UNZ_BUFSIZE;
   1104       if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
   1105         uReadThis = (uInt) pfile_in_zip_read_info->rest_read_compressed;
   1106       if (0 == uReadThis)
   1107         return EXTRACTOR_UNZIP_EOF;
   1108       if (0 !=
   1109           ZSEEK (pfile_in_zip_read_info->z_filefunc,
   1110                  (int64_t) (pfile_in_zip_read_info->pos_in_zipfile
   1111                             + pfile_in_zip_read_info->byte_before_the_zipfile),
   1112                  SEEK_SET))
   1113         return EXTRACTOR_UNZIP_ERRNO;
   1114       if (ZREAD (pfile_in_zip_read_info->z_filefunc,
   1115                  pfile_in_zip_read_info->read_buffer,
   1116                  uReadThis) != uReadThis)
   1117         return EXTRACTOR_UNZIP_ERRNO;
   1118 
   1119       pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
   1120       pfile_in_zip_read_info->rest_read_compressed -= (uint32_t) uReadThis;
   1121       pfile_in_zip_read_info->stream.next_in =
   1122         (Bytef *) pfile_in_zip_read_info->read_buffer;
   1123       pfile_in_zip_read_info->stream.avail_in = (uInt) uReadThis;
   1124     }
   1125 
   1126     if (0 == pfile_in_zip_read_info->compression_method)
   1127     {
   1128       uInt uDoCopy;
   1129 
   1130       if ( (0 == pfile_in_zip_read_info->stream.avail_in) &&
   1131            (0 == pfile_in_zip_read_info->rest_read_compressed) )
   1132         return (0 == iRead) ? EXTRACTOR_UNZIP_EOF : (ssize_t) iRead;
   1133 
   1134       if (pfile_in_zip_read_info->stream.avail_out <
   1135           pfile_in_zip_read_info->stream.avail_in)
   1136         uDoCopy = pfile_in_zip_read_info->stream.avail_out;
   1137       else
   1138         uDoCopy = pfile_in_zip_read_info->stream.avail_in;
   1139       memcpy (pfile_in_zip_read_info->stream.next_out,
   1140               pfile_in_zip_read_info->stream.next_in,
   1141               uDoCopy);
   1142       pfile_in_zip_read_info->crc32 =
   1143         (uint32_t) crc32 (pfile_in_zip_read_info->crc32,
   1144                           pfile_in_zip_read_info->stream.next_out,
   1145                           uDoCopy);
   1146       pfile_in_zip_read_info->rest_read_uncompressed -= (uint32_t) uDoCopy;
   1147       pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
   1148       pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
   1149       pfile_in_zip_read_info->stream.next_out += uDoCopy;
   1150       pfile_in_zip_read_info->stream.next_in += uDoCopy;
   1151       pfile_in_zip_read_info->stream.total_out += uDoCopy;
   1152       iRead += uDoCopy;
   1153     }
   1154     else
   1155     {
   1156       uLong uTotalOutBefore;
   1157       uLong uTotalOutAfter;
   1158       const Bytef *bufBefore;
   1159       uLong uOutThis;
   1160       int flush = Z_SYNC_FLUSH;
   1161 
   1162       uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
   1163       bufBefore = pfile_in_zip_read_info->stream.next_out;
   1164 
   1165       /*
   1166         if ((pfile_in_zip_read_info->rest_read_uncompressed ==
   1167         pfile_in_zip_read_info->stream.avail_out) &&
   1168         (pfile_in_zip_read_info->rest_read_compressed == 0))
   1169         flush = Z_FINISH;
   1170       */err = inflate (&pfile_in_zip_read_info->stream, flush);
   1171 
   1172       uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
   1173       uOutThis = uTotalOutAfter - uTotalOutBefore;
   1174 
   1175       pfile_in_zip_read_info->crc32 =
   1176         (uint32_t) crc32 (pfile_in_zip_read_info->crc32, bufBefore,
   1177                           (uInt) (uOutThis));
   1178 
   1179       pfile_in_zip_read_info->rest_read_uncompressed -=
   1180         (uint32_t) uOutThis;
   1181 
   1182       iRead += (size_t) (uTotalOutAfter - uTotalOutBefore);
   1183 
   1184       if (Z_STREAM_END == err)
   1185         return (0 == iRead) ? EXTRACTOR_UNZIP_EOF : (ssize_t) iRead;
   1186       if (Z_OK != err)
   1187         break;
   1188     }
   1189   }
   1190 
   1191   if (Z_OK == err)
   1192     return (ssize_t) iRead;
   1193   return err;
   1194 }
   1195 
   1196 
   1197 /**
   1198  * Read the local header of the current zipfile. Check the coherency of
   1199  * the local header and info in the end of central directory about
   1200  * this file. Store in *piSizeVar the size of extra info in local
   1201  * header (filename and size of extra field data)
   1202  *
   1203  * @param file zipfile to process
   1204  * @param piSizeVar where to store the size of the extra info
   1205  * @param poffset_local_extrafield where to store the offset of the local extrafield
   1206  * @param psoze_local_extrafield where to store the size of the local extrafield
   1207  * @return #EXTRACTOR_UNZIP_OK on success
   1208  */
   1209 static int
   1210 parse_current_file_coherency_header (struct EXTRACTOR_UnzipFile *file,
   1211                                      uint32_t *piSizeVar,
   1212                                      uint64_t *poffset_local_extrafield,
   1213                                      uint16_t *psize_local_extrafield)
   1214 {
   1215   uint32_t uMagic;
   1216   uint16_t u16;
   1217   uint32_t u32;
   1218   uint16_t uFlags;
   1219   uint16_t size_filename;
   1220   uint16_t size_extra_field;
   1221 
   1222   *piSizeVar = 0;
   1223   *poffset_local_extrafield = 0;
   1224   *psize_local_extrafield = 0;
   1225 
   1226   if (0 != ZSEEK (file->z_filefunc,
   1227                   (int64_t) (file->cur_file_info_internal.offset_curfile
   1228                              + file->byte_before_the_zipfile),
   1229                   SEEK_SET))
   1230     return EXTRACTOR_UNZIP_ERRNO;
   1231   if (EXTRACTOR_UNZIP_OK !=
   1232       read_uint32_from_ffd (&file->z_filefunc,
   1233                             &uMagic))
   1234     return EXTRACTOR_UNZIP_ERRNO;
   1235   if (0x04034b50 != uMagic)
   1236     return EXTRACTOR_UNZIP_BADZIPFILE;
   1237   if ( (EXTRACTOR_UNZIP_OK !=
   1238         read_uint16_from_ffd (&file->z_filefunc, &u16)) ||  /* version */
   1239        (EXTRACTOR_UNZIP_OK !=
   1240         read_uint16_from_ffd (&file->z_filefunc, &uFlags)) )
   1241     return EXTRACTOR_UNZIP_ERRNO;
   1242   if (EXTRACTOR_UNZIP_OK != read_uint16_from_ffd (&file->z_filefunc, &u16))
   1243     return EXTRACTOR_UNZIP_ERRNO;
   1244   if (u16 != file->cur_file_info.compression_method)
   1245     return EXTRACTOR_UNZIP_BADZIPFILE;
   1246   if ( (0 != file->cur_file_info.compression_method) &&
   1247        (Z_DEFLATED != file->cur_file_info.compression_method) )
   1248     return EXTRACTOR_UNZIP_BADZIPFILE;
   1249   if (EXTRACTOR_UNZIP_OK !=
   1250       read_uint32_from_ffd (&file->z_filefunc, &u32)) /* date/time */
   1251     return EXTRACTOR_UNZIP_ERRNO;
   1252   if (EXTRACTOR_UNZIP_OK !=
   1253       read_uint32_from_ffd (&file->z_filefunc, &u32)) /* crc */
   1254     return EXTRACTOR_UNZIP_ERRNO;
   1255   if ( (u32 != file->cur_file_info.crc) &&
   1256        (0 == (uFlags & 8)) )
   1257     return EXTRACTOR_UNZIP_BADZIPFILE;
   1258   if (EXTRACTOR_UNZIP_OK !=
   1259       read_uint32_from_ffd (&file->z_filefunc, &u32)) /* size compr */
   1260     return EXTRACTOR_UNZIP_ERRNO;
   1261   if ( (u32 != file->cur_file_info.compressed_size) &&
   1262        (0 == (uFlags & 8)) )
   1263     return EXTRACTOR_UNZIP_BADZIPFILE;
   1264   if (EXTRACTOR_UNZIP_OK !=
   1265       read_uint32_from_ffd (&file->z_filefunc,
   1266                             &u32)) /* size uncompr */
   1267     return EXTRACTOR_UNZIP_ERRNO;
   1268   if ( (u32 != file->cur_file_info.uncompressed_size) &&
   1269        (0 == (uFlags & 8)))
   1270     return EXTRACTOR_UNZIP_BADZIPFILE;
   1271   if (EXTRACTOR_UNZIP_OK !=
   1272       read_uint16_from_ffd (&file->z_filefunc, &size_filename))
   1273     return EXTRACTOR_UNZIP_ERRNO;
   1274   if (size_filename != file->cur_file_info.size_filename)
   1275     return EXTRACTOR_UNZIP_BADZIPFILE;
   1276   *piSizeVar += size_filename;
   1277   if (EXTRACTOR_UNZIP_OK !=
   1278       read_uint16_from_ffd (&file->z_filefunc,
   1279                             &size_extra_field))
   1280     return EXTRACTOR_UNZIP_ERRNO;
   1281   *poffset_local_extrafield = (uint64_t) file->cur_file_info_internal.
   1282                               offset_curfile
   1283                               + SIZEZIPLOCALHEADER + size_filename;
   1284   *psize_local_extrafield = size_extra_field;
   1285   *piSizeVar += size_extra_field;
   1286 
   1287   return EXTRACTOR_UNZIP_OK;
   1288 }
   1289 
   1290 
   1291 /**
   1292  * Open for reading data the current file in the zipfile.
   1293  *
   1294  * @param file zipfile to manipulate
   1295  * @return #EXTRACTOR_UNZIP_OK on success
   1296  */
   1297 int
   1298 EXTRACTOR_common_unzip_open_current_file (struct EXTRACTOR_UnzipFile *file)
   1299 {
   1300   int err;
   1301   uint32_t iSizeVar;
   1302   struct FileInZipReadInfo *pfile_in_zip_read_info;
   1303   uint64_t offset_local_extrafield;  /* offset of the local extra field */
   1304   uint16_t size_local_extrafield;    /* size of the local extra field */
   1305 
   1306   if (NULL == file)
   1307     return EXTRACTOR_UNZIP_PARAMERROR;
   1308   if (! file->current_file_ok)
   1309     return EXTRACTOR_UNZIP_PARAMERROR;
   1310   if (NULL != file->pfile_in_zip_read)
   1311     EXTRACTOR_common_unzip_close_current_file (file);
   1312   if (EXTRACTOR_UNZIP_OK !=
   1313       parse_current_file_coherency_header (file,
   1314                                            &iSizeVar,
   1315                                            &offset_local_extrafield,
   1316                                            &size_local_extrafield))
   1317     return EXTRACTOR_UNZIP_BADZIPFILE;
   1318   if (NULL == (pfile_in_zip_read_info
   1319                  = malloc (sizeof(struct FileInZipReadInfo))))
   1320     return EXTRACTOR_UNZIP_INTERNALERROR;
   1321   if (NULL == (pfile_in_zip_read_info->read_buffer = malloc (UNZ_BUFSIZE)))
   1322   {
   1323     free (pfile_in_zip_read_info);
   1324     return EXTRACTOR_UNZIP_INTERNALERROR;
   1325   }
   1326   pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
   1327   pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
   1328   pfile_in_zip_read_info->pos_local_extrafield = 0;
   1329   pfile_in_zip_read_info->stream_initialised = 0;
   1330 
   1331   if ( (0 != file->cur_file_info.compression_method) &&
   1332        (Z_DEFLATED != file->cur_file_info.compression_method) )
   1333   {
   1334     // err = EXTRACTOR_UNZIP_BADZIPFILE;
   1335     // FIXME: we don't do anything with this 'err' code.
   1336     // Can this happen? Should we abort in this case?
   1337   }
   1338 
   1339   pfile_in_zip_read_info->crc32_wait = file->cur_file_info.crc;
   1340   pfile_in_zip_read_info->crc32 = 0;
   1341   pfile_in_zip_read_info->compression_method =
   1342     file->cur_file_info.compression_method;
   1343   pfile_in_zip_read_info->z_filefunc = file->z_filefunc;
   1344   pfile_in_zip_read_info->byte_before_the_zipfile =
   1345     file->byte_before_the_zipfile;
   1346   pfile_in_zip_read_info->stream.total_out = 0;
   1347   if (Z_DEFLATED == file->cur_file_info.compression_method)
   1348   {
   1349     pfile_in_zip_read_info->stream.zalloc = (alloc_func) NULL;
   1350     pfile_in_zip_read_info->stream.zfree = (free_func) NULL;
   1351     pfile_in_zip_read_info->stream.opaque = NULL;
   1352     pfile_in_zip_read_info->stream.next_in = NULL;
   1353     pfile_in_zip_read_info->stream.avail_in = 0;
   1354     if (Z_OK != (err = inflateInit2 (&pfile_in_zip_read_info->stream,
   1355                                      -MAX_WBITS)))
   1356     {
   1357       free (pfile_in_zip_read_info->read_buffer);
   1358       free (pfile_in_zip_read_info);
   1359       return err;
   1360     }
   1361     pfile_in_zip_read_info->stream_initialised = 1;
   1362     /* windowBits is passed < 0 to tell that there is no zlib header.
   1363      * Note that in this case inflate *requires* an extra "dummy" byte
   1364      * after the compressed stream in order to complete decompression and
   1365      * return Z_STREAM_END.
   1366      * In unzip, i don't wait absolutely Z_STREAM_END because I known the
   1367      * size of both compressed and uncompressed data
   1368      */}
   1369   pfile_in_zip_read_info->rest_read_compressed =
   1370     file->cur_file_info.compressed_size;
   1371   pfile_in_zip_read_info->rest_read_uncompressed =
   1372     file->cur_file_info.uncompressed_size;
   1373   pfile_in_zip_read_info->pos_in_zipfile =
   1374     file->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER
   1375     + iSizeVar;
   1376   pfile_in_zip_read_info->stream.avail_in = 0;
   1377   file->pfile_in_zip_read = pfile_in_zip_read_info;
   1378   return EXTRACTOR_UNZIP_OK;
   1379 }
   1380 
   1381 
   1382 /**
   1383  * Callback to perform read operation using LE API.
   1384  * Note that partial reads are not allowed.
   1385  *
   1386  * @param opaque the 'struct EXTRACTOR_ExtractContext'
   1387  * @param buf where to write bytes read
   1388  * @param size number of bytes desired
   1389  * @return number of bytes copied to buf
   1390  */
   1391 static size_t
   1392 ec_read_file_func (void *opaque,
   1393                    void *buf,
   1394                    size_t size)
   1395 {
   1396   struct EXTRACTOR_ExtractContext *ec = opaque;
   1397   void *ptr;
   1398   ssize_t ret;
   1399   size_t done;
   1400 
   1401   done = 0;
   1402   while (done < size)
   1403   {
   1404     ret = ec->read (ec->cls,
   1405                     &ptr,
   1406                     size - done);
   1407     if (ret <= 0)
   1408       return done;
   1409     /* the contract says a read never returns more than was asked for,
   1410        but this is the memcpy() that would run off the end of @a buf if
   1411        some data source ever got that wrong */
   1412     if ((size_t) ret > size - done)
   1413       ret = (ssize_t) (size - done);
   1414     memcpy ((char *) buf + done,
   1415             ptr,
   1416             (size_t) ret);
   1417     done += (size_t) ret;
   1418   }
   1419   return done;
   1420 }
   1421 
   1422 
   1423 /**
   1424  * Callback to obtain current offset in file using LE API.
   1425  *
   1426  * @param opaque the 'struct EXTRACTOR_ExtractContext'
   1427  * @return current offset in file, -1 on error
   1428  */
   1429 static int64_t
   1430 ec_tell_file_func (void *opaque)
   1431 {
   1432   struct EXTRACTOR_ExtractContext *ec = opaque;
   1433 
   1434   return ec->seek (ec->cls,
   1435                    0,
   1436                    SEEK_CUR);
   1437 }
   1438 
   1439 
   1440 /**
   1441  * Callback to perform seek operation using LE API.
   1442  *
   1443  * @param opaque the 'struct EXTRACTOR_ExtractContext'
   1444  * @param offset where to seek
   1445  * @param whence relative to where should we seek
   1446  * @return #EXTRACTOR_UNZIP_OK on success
   1447  */
   1448 static int
   1449 ec_seek_file_func (void *opaque,
   1450                    int64_t offset,
   1451                    int whence)
   1452 {
   1453   struct EXTRACTOR_ExtractContext *ec = opaque;
   1454 
   1455   if (-1 == ec->seek (ec->cls, offset, whence))
   1456     return EXTRACTOR_UNZIP_INTERNALERROR;
   1457   return EXTRACTOR_UNZIP_OK;
   1458 }
   1459 
   1460 
   1461 /**
   1462  * Open a zip file for processing using the data access
   1463  * functions from the extract context.
   1464  *
   1465  * @param ec extract context to use
   1466  * @return handle to zip data, NULL on error
   1467  */
   1468 struct EXTRACTOR_UnzipFile *
   1469 EXTRACTOR_common_unzip_open (struct EXTRACTOR_ExtractContext *ec)
   1470 {
   1471   struct FileFuncDefs ffd;
   1472 
   1473   ffd.zread_file = &ec_read_file_func;
   1474   ffd.ztell_file = &ec_tell_file_func;
   1475   ffd.zseek_file = &ec_seek_file_func;
   1476   ffd.opaque = ec;
   1477 
   1478   return unzip_open_using_ffd (&ffd);
   1479 }
   1480 
   1481 
   1482 /* end of unzip.c */