libextractor

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

unzip.c (44242B)


      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 = 0;
    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, &file_info.version)) ||
    578        (EXTRACTOR_UNZIP_OK !=
    579         read_short_from_ffd (&file->z_filefunc, &file_info.version_needed)) ||
    580        (EXTRACTOR_UNZIP_OK !=
    581         read_short_from_ffd (&file->z_filefunc, &file_info.flag)) ||
    582        (EXTRACTOR_UNZIP_OK !=
    583         read_short_from_ffd (&file->z_filefunc,
    584                              &file_info.compression_method)) ||
    585        (EXTRACTOR_UNZIP_OK !=
    586         read_long_from_ffd (&file->z_filefunc, &file_info.dosDate)) )
    587     return EXTRACTOR_UNZIP_ERRNO;
    588   dos_date_to_tmu_date (file_info.dosDate,
    589                         &file_info.tmu_date);
    590   if ( (EXTRACTOR_UNZIP_OK !=
    591         read_long_from_ffd (&file->z_filefunc, &file_info.crc)) ||
    592        (EXTRACTOR_UNZIP_OK !=
    593         read_long_from_ffd (&file->z_filefunc, &file_info.compressed_size)) ||
    594        (EXTRACTOR_UNZIP_OK !=
    595         read_long_from_ffd (&file->z_filefunc, &file_info.uncompressed_size)) ||
    596        (EXTRACTOR_UNZIP_OK !=
    597         read_short_from_ffd (&file->z_filefunc, &file_info.size_filename)) ||
    598        (EXTRACTOR_UNZIP_OK !=
    599         read_short_from_ffd (&file->z_filefunc, &file_info.size_file_extra)) ||
    600        (EXTRACTOR_UNZIP_OK !=
    601         read_short_from_ffd (&file->z_filefunc,
    602                              &file_info.size_file_comment)) ||
    603        (EXTRACTOR_UNZIP_OK !=
    604         read_short_from_ffd (&file->z_filefunc, &file_info.disk_num_start)) ||
    605        (EXTRACTOR_UNZIP_OK !=
    606         read_short_from_ffd (&file->z_filefunc, &file_info.internal_fa)) ||
    607        (EXTRACTOR_UNZIP_OK !=
    608         read_long_from_ffd (&file->z_filefunc, &file_info.external_fa)) ||
    609        (EXTRACTOR_UNZIP_OK !=
    610         read_long_from_ffd (&file->z_filefunc,
    611                             &file_info_internal.offset_curfile)) )
    612     return EXTRACTOR_UNZIP_ERRNO;
    613 
    614   lSeek += file_info.size_filename;
    615   if (NULL != szFileName)
    616   {
    617     uLong uSizeRead;
    618 
    619     if (file_info.size_filename < fileNameBufferSize)
    620     {
    621       *(szFileName + file_info.size_filename) = '\0';
    622       uSizeRead = file_info.size_filename;
    623     }
    624     else
    625       uSizeRead = fileNameBufferSize;
    626 
    627     if ( (file_info.size_filename > 0) &&
    628          (fileNameBufferSize > 0) )
    629       if (ZREAD (file->z_filefunc, szFileName, uSizeRead) != uSizeRead)
    630         return EXTRACTOR_UNZIP_ERRNO;
    631     lSeek -= uSizeRead;
    632   }
    633 
    634   if (NULL != extraField)
    635   {
    636     uLong uSizeRead;
    637 
    638     if (file_info.size_file_extra<extraFieldBufferSize)
    639       uSizeRead = file_info.size_file_extra;
    640     else
    641       uSizeRead = extraFieldBufferSize;
    642 
    643     if (0 != lSeek)
    644     {
    645       if (0 == ZSEEK (file->z_filefunc, lSeek, SEEK_CUR))
    646         lSeek = 0;
    647       else
    648         return EXTRACTOR_UNZIP_ERRNO;
    649     }
    650     if ( (file_info.size_file_extra > 0) &&
    651          (extraFieldBufferSize > 0) &&
    652          (ZREAD (file->z_filefunc,
    653                  extraField,
    654                  uSizeRead) != uSizeRead) )
    655       return EXTRACTOR_UNZIP_ERRNO;
    656     lSeek += file_info.size_file_extra - uSizeRead;
    657   }
    658   else
    659     lSeek += file_info.size_file_extra;
    660 
    661   if (NULL != szComment)
    662   {
    663     uLong uSizeRead;
    664 
    665     if (file_info.size_file_comment < commentBufferSize)
    666     {
    667       *(szComment + file_info.size_file_comment) = '\0';
    668       uSizeRead = file_info.size_file_comment;
    669     }
    670     else
    671     {
    672       *(szComment + commentBufferSize - 1) = '\0';
    673       uSizeRead = commentBufferSize - 1;
    674     }
    675 
    676     if (0 != lSeek)
    677     {
    678       if (0 == ZSEEK (file->z_filefunc, lSeek, SEEK_CUR))
    679         lSeek = 0;
    680       else
    681         return EXTRACTOR_UNZIP_ERRNO;
    682     }
    683     if ( (file_info.size_file_comment > 0) &&
    684          (commentBufferSize > 0) &&
    685          (ZREAD (file->z_filefunc, szComment, uSizeRead) != uSizeRead) )
    686       return EXTRACTOR_UNZIP_ERRNO;
    687     lSeek += file_info.size_file_comment - uSizeRead;
    688   }
    689   else
    690     lSeek += file_info.size_file_comment;
    691 
    692   if (NULL != pfile_info)
    693     *pfile_info = file_info;
    694   if (NULL != pfile_info_internal)
    695     *pfile_info_internal = file_info_internal;
    696   return EXTRACTOR_UNZIP_OK;
    697 }
    698 
    699 
    700 /**
    701  * Set the current file of the zipfile to the first file.
    702  *
    703  * @param file zipfile to manipulate
    704  * @return UNZ_OK if there is no problem
    705  */
    706 int
    707 EXTRACTOR_common_unzip_go_to_first_file (struct EXTRACTOR_UnzipFile *file)
    708 {
    709   int err;
    710 
    711   if (NULL == file)
    712     return EXTRACTOR_UNZIP_PARAMERROR;
    713   file->pos_in_central_dir = file->offset_central_dir;
    714   file->num_file = 0;
    715   err = get_current_file_info (file,
    716                                &file->cur_file_info,
    717                                &file->cur_file_info_internal,
    718                                NULL, 0, NULL, 0, NULL, 0);
    719   file->current_file_ok = (EXTRACTOR_UNZIP_OK == err);
    720   return err;
    721 }
    722 
    723 
    724 /**
    725  * Open a Zip file.
    726  *
    727  * @param ffd IO functions
    728  * @return NULL on error
    729  */
    730 static struct EXTRACTOR_UnzipFile *
    731 unzip_open_using_ffd (struct FileFuncDefs *ffd)
    732 {
    733   struct EXTRACTOR_UnzipFile us;
    734   struct EXTRACTOR_UnzipFile *file;
    735   uLong central_pos;
    736   uLong uL;
    737   uLong number_disk;          /* number of the current dist, used for
    738          spanning ZIP, unsupported, always 0*/
    739   uLong number_disk_with_CD;  /* number of the disk with central dir, used
    740          for spanning ZIP, unsupported, always 0*/
    741   uLong number_entry_CD;      /* total number of entries in
    742          the central dir
    743          (same than number_entry on nospan) */
    744 
    745   memset (&us, 0, sizeof(us));
    746   us.z_filefunc = *ffd;
    747   central_pos = locate_central_directory (&us.z_filefunc);
    748   if (0 == central_pos)
    749     return NULL;
    750   if (0 != ZSEEK (us.z_filefunc,
    751                   central_pos, SEEK_SET))
    752     return NULL;
    753 
    754   /* the signature, already checked */
    755   if (EXTRACTOR_UNZIP_OK !=
    756       read_long_from_ffd (&us.z_filefunc, &uL))
    757     return NULL;
    758 
    759   /* number of this disk */
    760   if (EXTRACTOR_UNZIP_OK !=
    761       read_short_from_ffd (&us.z_filefunc, &number_disk))
    762     return NULL;
    763 
    764   /* number of the disk with the start of the central directory */
    765   if (EXTRACTOR_UNZIP_OK !=
    766       read_short_from_ffd (&us.z_filefunc, &number_disk_with_CD))
    767     return NULL;
    768 
    769   /* total number of entries in the central dir on this disk */
    770   if (EXTRACTOR_UNZIP_OK !=
    771       read_short_from_ffd (&us.z_filefunc, &us.gi.number_entry))
    772     return NULL;
    773 
    774   /* total number of entries in the central dir */
    775   if (EXTRACTOR_UNZIP_OK !=
    776       read_short_from_ffd (&us.z_filefunc, &number_entry_CD))
    777     return NULL;
    778 
    779   if ( (number_entry_CD != us.gi.number_entry) ||
    780        (0 != number_disk_with_CD) ||
    781        (0 != number_disk) )
    782     return NULL;
    783 
    784   /* size of the central directory */
    785   if (EXTRACTOR_UNZIP_OK !=
    786       read_long_from_ffd (&us.z_filefunc, &us.size_central_dir))
    787     return NULL;
    788 
    789   /* offset of start of central directory with respect to the
    790      starting disk number */
    791   if (EXTRACTOR_UNZIP_OK !=
    792       read_long_from_ffd (&us.z_filefunc, &us.offset_central_dir))
    793     return NULL;
    794 
    795   /* zipfile comment length */
    796   if (EXTRACTOR_UNZIP_OK !=
    797       read_short_from_ffd (&us.z_filefunc, &us.gi.size_comment))
    798     return NULL;
    799   us.gi.offset_comment = ZTELL (us.z_filefunc);
    800   if ((central_pos < us.offset_central_dir + us.size_central_dir))
    801     return NULL;
    802 
    803   us.byte_before_the_zipfile = central_pos
    804                                - (us.offset_central_dir + us.size_central_dir);
    805   us.central_pos = central_pos;
    806   us.pfile_in_zip_read = NULL;
    807   us.encrypted = 0;
    808 
    809   if (NULL == (file = malloc (sizeof(struct EXTRACTOR_UnzipFile))))
    810     return NULL;
    811   *file = us;
    812   EXTRACTOR_common_unzip_go_to_first_file (file);
    813   return file;
    814 }
    815 
    816 
    817 /**
    818  * Close the file in zip opened with #EXTRACTOR_common_unzip_open_current_file().
    819  *
    820  * @return #EXTRACTOR_UNZIP_CRCERROR if all the file was read but the CRC is not good
    821  */
    822 int
    823 EXTRACTOR_common_unzip_close_current_file (struct EXTRACTOR_UnzipFile *file)
    824 {
    825   struct FileInZipReadInfo*pfile_in_zip_read_info;
    826   int err = EXTRACTOR_UNZIP_OK;
    827 
    828   if (NULL == file)
    829     return EXTRACTOR_UNZIP_PARAMERROR;
    830   if (NULL == (pfile_in_zip_read_info = file->pfile_in_zip_read))
    831     return EXTRACTOR_UNZIP_PARAMERROR;
    832   if ( (0 == pfile_in_zip_read_info->rest_read_uncompressed) &&
    833        (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) )
    834     err = EXTRACTOR_UNZIP_CRCERROR;
    835   if (NULL != pfile_in_zip_read_info->read_buffer)
    836     free (pfile_in_zip_read_info->read_buffer);
    837   pfile_in_zip_read_info->read_buffer = NULL;
    838   if (pfile_in_zip_read_info->stream_initialised)
    839     inflateEnd (&pfile_in_zip_read_info->stream);
    840   pfile_in_zip_read_info->stream_initialised = 0;
    841   free (pfile_in_zip_read_info);
    842   file->pfile_in_zip_read = NULL;
    843   return err;
    844 }
    845 
    846 
    847 /**
    848  * Close a ZipFile.
    849  *
    850  * @param file zip file to close
    851  * @return #EXTRACTOR_UNZIP_OK if there is no problem.
    852  */
    853 int
    854 EXTRACTOR_common_unzip_close (struct EXTRACTOR_UnzipFile *file)
    855 {
    856   if (NULL == file)
    857     return EXTRACTOR_UNZIP_PARAMERROR;
    858   if (NULL != file->pfile_in_zip_read)
    859     EXTRACTOR_common_unzip_close_current_file (file);
    860   free (file);
    861   return EXTRACTOR_UNZIP_OK;
    862 }
    863 
    864 
    865 /**
    866  * Obtain the global comment from a ZIP file.
    867  *
    868  * @param file unzip file to inspect
    869  * @param comment where to copy the comment
    870  * @param comment_len maximum number of bytes available in comment
    871  * @return #EXTRACTOR_UNZIP_OK on success
    872  */
    873 int
    874 EXTRACTOR_common_unzip_get_global_comment (struct EXTRACTOR_UnzipFile *file,
    875                                            char *comment,
    876                                            size_t comment_len)
    877 {
    878   if (NULL == file)
    879     return EXTRACTOR_UNZIP_PARAMERROR;
    880   if (comment_len > file->gi.size_comment)
    881     comment_len = file->gi.size_comment + 1;
    882   if (0 !=
    883       ZSEEK (file->z_filefunc, file->gi.offset_comment, SEEK_SET))
    884     return EXTRACTOR_UNZIP_ERRNO;
    885   if (comment_len - 1 !=
    886       ZREAD (file->z_filefunc, comment, comment_len - 1))
    887     return EXTRACTOR_UNZIP_ERRNO;
    888   comment[comment_len - 1] = '\0';
    889   return EXTRACTOR_UNZIP_OK;
    890 }
    891 
    892 
    893 /**
    894  * Write info about the ZipFile in the *pglobal_info structure.
    895  * No preparation of the structure is needed.
    896  *
    897  * @param file zipfile to manipulate
    898  * @param pfile_info file information to initialize
    899  * @param szFileName where to write the name of the current file
    900  * @param fileNameBufferSize number of bytes available in szFileName
    901  * @param extraField where to write extra data
    902  * @param extraFieldBufferSize number of bytes available in extraField
    903  * @param szComment where to write the comment on the current file
    904  * @param commentBufferSize number of bytes available in szComment
    905  * @return #EXTRACTOR_UNZIP_OK if there is no problem.
    906  */
    907 int
    908 EXTRACTOR_common_unzip_get_current_file_info (struct EXTRACTOR_UnzipFile *file,
    909                                               struct EXTRACTOR_UnzipFileInfo *
    910                                               pfile_info,
    911                                               char *szFileName,
    912                                               uLong fileNameBufferSize,
    913                                               void *extraField,
    914                                               uLong extraFieldBufferSize,
    915                                               char *szComment,
    916                                               uLong commentBufferSize)
    917 {
    918   return get_current_file_info (file, pfile_info, NULL,
    919                                 szFileName, fileNameBufferSize,
    920                                 extraField, extraFieldBufferSize,
    921                                 szComment, commentBufferSize);
    922 }
    923 
    924 
    925 /**
    926  * Set the current file of the zipfile to the next file.
    927  *
    928  * @param file zipfile to manipulate
    929  * @return #EXTRACTOR_UNZIP_OK if there is no problem,
    930  *         #EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE if the actual file was the latest.
    931  */
    932 int
    933 EXTRACTOR_common_unzip_go_to_next_file (struct EXTRACTOR_UnzipFile *file)
    934 {
    935   int err;
    936 
    937   if (NULL == file)
    938     return EXTRACTOR_UNZIP_PARAMERROR;
    939   if (! file->current_file_ok)
    940     return EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE;
    941   if (file->num_file + 1 == file->gi.number_entry)
    942     return EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE;
    943   file->pos_in_central_dir += SIZECENTRALDIRITEM
    944                               + file->cur_file_info.size_filename
    945                               + file->cur_file_info.size_file_extra
    946                               + file->cur_file_info.size_file_comment;
    947   file->num_file++;
    948   err = get_current_file_info (file,
    949                                &file->cur_file_info,
    950                                &file->cur_file_info_internal,
    951                                NULL, 0, NULL, 0, NULL, 0);
    952   file->current_file_ok = (EXTRACTOR_UNZIP_OK == err);
    953   return err;
    954 }
    955 
    956 
    957 /**
    958  * Try locate the file szFileName in the zipfile.
    959  *
    960  * @param file zipfile to manipulate
    961  * @param szFileName name to find
    962  * @param iCaseSensitivity, use 1 for case sensitivity (like strcmp);
    963  *        2 for no case sensitivity (like strcmpi or strcasecmp); or
    964  *        0 for default of your operating system (like 1 on Unix, 2 on Windows)
    965  * @return #EXTRACTOR_UNZIP_OK if the file is found. It becomes the current file.
    966  *         #EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE if the file is not found
    967  */
    968 int
    969 EXTRACTOR_common_unzip_go_find_local_file (struct EXTRACTOR_UnzipFile *file,
    970                                            const char *szFileName,
    971                                            int iCaseSensitivity)
    972 {
    973   int err;
    974   /* We remember the 'current' position in the file so that we can jump
    975    * back there if we fail.
    976    */
    977   struct EXTRACTOR_UnzipFileInfo cur_file_infoSaved;
    978   struct UnzipFileInfoInternal cur_file_info_internalSaved;
    979   uLong num_fileSaved;
    980   uLong pos_in_central_dirSaved;
    981 
    982   if (NULL == file)
    983     return EXTRACTOR_UNZIP_PARAMERROR;
    984   if (strlen (szFileName) >= UNZ_MAXFILENAMEINZIP)
    985     return EXTRACTOR_UNZIP_PARAMERROR;
    986   if (! file->current_file_ok)
    987     return EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE;
    988 
    989   /* Save the current state */
    990   num_fileSaved = file->num_file;
    991   pos_in_central_dirSaved = file->pos_in_central_dir;
    992   cur_file_infoSaved = file->cur_file_info;
    993   cur_file_info_internalSaved = file->cur_file_info_internal;
    994   err = EXTRACTOR_common_unzip_go_to_first_file (file);
    995 
    996   while (EXTRACTOR_UNZIP_OK == err)
    997   {
    998     char szCurrentFileName[UNZ_MAXFILENAMEINZIP + 1];
    999 
   1000     if (EXTRACTOR_UNZIP_OK !=
   1001         (err = EXTRACTOR_common_unzip_get_current_file_info (file, NULL,
   1002                                                              szCurrentFileName,
   1003                                                              sizeof (
   1004                                                                szCurrentFileName)
   1005                                                              - 1,
   1006                                                              NULL, 0, NULL, 0)))
   1007       break;
   1008     if (0 ==
   1009         EXTRACTOR_common_unzip_string_file_name_compare (szCurrentFileName,
   1010                                                          szFileName,
   1011                                                          iCaseSensitivity))
   1012       return EXTRACTOR_UNZIP_OK;
   1013     err = EXTRACTOR_common_unzip_go_to_next_file (file);
   1014   }
   1015 
   1016   /* We failed, so restore the state of the 'current file' to where we
   1017    * were.
   1018    */
   1019   file->num_file = num_fileSaved;
   1020   file->pos_in_central_dir = pos_in_central_dirSaved;
   1021   file->cur_file_info = cur_file_infoSaved;
   1022   file->cur_file_info_internal = cur_file_info_internalSaved;
   1023   return err;
   1024 }
   1025 
   1026 
   1027 /**
   1028  * Read bytes from the current file (must have been opened).
   1029  *
   1030  * @param buf contain buffer where data must be copied
   1031  * @param len the size of buf.
   1032  * @return the number of byte copied if some bytes are copied
   1033  *         0 if the end of file was reached
   1034  *         <0 with error code if there is an error
   1035  *        (#EXTRACTOR_UNZIP_ERRNO for IO error, or zLib error for uncompress error)
   1036  */
   1037 ssize_t
   1038 EXTRACTOR_common_unzip_read_current_file (struct EXTRACTOR_UnzipFile *file,
   1039                                           void *buf,
   1040                                           size_t len)
   1041 {
   1042   int err = EXTRACTOR_UNZIP_OK;
   1043   uInt iRead = 0;
   1044   struct FileInZipReadInfo *pfile_in_zip_read_info;
   1045 
   1046   if (NULL == file)
   1047     return EXTRACTOR_UNZIP_PARAMERROR;
   1048   if (NULL == (pfile_in_zip_read_info = file->pfile_in_zip_read))
   1049     return EXTRACTOR_UNZIP_PARAMERROR;
   1050   if (NULL == pfile_in_zip_read_info->read_buffer)
   1051     return EXTRACTOR_UNZIP_END_OF_LIST_OF_FILE;
   1052   if (0 == len)
   1053     return 0;
   1054 
   1055   pfile_in_zip_read_info->stream.next_out = (Bytef *) buf;
   1056   pfile_in_zip_read_info->stream.avail_out = (uInt) len;
   1057   if (len > pfile_in_zip_read_info->rest_read_uncompressed)
   1058     pfile_in_zip_read_info->stream.avail_out =
   1059       (uInt) pfile_in_zip_read_info->rest_read_uncompressed;
   1060 
   1061   while (pfile_in_zip_read_info->stream.avail_out > 0)
   1062   {
   1063     if ( (0 == pfile_in_zip_read_info->stream.avail_in) &&
   1064          (pfile_in_zip_read_info->rest_read_compressed > 0) )
   1065     {
   1066       uInt uReadThis = UNZ_BUFSIZE;
   1067       if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
   1068         uReadThis = (uInt) pfile_in_zip_read_info->rest_read_compressed;
   1069       if (0 == uReadThis)
   1070         return EXTRACTOR_UNZIP_EOF;
   1071       if (0 !=
   1072           ZSEEK (pfile_in_zip_read_info->z_filefunc,
   1073                  pfile_in_zip_read_info->pos_in_zipfile
   1074                  + pfile_in_zip_read_info->byte_before_the_zipfile,
   1075                  SEEK_SET))
   1076         return EXTRACTOR_UNZIP_ERRNO;
   1077       if (ZREAD (pfile_in_zip_read_info->z_filefunc,
   1078                  pfile_in_zip_read_info->read_buffer,
   1079                  uReadThis) != uReadThis)
   1080         return EXTRACTOR_UNZIP_ERRNO;
   1081 
   1082       pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
   1083       pfile_in_zip_read_info->rest_read_compressed -= uReadThis;
   1084       pfile_in_zip_read_info->stream.next_in =
   1085         (Bytef *) pfile_in_zip_read_info->read_buffer;
   1086       pfile_in_zip_read_info->stream.avail_in = (uInt) uReadThis;
   1087     }
   1088 
   1089     if (0 == pfile_in_zip_read_info->compression_method)
   1090     {
   1091       uInt uDoCopy;
   1092 
   1093       if ( (0 == pfile_in_zip_read_info->stream.avail_in) &&
   1094            (0 == pfile_in_zip_read_info->rest_read_compressed) )
   1095         return (0 == iRead) ? EXTRACTOR_UNZIP_EOF : iRead;
   1096 
   1097       if (pfile_in_zip_read_info->stream.avail_out <
   1098           pfile_in_zip_read_info->stream.avail_in)
   1099         uDoCopy = pfile_in_zip_read_info->stream.avail_out;
   1100       else
   1101         uDoCopy = pfile_in_zip_read_info->stream.avail_in;
   1102       memcpy (pfile_in_zip_read_info->stream.next_out,
   1103               pfile_in_zip_read_info->stream.next_in,
   1104               uDoCopy);
   1105       pfile_in_zip_read_info->crc32 = crc32 (pfile_in_zip_read_info->crc32,
   1106                                              pfile_in_zip_read_info->stream.
   1107                                              next_out,
   1108                                              uDoCopy);
   1109       pfile_in_zip_read_info->rest_read_uncompressed -= uDoCopy;
   1110       pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
   1111       pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
   1112       pfile_in_zip_read_info->stream.next_out += uDoCopy;
   1113       pfile_in_zip_read_info->stream.next_in += uDoCopy;
   1114       pfile_in_zip_read_info->stream.total_out += uDoCopy;
   1115       iRead += uDoCopy;
   1116     }
   1117     else
   1118     {
   1119       uLong uTotalOutBefore;
   1120       uLong uTotalOutAfter;
   1121       const Bytef *bufBefore;
   1122       uLong uOutThis;
   1123       int flush = Z_SYNC_FLUSH;
   1124 
   1125       uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
   1126       bufBefore = pfile_in_zip_read_info->stream.next_out;
   1127 
   1128       /*
   1129         if ((pfile_in_zip_read_info->rest_read_uncompressed ==
   1130         pfile_in_zip_read_info->stream.avail_out) &&
   1131         (pfile_in_zip_read_info->rest_read_compressed == 0))
   1132         flush = Z_FINISH;
   1133       */err = inflate (&pfile_in_zip_read_info->stream, flush);
   1134 
   1135       uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
   1136       uOutThis = uTotalOutAfter - uTotalOutBefore;
   1137 
   1138       pfile_in_zip_read_info->crc32 =
   1139         crc32 (pfile_in_zip_read_info->crc32, bufBefore,
   1140                (uInt) (uOutThis));
   1141 
   1142       pfile_in_zip_read_info->rest_read_uncompressed -=
   1143         uOutThis;
   1144 
   1145       iRead += (uInt) (uTotalOutAfter - uTotalOutBefore);
   1146 
   1147       if (Z_STREAM_END == err)
   1148         return (0 == iRead) ? EXTRACTOR_UNZIP_EOF : iRead;
   1149       if (Z_OK != err)
   1150         break;
   1151     }
   1152   }
   1153 
   1154   if (Z_OK == err)
   1155     return iRead;
   1156   return err;
   1157 }
   1158 
   1159 
   1160 /**
   1161  * Read the local header of the current zipfile. Check the coherency of
   1162  * the local header and info in the end of central directory about
   1163  * this file. Store in *piSizeVar the size of extra info in local
   1164  * header (filename and size of extra field data)
   1165  *
   1166  * @param file zipfile to process
   1167  * @param piSizeVar where to store the size of the extra info
   1168  * @param poffset_local_extrafield where to store the offset of the local extrafield
   1169  * @param psoze_local_extrafield where to store the size of the local extrafield
   1170  * @return #EXTRACTOR_UNZIP_OK on success
   1171  */
   1172 static int
   1173 parse_current_file_coherency_header (struct EXTRACTOR_UnzipFile *file,
   1174                                      uInt *piSizeVar,
   1175                                      uLong *poffset_local_extrafield,
   1176                                      uInt *psize_local_extrafield)
   1177 {
   1178   uLong uMagic;
   1179   uLong uData;
   1180   uLong uFlags;
   1181   uLong size_filename;
   1182   uLong size_extra_field;
   1183 
   1184   *piSizeVar = 0;
   1185   *poffset_local_extrafield = 0;
   1186   *psize_local_extrafield = 0;
   1187 
   1188   if (0 != ZSEEK (file->z_filefunc,
   1189                   file->cur_file_info_internal.offset_curfile
   1190                   + file->byte_before_the_zipfile,
   1191                   SEEK_SET))
   1192     return EXTRACTOR_UNZIP_ERRNO;
   1193   if (EXTRACTOR_UNZIP_OK !=
   1194       read_long_from_ffd (&file->z_filefunc,
   1195                           &uMagic))
   1196     return EXTRACTOR_UNZIP_ERRNO;
   1197   if (0x04034b50 != uMagic)
   1198     return EXTRACTOR_UNZIP_BADZIPFILE;
   1199   if ( (EXTRACTOR_UNZIP_OK !=
   1200         read_short_from_ffd (&file->z_filefunc, &uData)) ||
   1201        (EXTRACTOR_UNZIP_OK !=
   1202         read_short_from_ffd (&file->z_filefunc, &uFlags)) )
   1203     return EXTRACTOR_UNZIP_ERRNO;
   1204   if (EXTRACTOR_UNZIP_OK != read_short_from_ffd (&file->z_filefunc, &uData))
   1205     return EXTRACTOR_UNZIP_ERRNO;
   1206   if (uData != file->cur_file_info.compression_method)
   1207     return EXTRACTOR_UNZIP_BADZIPFILE;
   1208   if ( (0 != file->cur_file_info.compression_method) &&
   1209        (Z_DEFLATED != file->cur_file_info.compression_method) )
   1210     return EXTRACTOR_UNZIP_BADZIPFILE;
   1211   if (EXTRACTOR_UNZIP_OK !=
   1212       read_long_from_ffd (&file->z_filefunc, &uData)) /* date/time */
   1213     return EXTRACTOR_UNZIP_ERRNO;
   1214   if (EXTRACTOR_UNZIP_OK !=
   1215       read_long_from_ffd (&file->z_filefunc, &uData)) /* crc */
   1216     return EXTRACTOR_UNZIP_ERRNO;
   1217   if ( (uData != file->cur_file_info.crc) &&
   1218        (0 == (uFlags & 8)) )
   1219     return EXTRACTOR_UNZIP_BADZIPFILE;
   1220   if (EXTRACTOR_UNZIP_OK !=
   1221       read_long_from_ffd (&file->z_filefunc, &uData)) /* size compr */
   1222     return EXTRACTOR_UNZIP_ERRNO;
   1223   if ( (uData != file->cur_file_info.compressed_size) &&
   1224        (0 == (uFlags & 8)) )
   1225     return EXTRACTOR_UNZIP_BADZIPFILE;
   1226   if (EXTRACTOR_UNZIP_OK !=
   1227       read_long_from_ffd (&file->z_filefunc,
   1228                           &uData)) /* size uncompr */
   1229     return EXTRACTOR_UNZIP_ERRNO;
   1230   if ( (uData != file->cur_file_info.uncompressed_size) &&
   1231        (0 == (uFlags & 8)))
   1232     return EXTRACTOR_UNZIP_BADZIPFILE;
   1233   if (EXTRACTOR_UNZIP_OK !=
   1234       read_short_from_ffd (&file->z_filefunc, &size_filename))
   1235     return EXTRACTOR_UNZIP_ERRNO;
   1236   if (size_filename != file->cur_file_info.size_filename)
   1237     return EXTRACTOR_UNZIP_BADZIPFILE;
   1238   *piSizeVar += (uInt) size_filename;
   1239   if (EXTRACTOR_UNZIP_OK !=
   1240       read_short_from_ffd (&file->z_filefunc,
   1241                            &size_extra_field))
   1242     return EXTRACTOR_UNZIP_ERRNO;
   1243   *poffset_local_extrafield = file->cur_file_info_internal.offset_curfile
   1244                               + SIZEZIPLOCALHEADER + size_filename;
   1245   *psize_local_extrafield = (uInt) size_extra_field;
   1246   *piSizeVar += (uInt) size_extra_field;
   1247 
   1248   return EXTRACTOR_UNZIP_OK;
   1249 }
   1250 
   1251 
   1252 /**
   1253  * Open for reading data the current file in the zipfile.
   1254  *
   1255  * @param file zipfile to manipulate
   1256  * @return #EXTRACTOR_UNZIP_OK on success
   1257  */
   1258 int
   1259 EXTRACTOR_common_unzip_open_current_file (struct EXTRACTOR_UnzipFile *file)
   1260 {
   1261   int err;
   1262   uInt iSizeVar;
   1263   struct FileInZipReadInfo *pfile_in_zip_read_info;
   1264   uLong offset_local_extrafield;  /* offset of the local extra field */
   1265   uInt size_local_extrafield;     /* size of the local extra field */
   1266 
   1267   if (NULL == file)
   1268     return EXTRACTOR_UNZIP_PARAMERROR;
   1269   if (! file->current_file_ok)
   1270     return EXTRACTOR_UNZIP_PARAMERROR;
   1271   if (NULL != file->pfile_in_zip_read)
   1272     EXTRACTOR_common_unzip_close_current_file (file);
   1273   if (EXTRACTOR_UNZIP_OK !=
   1274       parse_current_file_coherency_header (file,
   1275                                            &iSizeVar,
   1276                                            &offset_local_extrafield,
   1277                                            &size_local_extrafield))
   1278     return EXTRACTOR_UNZIP_BADZIPFILE;
   1279   if (NULL == (pfile_in_zip_read_info = malloc (sizeof(struct
   1280                                                        FileInZipReadInfo))))
   1281     return EXTRACTOR_UNZIP_INTERNALERROR;
   1282   if (NULL == (pfile_in_zip_read_info->read_buffer = malloc (UNZ_BUFSIZE)))
   1283   {
   1284     free (pfile_in_zip_read_info);
   1285     return EXTRACTOR_UNZIP_INTERNALERROR;
   1286   }
   1287   pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
   1288   pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
   1289   pfile_in_zip_read_info->pos_local_extrafield = 0;
   1290   pfile_in_zip_read_info->stream_initialised = 0;
   1291 
   1292   if ( (0 != file->cur_file_info.compression_method) &&
   1293        (Z_DEFLATED != file->cur_file_info.compression_method) )
   1294   {
   1295     // err = EXTRACTOR_UNZIP_BADZIPFILE;
   1296     // FIXME: we don't do anything with this 'err' code.
   1297     // Can this happen? Should we abort in this case?
   1298   }
   1299 
   1300   pfile_in_zip_read_info->crc32_wait = file->cur_file_info.crc;
   1301   pfile_in_zip_read_info->crc32 = 0;
   1302   pfile_in_zip_read_info->compression_method =
   1303     file->cur_file_info.compression_method;
   1304   pfile_in_zip_read_info->z_filefunc = file->z_filefunc;
   1305   pfile_in_zip_read_info->byte_before_the_zipfile =
   1306     file->byte_before_the_zipfile;
   1307   pfile_in_zip_read_info->stream.total_out = 0;
   1308   if (Z_DEFLATED == file->cur_file_info.compression_method)
   1309   {
   1310     pfile_in_zip_read_info->stream.zalloc = (alloc_func) NULL;
   1311     pfile_in_zip_read_info->stream.zfree = (free_func) NULL;
   1312     pfile_in_zip_read_info->stream.opaque = NULL;
   1313     pfile_in_zip_read_info->stream.next_in = NULL;
   1314     pfile_in_zip_read_info->stream.avail_in = 0;
   1315     if (Z_OK != (err = inflateInit2 (&pfile_in_zip_read_info->stream,
   1316                                      -MAX_WBITS)))
   1317     {
   1318       free (pfile_in_zip_read_info->read_buffer);
   1319       free (pfile_in_zip_read_info);
   1320       return err;
   1321     }
   1322     pfile_in_zip_read_info->stream_initialised = 1;
   1323     /* windowBits is passed < 0 to tell that there is no zlib header.
   1324      * Note that in this case inflate *requires* an extra "dummy" byte
   1325      * after the compressed stream in order to complete decompression and
   1326      * return Z_STREAM_END.
   1327      * In unzip, i don't wait absolutely Z_STREAM_END because I known the
   1328      * size of both compressed and uncompressed data
   1329      */}
   1330   pfile_in_zip_read_info->rest_read_compressed =
   1331     file->cur_file_info.compressed_size;
   1332   pfile_in_zip_read_info->rest_read_uncompressed =
   1333     file->cur_file_info.uncompressed_size;
   1334   pfile_in_zip_read_info->pos_in_zipfile =
   1335     file->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER
   1336     + iSizeVar;
   1337   pfile_in_zip_read_info->stream.avail_in = 0;
   1338   file->pfile_in_zip_read = pfile_in_zip_read_info;
   1339   return EXTRACTOR_UNZIP_OK;
   1340 }
   1341 
   1342 
   1343 /**
   1344  * Callback to perform read operation using LE API.
   1345  * Note that partial reads are not allowed.
   1346  *
   1347  * @param opaque the 'struct EXTRACTOR_ExtractContext'
   1348  * @param buf where to write bytes read
   1349  * @param size number of bytes desired
   1350  * @return number of bytes copied to buf
   1351  */
   1352 static uLong
   1353 ec_read_file_func (voidpf opaque,
   1354                    void*buf,
   1355                    uLong size)
   1356 {
   1357   struct EXTRACTOR_ExtractContext *ec = opaque;
   1358   void *ptr;
   1359   ssize_t ret;
   1360   uLong done;
   1361 
   1362   done = 0;
   1363   while (done < size)
   1364   {
   1365     ret = ec->read (ec->cls,
   1366                     &ptr,
   1367                     size - done);
   1368     if (ret <= 0)
   1369       return done;
   1370     memcpy (buf + done, ptr, ret);
   1371     done += ret;
   1372   }
   1373   return done;
   1374 }
   1375 
   1376 
   1377 /**
   1378  * Callback to obtain current offset in file using LE API.
   1379  *
   1380  * @param opaque the 'struct EXTRACTOR_ExtractContext'
   1381  * @return current offset in file, -1 on error
   1382  */
   1383 static long
   1384 ec_tell_file_func (voidpf opaque)
   1385 {
   1386   struct EXTRACTOR_ExtractContext *ec = opaque;
   1387 
   1388   return ec->seek (ec->cls, 0, SEEK_CUR);
   1389 }
   1390 
   1391 
   1392 /**
   1393  * Callback to perform seek operation using LE API.
   1394  *
   1395  * @param opaque the 'struct EXTRACTOR_ExtractContext'
   1396  * @param offset where to seek
   1397  * @param origin relative to where should we seek
   1398  * @return #EXTRACTOR_UNZIP_OK on success
   1399  */
   1400 static long
   1401 ec_seek_file_func (voidpf opaque,
   1402                    uLong offset,
   1403                    int origin)
   1404 {
   1405   struct EXTRACTOR_ExtractContext *ec = opaque;
   1406 
   1407   if (-1 == ec->seek (ec->cls, offset, origin))
   1408     return EXTRACTOR_UNZIP_INTERNALERROR;
   1409   return EXTRACTOR_UNZIP_OK;
   1410 }
   1411 
   1412 
   1413 /**
   1414  * Open a zip file for processing using the data access
   1415  * functions from the extract context.
   1416  *
   1417  * @param ec extract context to use
   1418  * @return handle to zip data, NULL on error
   1419  */
   1420 struct EXTRACTOR_UnzipFile *
   1421 EXTRACTOR_common_unzip_open (struct EXTRACTOR_ExtractContext *ec)
   1422 {
   1423   struct FileFuncDefs ffd;
   1424 
   1425   ffd.zread_file = &ec_read_file_func;
   1426   ffd.ztell_file = &ec_tell_file_func;
   1427   ffd.zseek_file = &ec_seek_file_func;
   1428   ffd.opaque = ec;
   1429 
   1430   return unzip_open_using_ffd (&ffd);
   1431 }
   1432 
   1433 
   1434 /* end of unzip.c */