libextractor

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

unzip.c (44558B)


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