"Fossies" - the Fresh Open Source Software Archive

Member "libextractor-1.11/src/common/unzip.c" (30 Jan 2021, 44242 Bytes) of package /linux/privat/libextractor-1.11.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "unzip.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.10_vs_1.11.

    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 */