added generic support for listing and extracting zip files (using minizip)
[rocksndiamonds.git] / src / libgame / zip / unzip.c
1 /* unzip.c -- IO for uncompress .zip files using zlib
2    Version 1.2.0, September 16th, 2017
3    part of the MiniZip project
4
5    Copyright (C) 2010-2017 Nathan Moinvaziri
6      Modifications for AES, PKWARE disk spanning
7      https://github.com/nmoinvaz/minizip
8    Copyright (C) 2009-2010 Mathias Svensson
9      Modifications for Zip64 support on both zip and unzip
10      http://result42.com
11    Copyright (C) 2007-2008 Even Rouault
12      Modifications of Unzip for Zip64
13    Copyright (C) 1998-2010 Gilles Vollant
14      http://www.winimage.com/zLibDll/minizip.html
15
16    This program is distributed under the terms of the same license as zlib.
17    See the accompanying LICENSE file for the full text of the license.
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdint.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <assert.h>
26 #include <limits.h>
27
28 #define NOUNCRYPT
29
30 #include "zlib.h"
31 #include "unzip.h"
32
33 #ifdef HAVE_AES
34 #  define AES_METHOD          (99)
35 #  define AES_PWVERIFYSIZE    (2)
36 #  define AES_MAXSALTLENGTH   (16)
37 #  define AES_AUTHCODESIZE    (10)
38 #  define AES_HEADERSIZE      (11)
39 #  define AES_KEYSIZE(mode)   (64 + (mode * 64))
40
41 #  include "aes/aes.h"
42 #  include "aes/fileenc.h"
43 #endif
44 #ifdef HAVE_APPLE_COMPRESSION
45 #  include <compression.h>
46 #endif
47
48 #ifndef NOUNCRYPT
49 #  include "crypt.h"
50 #endif
51
52 #define DISKHEADERMAGIC             (0x08074b50)
53 #define LOCALHEADERMAGIC            (0x04034b50)
54 #define CENTRALHEADERMAGIC          (0x02014b50)
55 #define ENDHEADERMAGIC              (0x06054b50)
56 #define ZIP64ENDHEADERMAGIC         (0x06064b50)
57 #define ZIP64ENDLOCHEADERMAGIC      (0x07064b50)
58
59 #define SIZECENTRALDIRITEM          (0x2e)
60 #define SIZECENTRALHEADERLOCATOR    (0x14)
61 #define SIZEZIPLOCALHEADER          (0x1e)
62
63 #ifndef BUFREADCOMMENT
64 #  define BUFREADCOMMENT            (0x400)
65 #endif
66
67 #ifndef UNZ_BUFSIZE
68 #  define UNZ_BUFSIZE               (UINT16_MAX)
69 #endif
70 #ifndef UNZ_MAXFILENAMEINZIP
71 #  define UNZ_MAXFILENAMEINZIP      (256)
72 #endif
73
74 #ifndef ALLOC
75 #  define ALLOC(size) (malloc(size))
76 #endif
77 #ifndef TRYFREE
78 #  define TRYFREE(p) {if (p) free(p);}
79 #endif
80
81 const char unz_copyright[] = " unzip 1.2.0 Copyright 1998-2017 - https://github.com/nmoinvaz/minizip";
82
83 /* unz_file_info_internal contain internal info about a file in zipfile*/
84 typedef struct unz_file_info64_internal_s
85 {
86     uint64_t offset_curfile;            /* relative offset of local header 8 bytes */
87     uint64_t byte_before_the_zipfile;   /* byte before the zipfile, (>0 for sfx) */
88 #ifdef HAVE_AES
89     uint8_t  aes_encryption_mode;
90     uint16_t aes_compression_method;
91     uint16_t aes_version;
92 #endif
93 } unz_file_info64_internal;
94
95 /* file_in_zip_read_info_s contain internal information about a file in zipfile */
96 typedef struct
97 {
98     uint8_t *read_buffer;               /* internal buffer for compressed data */
99     z_stream stream;                    /* zLib stream structure for inflate */
100 #ifdef HAVE_BZIP2
101     bz_stream bstream;                  /* bzLib stream structure for bziped */
102 #endif
103 #ifdef HAVE_APPLE_COMPRESSION
104     compression_stream astream;         /* libcompression stream structure */
105 #endif
106 #ifdef HAVE_AES
107     fcrypt_ctx aes_ctx;
108 #endif
109     uint64_t pos_in_zipfile;            /* position in byte on the zipfile, for fseek */
110     uint8_t  stream_initialised;        /* flag set if stream structure is initialised */
111
112     uint64_t offset_local_extrafield;   /* offset of the local extra field */
113     uint16_t size_local_extrafield;     /* size of the local extra field */
114     uint64_t pos_local_extrafield;      /* position in the local extra field in read */
115     uint64_t total_out_64;
116
117     uint32_t crc32;                     /* crc32 of all data uncompressed */
118     uint32_t crc32_expected;            /* crc32 we must obtain after decompress all */
119     uint64_t rest_read_compressed;      /* number of byte to be decompressed */
120     uint64_t rest_read_uncompressed;    /* number of byte to be obtained after decomp */
121
122     zlib_filefunc64_32_def z_filefunc;
123
124     voidpf   filestream;                /* io structore of the zipfile */
125     uint16_t compression_method;        /* compression method (0==store) */
126     uint64_t byte_before_the_zipfile;   /* byte before the zipfile, (>0 for sfx) */
127     int      raw;
128 } file_in_zip64_read_info_s;
129
130 /* unz64_s contain internal information about the zipfile */
131 typedef struct
132 {
133     zlib_filefunc64_32_def z_filefunc;
134
135     voidpf filestream;                  /* io structure of the current zipfile */
136     voidpf filestream_with_CD;          /* io structure of the disk with the central directory */
137
138     unz_global_info64 gi;               /* public global information */
139
140     uint64_t byte_before_the_zipfile;   /* byte before the zipfile, (>0 for sfx) */
141     uint64_t num_file;                  /* number of the current file in the zipfile */
142     uint64_t pos_in_central_dir;        /* pos of the current file in the central dir */
143     uint64_t current_file_ok;           /* flag about the usability of the current file */
144     uint64_t central_pos;               /* position of the beginning of the central dir */
145     uint32_t number_disk;               /* number of the current disk, used for spanning ZIP */
146     uint64_t size_central_dir;          /* size of the central directory */
147     uint64_t offset_central_dir;        /* offset of start of central directory with
148                                            respect to the starting disk number */
149
150     unz_file_info64 cur_file_info;      /* public info about the current file in zip*/
151     unz_file_info64_internal cur_file_info_internal;
152                                         /* private info about it*/
153     file_in_zip64_read_info_s *pfile_in_zip_read;
154                                         /* structure about the current file if we are decompressing it */
155     int is_zip64;                       /* is the current file zip64 */
156 #ifndef NOUNCRYPT
157     uint32_t keys[3];                   /* keys defining the pseudo-random sequence */
158     const z_crc_t *pcrc_32_tab;
159 #endif
160 } unz64_internal;
161
162 /* Read a byte from a gz_stream; Return EOF for end of file. */
163 static int unzReadUInt8(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint8_t *value)
164 {
165     uint8_t c = 0;
166     if (ZREAD64(*pzlib_filefunc_def, filestream, &c, 1) == 1)
167     {
168         *value = (uint8_t)c;
169         return UNZ_OK;
170     }
171     *value = 0;
172     if (ZERROR64(*pzlib_filefunc_def, filestream))
173         return UNZ_ERRNO;
174     return UNZ_EOF;
175 }
176
177 static int unzReadUInt16(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint16_t *value)
178 {
179     uint16_t x;
180     uint8_t c = 0;
181     int err = UNZ_OK;
182
183     err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
184     x = (uint16_t)c;
185     if (err == UNZ_OK)
186         err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
187     x |= ((uint16_t)c) << 8;
188
189     if (err == UNZ_OK)
190         *value = x;
191     else
192         *value = 0;
193     return err;
194 }
195
196 static int unzReadUInt32(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint32_t *value)
197 {
198     uint32_t x = 0;
199     uint8_t c = 0;
200     int err = UNZ_OK;
201
202     err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
203     x = (uint32_t)c;
204     if (err == UNZ_OK)
205         err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
206     x |= ((uint32_t)c) << 8;
207     if (err == UNZ_OK)
208         err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
209     x |= ((uint32_t)c) << 16;
210     if (err == UNZ_OK)
211         err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
212     x += ((uint32_t)c) << 24;
213
214     if (err == UNZ_OK)
215         *value = x;
216     else
217         *value = 0;
218     return err;
219 }
220
221 static int unzReadUInt64(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint64_t *value)
222 {
223     uint64_t x = 0;
224     uint8_t i = 0;
225     int err = UNZ_OK;
226
227     err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
228     x = (uint64_t)i;
229     if (err == UNZ_OK)
230         err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
231     x |= ((uint64_t)i) << 8;
232     if (err == UNZ_OK)
233         err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
234     x |= ((uint64_t)i) << 16;
235     if (err == UNZ_OK)
236         err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
237     x |= ((uint64_t)i) << 24;
238     if (err == UNZ_OK)
239         err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
240     x |= ((uint64_t)i) << 32;
241     if (err == UNZ_OK)
242         err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
243     x |= ((uint64_t)i) << 40;
244     if (err == UNZ_OK)
245         err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
246     x |= ((uint64_t)i) << 48;
247     if (err == UNZ_OK)
248         err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
249     x |= ((uint64_t)i) << 56;
250
251     if (err == UNZ_OK)
252         *value = x;
253     else
254         *value = 0;
255     return err;
256 }
257
258 /* Locate the Central directory of a zip file (at the end, just before the global comment) */
259 static int unzSearchCentralDir(const zlib_filefunc64_32_def *pzlib_filefunc_def, uint64_t *pos_found, voidpf filestream)
260 {
261     uint8_t buf[BUFREADCOMMENT + 4];
262     uint64_t file_size = 0;
263     uint64_t back_read = 4;
264     uint64_t max_back = UINT16_MAX; /* maximum size of global comment */
265     uint32_t read_size = 0;
266     uint64_t read_pos = 0;
267     uint32_t i = 0;
268     *pos_found = 0;
269
270     if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) != 0)
271         return UNZ_ERRNO;
272
273     file_size = ZTELL64(*pzlib_filefunc_def, filestream);
274
275     if (max_back > file_size)
276         max_back = file_size;
277
278     while (back_read < max_back)
279     {
280         if (back_read + BUFREADCOMMENT > max_back)
281             back_read = max_back;
282         else
283             back_read += BUFREADCOMMENT;
284
285         read_pos = file_size - back_read;
286         read_size = ((BUFREADCOMMENT + 4) < (file_size - read_pos)) ?
287                      (BUFREADCOMMENT + 4) : (uint32_t)(file_size - read_pos);
288
289         if (ZSEEK64(*pzlib_filefunc_def, filestream, read_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
290             break;
291         if (ZREAD64(*pzlib_filefunc_def, filestream, buf, read_size) != read_size)
292             break;
293
294         for (i = read_size - 3; (i--) > 0;)
295             if (((*(buf+i)) == (ENDHEADERMAGIC & 0xff)) &&
296                 ((*(buf+i+1)) == (ENDHEADERMAGIC >> 8 & 0xff)) &&
297                 ((*(buf+i+2)) == (ENDHEADERMAGIC >> 16 & 0xff)) &&
298                 ((*(buf+i+3)) == (ENDHEADERMAGIC >> 24 & 0xff)))
299             {
300                 *pos_found = read_pos+i;
301                 return UNZ_OK;
302             }
303     }
304
305     return UNZ_ERRNO;
306 }
307
308 /* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */
309 static int unzSearchCentralDir64(const zlib_filefunc64_32_def *pzlib_filefunc_def, uint64_t *offset, voidpf filestream,
310     const uint64_t endcentraloffset)
311 {
312     uint32_t value32 = 0;
313     *offset = 0;
314
315     /* Zip64 end of central directory locator */
316     if (ZSEEK64(*pzlib_filefunc_def, filestream, endcentraloffset - SIZECENTRALHEADERLOCATOR, ZLIB_FILEFUNC_SEEK_SET) != 0)
317         return UNZ_ERRNO;
318
319     /* Read locator signature */
320     if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
321         return UNZ_ERRNO;
322     if (value32 != ZIP64ENDLOCHEADERMAGIC)
323         return UNZ_ERRNO;
324     /* Number of the disk with the start of the zip64 end of  central directory */
325     if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
326         return UNZ_ERRNO;
327     /* Relative offset of the zip64 end of central directory record */
328     if (unzReadUInt64(pzlib_filefunc_def, filestream, offset) != UNZ_OK)
329         return UNZ_ERRNO;
330     /* Total number of disks */
331     if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
332         return UNZ_ERRNO;
333     /* Goto end of central directory record */
334     if (ZSEEK64(*pzlib_filefunc_def, filestream, *offset, ZLIB_FILEFUNC_SEEK_SET) != 0)
335         return UNZ_ERRNO;
336      /* The signature */
337     if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
338         return UNZ_ERRNO;
339     if (value32 != ZIP64ENDHEADERMAGIC)
340         return UNZ_ERRNO;
341
342     return UNZ_OK;
343 }
344
345 static unzFile unzOpenInternal(const void *path, zlib_filefunc64_32_def *pzlib_filefunc64_32_def)
346 {
347     unz64_internal us = {{{ 0 }}};      // (prevent warning from GCC bug 53119)
348     unz64_internal *s = NULL;
349     uint64_t central_pos = 0;
350     uint64_t central_pos64 = 0;
351     uint64_t number_entry_CD = 0;
352     uint16_t value16 = 0;
353     uint32_t value32 = 0;
354     uint64_t value64 = 0;
355     voidpf filestream = NULL;
356     int err = UNZ_OK;
357     int err64 = UNZ_OK;
358
359     if (pzlib_filefunc64_32_def == NULL)
360         fill_fopen64_filefunc(&us.z_filefunc.zfile_func64);
361     else
362     {
363         assert((pzlib_filefunc64_32_def->zopen32_file || pzlib_filefunc64_32_def->zfile_func64.zopen64_file) &&
364                (pzlib_filefunc64_32_def->zopendisk32_file || pzlib_filefunc64_32_def->zfile_func64.zopendisk64_file) &&
365                (pzlib_filefunc64_32_def->ztell32_file || pzlib_filefunc64_32_def->zfile_func64.ztell64_file) &&
366                (pzlib_filefunc64_32_def->zseek32_file || pzlib_filefunc64_32_def->zfile_func64.zseek64_file));
367         us.z_filefunc = *pzlib_filefunc64_32_def;
368     }
369
370     us.filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
371
372     if (us.filestream == NULL)
373         return NULL;
374
375     us.filestream_with_CD = us.filestream;
376
377     /* Search for end of central directory header */
378     err = unzSearchCentralDir(&us.z_filefunc, &central_pos, us.filestream);
379     if (err == UNZ_OK)
380     {
381         if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
382             err = UNZ_ERRNO;
383
384         /* The signature, already checked */
385         if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
386             err = UNZ_ERRNO;
387         /* Number of this disk */
388         if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
389             err = UNZ_ERRNO;
390         us.number_disk = value16;
391         /* Number of the disk with the start of the central directory */
392         if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
393             err = UNZ_ERRNO;
394         us.gi.number_disk_with_CD = value16;
395         /* Total number of entries in the central directory on this disk */
396         if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
397             err = UNZ_ERRNO;
398         us.gi.number_entry = value16;
399         /* Total number of entries in the central directory */
400         if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
401             err = UNZ_ERRNO;
402         number_entry_CD = value16;
403         if (number_entry_CD != us.gi.number_entry)
404             err = UNZ_BADZIPFILE;
405         /* Size of the central directory */
406         if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
407             err = UNZ_ERRNO;
408         us.size_central_dir = value32;
409         /* Offset of start of central directory with respect to the starting disk number */
410         if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
411             err = UNZ_ERRNO;
412         us.offset_central_dir = value32;
413         /* Zipfile comment length */
414         if (unzReadUInt16(&us.z_filefunc, us.filestream, &us.gi.size_comment) != UNZ_OK)
415             err = UNZ_ERRNO;
416
417         if (err == UNZ_OK)
418         {
419             /* Search for Zip64 end of central directory header */
420             err64 = unzSearchCentralDir64(&us.z_filefunc, &central_pos64, us.filestream, central_pos);
421             if (err64 == UNZ_OK)
422             {
423                 central_pos = central_pos64;
424                 us.is_zip64 = 1;
425
426                 if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
427                     err = UNZ_ERRNO;
428
429                 /* the signature, already checked */
430                 if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
431                     err = UNZ_ERRNO;
432                 /* size of zip64 end of central directory record */
433                 if (unzReadUInt64(&us.z_filefunc, us.filestream, &value64) != UNZ_OK)
434                     err = UNZ_ERRNO;
435                 /* version made by */
436                 if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
437                     err = UNZ_ERRNO;
438                 /* version needed to extract */
439                 if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
440                     err = UNZ_ERRNO;
441                 /* number of this disk */
442                 if (unzReadUInt32(&us.z_filefunc, us.filestream, &us.number_disk) != UNZ_OK)
443                     err = UNZ_ERRNO;
444                 /* number of the disk with the start of the central directory */
445                 if (unzReadUInt32(&us.z_filefunc, us.filestream, &us.gi.number_disk_with_CD) != UNZ_OK)
446                     err = UNZ_ERRNO;
447                 /* total number of entries in the central directory on this disk */
448                 if (unzReadUInt64(&us.z_filefunc, us.filestream, &us.gi.number_entry) != UNZ_OK)
449                     err = UNZ_ERRNO;
450                 /* total number of entries in the central directory */
451                 if (unzReadUInt64(&us.z_filefunc, us.filestream, &number_entry_CD) != UNZ_OK)
452                     err = UNZ_ERRNO;
453                 if (number_entry_CD != us.gi.number_entry)
454                     err = UNZ_BADZIPFILE;
455                 /* size of the central directory */
456                 if (unzReadUInt64(&us.z_filefunc, us.filestream, &us.size_central_dir) != UNZ_OK)
457                     err = UNZ_ERRNO;
458                 /* offset of start of central directory with respect to the starting disk number */
459                 if (unzReadUInt64(&us.z_filefunc, us.filestream, &us.offset_central_dir) != UNZ_OK)
460                     err = UNZ_ERRNO;
461             }
462             else if ((us.size_central_dir == UINT16_MAX) || (us.offset_central_dir == UINT32_MAX))
463                 err = UNZ_BADZIPFILE;
464         }
465     }
466     else
467         err = UNZ_ERRNO;
468
469     if ((err == UNZ_OK) && (central_pos < us.offset_central_dir + us.size_central_dir))
470         err = UNZ_BADZIPFILE;
471
472     if (err != UNZ_OK)
473     {
474         ZCLOSE64(us.z_filefunc, us.filestream);
475         return NULL;
476     }
477
478     if (us.gi.number_disk_with_CD == 0)
479     {
480         /* If there is only one disk open another stream so we don't have to seek between the CD
481            and the file headers constantly */
482         filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
483         if (filestream != NULL)
484             us.filestream = filestream;
485     }
486
487     /* Hack for zip files that have no respect for zip64
488     if ((central_pos > 0xffffffff) && (us.offset_central_dir < 0xffffffff))
489         us.offset_central_dir = central_pos - us.size_central_dir;*/
490
491     us.byte_before_the_zipfile = central_pos - (us.offset_central_dir + us.size_central_dir);
492     us.central_pos = central_pos;
493
494     s = (unz64_internal*)ALLOC(sizeof(unz64_internal));
495     if (s != NULL)
496     {
497         *s = us;
498         if (err64 != UNZ_OK)
499             // workaround incorrect count #184
500             s->gi.number_entry = unzCountEntries(s);
501
502         unzGoToFirstFile((unzFile)s);
503     }
504     return (unzFile)s;
505 }
506
507 extern unzFile ZEXPORT unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc32_def)
508 {
509     if (pzlib_filefunc32_def != NULL)
510     {
511         zlib_filefunc64_32_def zlib_filefunc64_32_def_fill = {{ 0 }};
512         fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill, pzlib_filefunc32_def);
513         return unzOpenInternal(path, &zlib_filefunc64_32_def_fill);
514     }
515     return unzOpenInternal(path, NULL);
516 }
517
518 extern unzFile ZEXPORT unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def)
519 {
520     if (pzlib_filefunc_def != NULL)
521     {
522         zlib_filefunc64_32_def zlib_filefunc64_32_def_fill = {{ 0 }};
523         zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
524         return unzOpenInternal(path, &zlib_filefunc64_32_def_fill);
525     }
526     return unzOpenInternal(path, NULL);
527 }
528
529 extern unzFile ZEXPORT unzOpen(const char *path)
530 {
531     return unzOpenInternal(path, NULL);
532 }
533
534 extern unzFile ZEXPORT unzOpen64(const void *path)
535 {
536     return unzOpenInternal(path, NULL);
537 }
538
539 extern int ZEXPORT unzClose(unzFile file)
540 {
541     unz64_internal *s;
542     if (file == NULL)
543         return UNZ_PARAMERROR;
544     s = (unz64_internal*)file;
545
546     if (s->pfile_in_zip_read != NULL)
547         unzCloseCurrentFile(file);
548
549     if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD))
550         ZCLOSE64(s->z_filefunc, s->filestream);
551     if (s->filestream_with_CD != NULL)
552         ZCLOSE64(s->z_filefunc, s->filestream_with_CD);
553
554     s->filestream = NULL;
555     s->filestream_with_CD = NULL;
556     TRYFREE(s);
557     return UNZ_OK;
558 }
559
560 /* Goto to the next available disk for spanned archives */
561 static int unzGoToNextDisk(unzFile file)
562 {
563     unz64_internal *s;
564     uint32_t number_disk_next = 0;
565
566     s = (unz64_internal*)file;
567     if (s == NULL)
568         return UNZ_PARAMERROR;
569     number_disk_next = s->number_disk;
570
571     if ((s->pfile_in_zip_read != NULL) && (s->pfile_in_zip_read->rest_read_uncompressed > 0))
572         /* We are currently reading a file and we need the next sequential disk */
573         number_disk_next += 1;
574     else
575         /* Goto the disk for the current file */
576         number_disk_next = s->cur_file_info.disk_num_start;
577
578     if (number_disk_next != s->number_disk)
579     {
580         /* Switch disks */
581         if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD))
582             ZCLOSE64(s->z_filefunc, s->filestream);
583
584         if (number_disk_next == s->gi.number_disk_with_CD)
585         {
586             s->filestream = s->filestream_with_CD;
587         }
588         else
589         {
590             s->filestream = ZOPENDISK64(s->z_filefunc, s->filestream_with_CD, number_disk_next,
591                 ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
592         }
593
594         if (s->filestream == NULL)
595             return UNZ_ERRNO;
596
597         s->number_disk = number_disk_next;
598     }
599
600     return UNZ_OK;
601 }
602
603 extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32)
604 {
605     unz64_internal *s = NULL;
606     if (file == NULL)
607         return UNZ_PARAMERROR;
608     s = (unz64_internal*)file;
609
610     pglobal_info32->number_entry = (uint32_t)s->gi.number_entry;
611     pglobal_info32->size_comment = s->gi.size_comment;
612     pglobal_info32->number_disk_with_CD = s->gi.number_disk_with_CD;
613     return UNZ_OK;
614 }
615
616 extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info)
617 {
618     unz64_internal *s = NULL;
619     if (file == NULL)
620         return UNZ_PARAMERROR;
621     s = (unz64_internal*)file;
622     *pglobal_info = s->gi;
623     return UNZ_OK;
624 }
625
626 extern int ZEXPORT unzGetGlobalComment(unzFile file, char *comment, uint16_t comment_size)
627 {
628     unz64_internal *s = NULL;
629     uint16_t bytes_to_read = comment_size;
630     if (file == NULL)
631         return (int)UNZ_PARAMERROR;
632     s = (unz64_internal*)file;
633
634     if (bytes_to_read > s->gi.size_comment)
635         bytes_to_read = s->gi.size_comment;
636
637     if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, s->central_pos + 22, ZLIB_FILEFUNC_SEEK_SET) != 0)
638         return UNZ_ERRNO;
639
640     if (bytes_to_read > 0)
641     {
642         *comment = 0;
643         if (ZREAD64(s->z_filefunc, s->filestream_with_CD, comment, bytes_to_read) != bytes_to_read)
644             return UNZ_ERRNO;
645     }
646
647     if ((comment != NULL) && (comment_size > s->gi.size_comment))
648         *(comment + s->gi.size_comment) = 0;
649
650     return (int)bytes_to_read;
651 }
652
653 static int unzGetCurrentFileInfoField(unzFile file, uint32_t *seek, void *field, uint16_t field_size, uint16_t size_file_field, int null_terminated_field)
654 {
655     unz64_internal *s = NULL;
656     uint32_t bytes_to_read = 0;
657     int err = UNZ_OK;
658
659     if (file == NULL)
660         return (int)UNZ_PARAMERROR;
661     s = (unz64_internal*)file;
662
663     /* Read field */
664     if (field != NULL)
665     {
666         if (size_file_field < field_size)
667         {
668             if (null_terminated_field)
669                 *((char *)field+size_file_field) = 0;
670
671             bytes_to_read = size_file_field;
672         }
673         else
674             bytes_to_read = field_size;
675
676         if (*seek != 0)
677         {
678             if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, *seek, ZLIB_FILEFUNC_SEEK_CUR) == 0)
679                 *seek = 0;
680             else
681                 err = UNZ_ERRNO;
682         }
683
684         if ((size_file_field > 0) && (field_size > 0))
685         {
686             if (ZREAD64(s->z_filefunc, s->filestream_with_CD, field, bytes_to_read) != bytes_to_read)
687                 err = UNZ_ERRNO;
688         }
689         *seek += size_file_field - bytes_to_read;
690     }
691     else
692     {
693         *seek += size_file_field;
694     }
695
696     return err;
697 }
698
699 /* Get info about the current file in the zipfile, with internal only info */
700 static int unzGetCurrentFileInfoInternal(unzFile file, unz_file_info64 *pfile_info,
701     unz_file_info64_internal *pfile_info_internal, char *filename, uint16_t filename_size, void *extrafield,
702     uint16_t extrafield_size, char *comment, uint16_t comment_size)
703 {
704     unz64_internal *s = NULL;
705     unz_file_info64 file_info;
706     unz_file_info64_internal file_info_internal;
707     uint32_t magic = 0;
708     uint64_t current_pos = 0;
709     uint32_t seek = 0;
710     uint32_t extra_pos = 0;
711     uint16_t extra_header_id = 0;
712     uint16_t extra_data_size = 0;
713     uint16_t value16 = 0;
714     uint32_t value32 = 0;
715     uint64_t value64 = 0;
716     int err = UNZ_OK;
717
718     if (file == NULL)
719         return UNZ_PARAMERROR;
720     s = (unz64_internal*)file;
721
722     if (ZSEEK64(s->z_filefunc, s->filestream_with_CD,
723             s->pos_in_central_dir + s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
724         err = UNZ_ERRNO;
725
726     /* Check the magic */
727     if (err == UNZ_OK)
728     {
729         if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &magic) != UNZ_OK)
730             err = UNZ_ERRNO;
731         else if (magic != CENTRALHEADERMAGIC)
732             err = UNZ_BADZIPFILE;
733     }
734
735     /* Read central directory header */
736     if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.version) != UNZ_OK)
737         err = UNZ_ERRNO;
738     if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.version_needed) != UNZ_OK)
739         err = UNZ_ERRNO;
740     if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.flag) != UNZ_OK)
741         err = UNZ_ERRNO;
742     if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.compression_method) != UNZ_OK)
743         err = UNZ_ERRNO;
744     if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.dos_date) != UNZ_OK)
745         err = UNZ_ERRNO;
746     if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.crc) != UNZ_OK)
747         err = UNZ_ERRNO;
748     if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &value32) != UNZ_OK)
749         err = UNZ_ERRNO;
750     file_info.compressed_size = value32;
751     if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &value32) != UNZ_OK)
752         err = UNZ_ERRNO;
753     file_info.uncompressed_size = value32;
754     if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.size_filename) != UNZ_OK)
755         err = UNZ_ERRNO;
756     if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_extra) != UNZ_OK)
757         err = UNZ_ERRNO;
758     if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_comment) != UNZ_OK)
759         err = UNZ_ERRNO;
760     if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &value16) != UNZ_OK)
761         err = UNZ_ERRNO;
762     file_info.disk_num_start = value16;
763     if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.internal_fa) != UNZ_OK)
764         err = UNZ_ERRNO;
765     if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.external_fa) != UNZ_OK)
766         err = UNZ_ERRNO;
767     /* Relative offset of local header */
768     if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &value32) != UNZ_OK)
769         err = UNZ_ERRNO;
770
771     file_info.size_file_extra_internal = 0;
772     file_info.disk_offset = value32;
773     file_info_internal.offset_curfile = value32;
774 #ifdef HAVE_AES
775     file_info_internal.aes_compression_method = 0;
776     file_info_internal.aes_encryption_mode = 0;
777     file_info_internal.aes_version = 0;
778 #endif
779
780     if (err == UNZ_OK)
781         err = unzGetCurrentFileInfoField(file, &seek, filename, filename_size, file_info.size_filename, 1);
782
783     /* Read extrafield */
784     if (err == UNZ_OK)
785         err = unzGetCurrentFileInfoField(file, &seek, extrafield, extrafield_size, file_info.size_file_extra, 0);
786
787     if ((err == UNZ_OK) && (file_info.size_file_extra != 0))
788     {
789         if (seek != 0)
790         {
791             if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, seek, ZLIB_FILEFUNC_SEEK_CUR) == 0)
792                 seek = 0;
793             else
794                 err = UNZ_ERRNO;
795         }
796
797         /* We are going to parse the extra field so we need to move back */
798         current_pos = ZTELL64(s->z_filefunc, s->filestream_with_CD);
799         if (current_pos < file_info.size_file_extra)
800             err = UNZ_ERRNO;
801         current_pos -= file_info.size_file_extra;
802         if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, current_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
803             err = UNZ_ERRNO;
804
805         while ((err != UNZ_ERRNO) && (extra_pos < file_info.size_file_extra))
806         {
807             if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &extra_header_id) != UNZ_OK)
808                 err = UNZ_ERRNO;
809             if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &extra_data_size) != UNZ_OK)
810                 err = UNZ_ERRNO;
811
812             /* ZIP64 extra fields */
813             if (extra_header_id == 0x0001)
814             {
815                 /* Subtract size of ZIP64 field, since ZIP64 is handled internally */
816                 file_info.size_file_extra_internal += 2 + 2 + extra_data_size;
817
818                 if (file_info.uncompressed_size == UINT32_MAX)
819                 {
820                     if (unzReadUInt64(&s->z_filefunc, s->filestream_with_CD, &file_info.uncompressed_size) != UNZ_OK)
821                         err = UNZ_ERRNO;
822                 }
823                 if (file_info.compressed_size == UINT32_MAX)
824                 {
825                     if (unzReadUInt64(&s->z_filefunc, s->filestream_with_CD, &file_info.compressed_size) != UNZ_OK)
826                         err = UNZ_ERRNO;
827                 }
828                 if (file_info_internal.offset_curfile == UINT32_MAX)
829                 {
830                     /* Relative Header offset */
831                     if (unzReadUInt64(&s->z_filefunc, s->filestream_with_CD, &value64) != UNZ_OK)
832                         err = UNZ_ERRNO;
833                     file_info_internal.offset_curfile = value64;
834                     file_info.disk_offset = value64;
835                 }
836                 if (file_info.disk_num_start == UINT32_MAX)
837                 {
838                     /* Disk Start Number */
839                     if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.disk_num_start) != UNZ_OK)
840                         err = UNZ_ERRNO;
841                 }
842             }
843 #ifdef HAVE_AES
844             /* AES header */
845             else if (extra_header_id == 0x9901)
846             {
847                 uint8_t value8 = 0;
848
849                 /* Subtract size of AES field, since AES is handled internally */
850                 file_info.size_file_extra_internal += 2 + 2 + extra_data_size;
851
852                 /* Verify version info */
853                 if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &value16) != UNZ_OK)
854                     err = UNZ_ERRNO;
855                 /* Support AE-1 and AE-2 */
856                 if (value16 != 1 && value16 != 2)
857                     err = UNZ_ERRNO;
858                 file_info_internal.aes_version = value16;
859                 if (unzReadUInt8(&s->z_filefunc, s->filestream_with_CD, &value8) != UNZ_OK)
860                     err = UNZ_ERRNO;
861                 if ((char)value8 != 'A')
862                     err = UNZ_ERRNO;
863                 if (unzReadUInt8(&s->z_filefunc, s->filestream_with_CD, &value8) != UNZ_OK)
864                     err = UNZ_ERRNO;
865                 if ((char)value8 != 'E')
866                     err = UNZ_ERRNO;
867                 /* Get AES encryption strength and actual compression method */
868                 if (unzReadUInt8(&s->z_filefunc, s->filestream_with_CD, &value8) != UNZ_OK)
869                     err = UNZ_ERRNO;
870                 file_info_internal.aes_encryption_mode = value8;
871                 if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &value16) != UNZ_OK)
872                     err = UNZ_ERRNO;
873                 file_info_internal.aes_compression_method = value16;
874             }
875 #endif
876             else
877             {
878                 if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, extra_data_size, ZLIB_FILEFUNC_SEEK_CUR) != 0)
879                     err = UNZ_ERRNO;
880             }
881
882             extra_pos += 2 + 2 + extra_data_size;
883         }
884     }
885
886     if (file_info.disk_num_start == s->gi.number_disk_with_CD)
887         file_info_internal.byte_before_the_zipfile = s->byte_before_the_zipfile;
888     else
889         file_info_internal.byte_before_the_zipfile = 0;
890
891     if (err == UNZ_OK)
892         err = unzGetCurrentFileInfoField(file, &seek, comment, comment_size, file_info.size_file_comment, 1);
893
894     if ((err == UNZ_OK) && (pfile_info != NULL))
895         *pfile_info = file_info;
896     if ((err == UNZ_OK) && (pfile_info_internal != NULL))
897         *pfile_info_internal = file_info_internal;
898
899     return err;
900 }
901
902 extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename,
903     uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
904 {
905     unz_file_info64 file_info64;
906     int err = UNZ_OK;
907
908     err = unzGetCurrentFileInfoInternal(file, &file_info64, NULL, filename, filename_size,
909                 extrafield, extrafield_size, comment, comment_size);
910
911     if ((err == UNZ_OK) && (pfile_info != NULL))
912     {
913         pfile_info->version = file_info64.version;
914         pfile_info->version_needed = file_info64.version_needed;
915         pfile_info->flag = file_info64.flag;
916         pfile_info->compression_method = file_info64.compression_method;
917         pfile_info->dos_date = file_info64.dos_date;
918         pfile_info->crc = file_info64.crc;
919
920         pfile_info->size_filename = file_info64.size_filename;
921         pfile_info->size_file_extra = file_info64.size_file_extra - file_info64.size_file_extra_internal;
922         pfile_info->size_file_comment = file_info64.size_file_comment;
923
924         pfile_info->disk_num_start = (uint16_t)file_info64.disk_num_start;
925         pfile_info->internal_fa = file_info64.internal_fa;
926         pfile_info->external_fa = file_info64.external_fa;
927
928         pfile_info->compressed_size = (uint32_t)file_info64.compressed_size;
929         pfile_info->uncompressed_size = (uint32_t)file_info64.uncompressed_size;
930     }
931     return err;
932 }
933
934 extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char *filename,
935     uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
936 {
937     return unzGetCurrentFileInfoInternal(file, pfile_info, NULL, filename, filename_size,
938         extrafield, extrafield_size, comment, comment_size);
939 }
940
941 /* Read the local header of the current zipfile. Check the coherency of the local header and info in the
942    end of central directory about this file store in *piSizeVar the size of extra info in local header
943    (filename and size of extra field data) */
944 static int unzCheckCurrentFileCoherencyHeader(unz64_internal *s, uint32_t *psize_variable, uint64_t *poffset_local_extrafield,
945     uint16_t *psize_local_extrafield)
946 {
947     uint32_t magic = 0;
948     uint16_t value16 = 0;
949     uint32_t value32 = 0;
950     uint32_t flags = 0;
951     uint16_t size_filename = 0;
952     uint16_t size_extra_field = 0;
953     uint16_t compression_method = 0;
954     int err = UNZ_OK;
955
956     if (psize_variable == NULL)
957         return UNZ_PARAMERROR;
958     *psize_variable = 0;
959     if (poffset_local_extrafield == NULL)
960         return UNZ_PARAMERROR;
961     *poffset_local_extrafield = 0;
962     if (psize_local_extrafield == NULL)
963         return UNZ_PARAMERROR;
964     *psize_local_extrafield = 0;
965
966     err = unzGoToNextDisk((unzFile)s);
967     if (err != UNZ_OK)
968         return err;
969
970     if (ZSEEK64(s->z_filefunc, s->filestream, s->cur_file_info_internal.offset_curfile +
971         s->cur_file_info_internal.byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
972         return UNZ_ERRNO;
973
974     if (err == UNZ_OK)
975     {
976         if (unzReadUInt32(&s->z_filefunc, s->filestream, &magic) != UNZ_OK)
977             err = UNZ_ERRNO;
978         else if (magic != LOCALHEADERMAGIC)
979             err = UNZ_BADZIPFILE;
980     }
981
982     if (unzReadUInt16(&s->z_filefunc, s->filestream, &value16) != UNZ_OK)
983         err = UNZ_ERRNO;
984     if (unzReadUInt16(&s->z_filefunc, s->filestream, &value16) != UNZ_OK)
985         err = UNZ_ERRNO;
986     flags = value16;
987     if (unzReadUInt16(&s->z_filefunc, s->filestream, &value16) != UNZ_OK)
988         err = UNZ_ERRNO;
989     else if ((err == UNZ_OK) && (value16 != s->cur_file_info.compression_method))
990         err = UNZ_BADZIPFILE;
991
992     compression_method = s->cur_file_info.compression_method;
993 #ifdef HAVE_AES
994     if (compression_method == AES_METHOD)
995         compression_method = s->cur_file_info_internal.aes_compression_method;
996 #endif
997
998     if ((err == UNZ_OK) && (compression_method != 0) && (compression_method != Z_DEFLATED))
999     {
1000 #ifdef HAVE_BZIP2
1001         if (compression_method != Z_BZIP2ED)
1002 #endif
1003             err = UNZ_BADZIPFILE;
1004     }
1005
1006     if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* date/time */
1007         err = UNZ_ERRNO;
1008     if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* crc */
1009         err = UNZ_ERRNO;
1010     else if ((err == UNZ_OK) && (value32 != s->cur_file_info.crc) && ((flags & 8) == 0))
1011         err = UNZ_BADZIPFILE;
1012     if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* size compr */
1013         err = UNZ_ERRNO;
1014     else if ((value32 != UINT32_MAX) && (err == UNZ_OK) && (value32 != s->cur_file_info.compressed_size) && ((flags & 8) == 0))
1015         err = UNZ_BADZIPFILE;
1016     if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* size uncompr */
1017         err = UNZ_ERRNO;
1018     else if ((value32 != UINT32_MAX) && (err == UNZ_OK) && (value32 != s->cur_file_info.uncompressed_size) && ((flags & 8) == 0))
1019         err = UNZ_BADZIPFILE;
1020     if (unzReadUInt16(&s->z_filefunc, s->filestream, &size_filename) != UNZ_OK)
1021         err = UNZ_ERRNO;
1022
1023     *psize_variable += size_filename;
1024
1025     if (unzReadUInt16(&s->z_filefunc, s->filestream, &size_extra_field) != UNZ_OK)
1026         err = UNZ_ERRNO;
1027
1028     *poffset_local_extrafield = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename;
1029     *psize_local_extrafield = size_extra_field;
1030     *psize_variable += size_extra_field;
1031
1032     return err;
1033 }
1034
1035 extern uint64_t ZEXPORT unzCountEntries(const unzFile file)
1036 {
1037     if (file == NULL)
1038         return 0;
1039
1040     unz64_internal s = *(unz64_internal*)file;
1041
1042     s.pos_in_central_dir = s.offset_central_dir;
1043     s.num_file = 0;
1044     while (UNZ_OK == unzGetCurrentFileInfoInternal(&s,
1045                                                    &s.cur_file_info,
1046                                                    &s.cur_file_info_internal,
1047                                                    NULL, 0, NULL, 0, NULL, 0))
1048     {
1049         s.pos_in_central_dir += SIZECENTRALDIRITEM
1050         + s.cur_file_info.size_filename
1051         + s.cur_file_info.size_file_extra
1052         + s.cur_file_info.size_file_comment;
1053         s.num_file += 1;
1054     }
1055     return s.num_file;
1056 }
1057
1058 /*
1059   Open for reading data the current file in the zipfile.
1060   If there is no error and the file is opened, the return value is UNZ_OK.
1061 */
1062 extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password)
1063 {
1064     unz64_internal *s = NULL;
1065     file_in_zip64_read_info_s *pfile_in_zip_read_info = NULL;
1066     uint16_t compression_method = 0;
1067     uint64_t offset_local_extrafield = 0;
1068     uint16_t size_local_extrafield = 0;
1069     uint32_t size_variable = 0;
1070     int err = UNZ_OK;
1071 #ifndef NOUNCRYPT
1072     char source[12];
1073 #else
1074     if (password != NULL)
1075         return UNZ_PARAMERROR;
1076 #endif
1077     if (file == NULL)
1078         return UNZ_PARAMERROR;
1079     s = (unz64_internal*)file;
1080     if (!s->current_file_ok)
1081         return UNZ_PARAMERROR;
1082
1083     if (s->pfile_in_zip_read != NULL)
1084         unzCloseCurrentFile(file);
1085
1086     if (unzCheckCurrentFileCoherencyHeader(s, &size_variable, &offset_local_extrafield, &size_local_extrafield) != UNZ_OK)
1087         return UNZ_BADZIPFILE;
1088
1089     compression_method = s->cur_file_info.compression_method;
1090 #ifdef HAVE_AES
1091     if (compression_method == AES_METHOD)
1092     {
1093         compression_method = s->cur_file_info_internal.aes_compression_method;
1094         if (password == NULL)
1095         {
1096             return UNZ_PARAMERROR;
1097         }
1098     }
1099 #endif
1100
1101     if (method != NULL)
1102         *method = compression_method;
1103
1104     if (level != NULL)
1105     {
1106         *level = 6;
1107         switch (s->cur_file_info.flag & 0x06)
1108         {
1109           case 6 : *level = 1; break;
1110           case 4 : *level = 2; break;
1111           case 2 : *level = 9; break;
1112         }
1113     }
1114
1115     if ((compression_method != 0) && (compression_method != Z_DEFLATED))
1116     {
1117 #ifdef HAVE_BZIP2
1118         if (compression_method != Z_BZIP2ED)
1119 #endif
1120         {
1121             return UNZ_BADZIPFILE;
1122         }
1123     }
1124
1125     pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s));
1126     if (pfile_in_zip_read_info == NULL)
1127         return UNZ_INTERNALERROR;
1128
1129     pfile_in_zip_read_info->read_buffer = (uint8_t*)ALLOC(UNZ_BUFSIZE);
1130     if (pfile_in_zip_read_info->read_buffer == NULL)
1131     {
1132         TRYFREE(pfile_in_zip_read_info);
1133         return UNZ_INTERNALERROR;
1134     }
1135
1136     pfile_in_zip_read_info->stream_initialised = 0;
1137
1138     pfile_in_zip_read_info->filestream = s->filestream;
1139     pfile_in_zip_read_info->z_filefunc = s->z_filefunc;
1140
1141     pfile_in_zip_read_info->raw = raw;
1142     pfile_in_zip_read_info->crc32 = 0;
1143     pfile_in_zip_read_info->crc32_expected = s->cur_file_info.crc;
1144     pfile_in_zip_read_info->total_out_64 = 0;
1145     pfile_in_zip_read_info->compression_method = compression_method;
1146
1147     pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
1148     pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
1149     pfile_in_zip_read_info->pos_local_extrafield = 0;
1150
1151     pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size;
1152     pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size;
1153     pfile_in_zip_read_info->byte_before_the_zipfile = 0;
1154
1155     if (s->number_disk == s->gi.number_disk_with_CD)
1156         pfile_in_zip_read_info->byte_before_the_zipfile = s->byte_before_the_zipfile;
1157
1158     pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_variable;
1159
1160     pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
1161     pfile_in_zip_read_info->stream.zfree = (free_func)0;
1162     pfile_in_zip_read_info->stream.opaque = (voidpf)s;
1163     pfile_in_zip_read_info->stream.total_out = 0;
1164     pfile_in_zip_read_info->stream.total_in = 0;
1165     pfile_in_zip_read_info->stream.next_in = NULL;
1166     pfile_in_zip_read_info->stream.avail_in = 0;
1167
1168     if (!raw)
1169     {
1170         if (compression_method == Z_BZIP2ED)
1171         {
1172 #ifdef HAVE_BZIP2
1173             pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0;
1174             pfile_in_zip_read_info->bstream.bzfree = (free_func)0;
1175             pfile_in_zip_read_info->bstream.opaque = (voidpf)0;
1176             pfile_in_zip_read_info->bstream.state = (voidpf)0;
1177
1178             err = BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0);
1179             if (err == Z_OK)
1180             {
1181                 pfile_in_zip_read_info->stream_initialised = Z_BZIP2ED;
1182             }
1183             else
1184             {
1185                 TRYFREE(pfile_in_zip_read_info);
1186                 return err;
1187             }
1188 #else
1189             pfile_in_zip_read_info->raw = 1;
1190 #endif
1191         }
1192         else if (compression_method == Z_DEFLATED)
1193         {
1194 #ifdef HAVE_APPLE_COMPRESSION
1195             err = compression_stream_init(&pfile_in_zip_read_info->astream, COMPRESSION_STREAM_DECODE, COMPRESSION_ZLIB);
1196             if (err == COMPRESSION_STATUS_ERROR)
1197                 err = UNZ_INTERNALERROR;
1198             else
1199                 err = Z_OK;
1200 #else
1201             err = inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
1202 #endif
1203             if (err == Z_OK)
1204             {
1205                 pfile_in_zip_read_info->stream_initialised = Z_DEFLATED;
1206             }
1207             else
1208             {
1209                 TRYFREE(pfile_in_zip_read_info);
1210                 return err;
1211             }
1212             /* windowBits is passed < 0 to tell that there is no zlib header.
1213              * Note that in this case inflate *requires* an extra "dummy" byte
1214              * after the compressed stream in order to complete decompression and
1215              * return Z_STREAM_END.
1216              * In unzip, i don't wait absolutely Z_STREAM_END because I known the
1217              * size of both compressed and uncompressed data
1218              */
1219         }
1220     }
1221
1222     s->pfile_in_zip_read = pfile_in_zip_read_info;
1223
1224 #ifndef NOUNCRYPT
1225     s->pcrc_32_tab = NULL;
1226
1227     if ((password != NULL) && ((s->cur_file_info.flag & 1) != 0))
1228     {
1229         if (ZSEEK64(s->z_filefunc, s->filestream,
1230                   s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile,
1231                   ZLIB_FILEFUNC_SEEK_SET) != 0)
1232             return UNZ_INTERNALERROR;
1233 #ifdef HAVE_AES
1234         if (s->cur_file_info.compression_method == AES_METHOD)
1235         {
1236             unsigned char passverify_archive[AES_PWVERIFYSIZE];
1237             unsigned char passverify_password[AES_PWVERIFYSIZE];
1238             unsigned char salt_value[AES_MAXSALTLENGTH];
1239             uint32_t salt_length = 0;
1240
1241             if ((s->cur_file_info_internal.aes_encryption_mode < 1) ||
1242                 (s->cur_file_info_internal.aes_encryption_mode > 3))
1243                 return UNZ_INTERNALERROR;
1244
1245             salt_length = SALT_LENGTH(s->cur_file_info_internal.aes_encryption_mode);
1246
1247             if (ZREAD64(s->z_filefunc, s->filestream, salt_value, salt_length) != salt_length)
1248                 return UNZ_INTERNALERROR;
1249             if (ZREAD64(s->z_filefunc, s->filestream, passverify_archive, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE)
1250                 return UNZ_INTERNALERROR;
1251
1252             fcrypt_init(s->cur_file_info_internal.aes_encryption_mode, (uint8_t *)password,
1253                 (uint32_t)strlen(password), salt_value, passverify_password, &s->pfile_in_zip_read->aes_ctx);
1254
1255             if (memcmp(passverify_archive, passverify_password, AES_PWVERIFYSIZE) != 0)
1256                 return UNZ_BADPASSWORD;
1257
1258             s->pfile_in_zip_read->rest_read_compressed -= salt_length + AES_PWVERIFYSIZE;
1259             s->pfile_in_zip_read->rest_read_compressed -= AES_AUTHCODESIZE;
1260
1261             s->pfile_in_zip_read->pos_in_zipfile += salt_length + AES_PWVERIFYSIZE;
1262         }
1263         else
1264 #endif
1265         {
1266             int i;
1267             s->pcrc_32_tab = (const z_crc_t*)get_crc_table();
1268             init_keys(password, s->keys, s->pcrc_32_tab);
1269
1270             if (ZREAD64(s->z_filefunc, s->filestream, source, 12) < 12)
1271                 return UNZ_INTERNALERROR;
1272
1273             for (i = 0; i < 12; i++)
1274                 zdecode(s->keys, s->pcrc_32_tab, source[i]);
1275             uint8_t expected = (s->cur_file_info.flag & (1 << 3)) ?
1276                 s->cur_file_info.dos_date >> 8 :
1277                 s->cur_file_info.crc >> 24;
1278             uint8_t actual = (uint8_t)source[11];
1279             if (expected != actual) {
1280               return UNZ_BADPASSWORD;
1281             }
1282
1283             s->pfile_in_zip_read->rest_read_compressed -= 12;
1284             s->pfile_in_zip_read->pos_in_zipfile += 12;
1285         }
1286     }
1287 #endif
1288
1289     return UNZ_OK;
1290 }
1291
1292 extern int ZEXPORT unzOpenCurrentFile(unzFile file)
1293 {
1294     return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
1295 }
1296
1297 extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char *password)
1298 {
1299     return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
1300 }
1301
1302 extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw)
1303 {
1304     return unzOpenCurrentFile3(file, method, level, raw, NULL);
1305 }
1306
1307 /* Read bytes from the current file.
1308    buf contain buffer where data must be copied
1309    len the size of buf.
1310
1311    return the number of byte copied if some bytes are copied
1312    return 0 if the end of file was reached
1313    return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */
1314 extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, uint32_t len)
1315 {
1316     unz64_internal *s = NULL;
1317     uint32_t read = 0;
1318     int err = UNZ_OK;
1319
1320     if (file == NULL)
1321         return UNZ_PARAMERROR;
1322     s = (unz64_internal*)file;
1323
1324     if (s->pfile_in_zip_read == NULL)
1325         return UNZ_PARAMERROR;
1326     if (s->pfile_in_zip_read->read_buffer == NULL)
1327         return UNZ_END_OF_LIST_OF_FILE;
1328     if (len == 0)
1329         return 0;
1330     // avail_out is uInt, so uint32_t len might allow requesting a larger buffer than zlib can support
1331     if (len > UINT_MAX)
1332         return UNZ_PARAMERROR;
1333
1334     s->pfile_in_zip_read->stream.next_out = (uint8_t*)buf;
1335     s->pfile_in_zip_read->stream.avail_out = (uInt)len;
1336
1337     if ((s->pfile_in_zip_read->compression_method == 0) || (s->pfile_in_zip_read->raw))
1338     {
1339         if (len > s->pfile_in_zip_read->rest_read_compressed + s->pfile_in_zip_read->stream.avail_in)
1340             s->pfile_in_zip_read->stream.avail_out = (uInt)s->pfile_in_zip_read->rest_read_compressed +
1341             s->pfile_in_zip_read->stream.avail_in;
1342     }
1343
1344     do
1345     {
1346         if (s->pfile_in_zip_read->stream.avail_in == 0)
1347         {
1348             uint32_t bytes_to_read = UNZ_BUFSIZE;
1349             uint32_t bytes_not_read = 0;
1350             uint32_t bytes_read = 0;
1351             uint32_t total_bytes_read = 0;
1352
1353             if (s->pfile_in_zip_read->stream.next_in != NULL)
1354                 bytes_not_read = (uint32_t)(s->pfile_in_zip_read->read_buffer + UNZ_BUFSIZE -
1355                     s->pfile_in_zip_read->stream.next_in);
1356             bytes_to_read -= bytes_not_read;
1357             if (bytes_not_read > 0)
1358                 memmove(s->pfile_in_zip_read->read_buffer, s->pfile_in_zip_read->stream.next_in, bytes_not_read);
1359             if (s->pfile_in_zip_read->rest_read_compressed < bytes_to_read)
1360                 bytes_to_read = (uint32_t)s->pfile_in_zip_read->rest_read_compressed;
1361
1362             while (total_bytes_read != bytes_to_read)
1363             {
1364                 if (ZSEEK64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream,
1365                         s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile,
1366                         ZLIB_FILEFUNC_SEEK_SET) != 0)
1367                     return UNZ_ERRNO;
1368
1369                 bytes_read = ZREAD64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream,
1370                           s->pfile_in_zip_read->read_buffer + bytes_not_read + total_bytes_read,
1371                           bytes_to_read - total_bytes_read);
1372
1373                 total_bytes_read += bytes_read;
1374                 s->pfile_in_zip_read->pos_in_zipfile += bytes_read;
1375
1376                 if (bytes_read == 0)
1377                 {
1378                     if (ZERROR64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream))
1379                         return UNZ_ERRNO;
1380
1381                     err = unzGoToNextDisk(file);
1382                     if (err != UNZ_OK)
1383                         return err;
1384
1385                     s->pfile_in_zip_read->pos_in_zipfile = 0;
1386                     s->pfile_in_zip_read->filestream = s->filestream;
1387                 }
1388             }
1389
1390 #ifndef NOUNCRYPT
1391             if ((s->cur_file_info.flag & 1) != 0)
1392             {
1393 #ifdef HAVE_AES
1394                 if (s->cur_file_info.compression_method == AES_METHOD)
1395                 {
1396                     fcrypt_decrypt(s->pfile_in_zip_read->read_buffer, bytes_to_read, &s->pfile_in_zip_read->aes_ctx);
1397                 }
1398                 else
1399 #endif
1400                 if (s->pcrc_32_tab != NULL)
1401                 {
1402                     uint32_t i = 0;
1403
1404                     for (i = 0; i < total_bytes_read; i++)
1405                       s->pfile_in_zip_read->read_buffer[i] =
1406                           zdecode(s->keys, s->pcrc_32_tab, s->pfile_in_zip_read->read_buffer[i]);
1407                 }
1408             }
1409 #endif
1410
1411             s->pfile_in_zip_read->rest_read_compressed -= total_bytes_read;
1412             s->pfile_in_zip_read->stream.next_in = (uint8_t*)s->pfile_in_zip_read->read_buffer;
1413             s->pfile_in_zip_read->stream.avail_in = (uInt)(bytes_not_read + total_bytes_read);
1414         }
1415
1416         if ((s->pfile_in_zip_read->compression_method == 0) || (s->pfile_in_zip_read->raw))
1417         {
1418             uint32_t i = 0;
1419             uint32_t copy = 0;
1420
1421             if ((s->pfile_in_zip_read->stream.avail_in == 0) &&
1422                 (s->pfile_in_zip_read->rest_read_compressed == 0))
1423                 return (read == 0) ? UNZ_EOF : read;
1424
1425             if (s->pfile_in_zip_read->stream.avail_out < s->pfile_in_zip_read->stream.avail_in)
1426                 copy = s->pfile_in_zip_read->stream.avail_out;
1427             else
1428                 copy = s->pfile_in_zip_read->stream.avail_in;
1429
1430             for (i = 0; i < copy; i++)
1431                 *(s->pfile_in_zip_read->stream.next_out + i) =
1432                         *(s->pfile_in_zip_read->stream.next_in + i);
1433
1434             s->pfile_in_zip_read->total_out_64 = s->pfile_in_zip_read->total_out_64 + copy;
1435             s->pfile_in_zip_read->rest_read_uncompressed -= copy;
1436             s->pfile_in_zip_read->crc32 = (uint32_t)crc32(s->pfile_in_zip_read->crc32,
1437                                 s->pfile_in_zip_read->stream.next_out, copy);
1438
1439             s->pfile_in_zip_read->stream.avail_in -= copy;
1440             s->pfile_in_zip_read->stream.avail_out -= copy;
1441             s->pfile_in_zip_read->stream.next_out += copy;
1442             s->pfile_in_zip_read->stream.next_in += copy;
1443             s->pfile_in_zip_read->stream.total_out += copy;
1444
1445             read += copy;
1446         }
1447         else if (s->pfile_in_zip_read->compression_method == Z_BZIP2ED)
1448         {
1449 #ifdef HAVE_BZIP2
1450             uint64_t total_out_before = 0;
1451             uint64_t total_out_after = 0;
1452             uint64_t out_bytes = 0;
1453             const uint8_t *buf_before = NULL;
1454
1455             s->pfile_in_zip_read->bstream.next_in        = (char*)s->pfile_in_zip_read->stream.next_in;
1456             s->pfile_in_zip_read->bstream.avail_in       = s->pfile_in_zip_read->stream.avail_in;
1457             s->pfile_in_zip_read->bstream.total_in_lo32  = (uint32_t)s->pfile_in_zip_read->stream.total_in;
1458             s->pfile_in_zip_read->bstream.total_in_hi32  = s->pfile_in_zip_read->stream.total_in >> 32;
1459
1460             s->pfile_in_zip_read->bstream.next_out       = (char*)s->pfile_in_zip_read->stream.next_out;
1461             s->pfile_in_zip_read->bstream.avail_out      = s->pfile_in_zip_read->stream.avail_out;
1462             s->pfile_in_zip_read->bstream.total_out_lo32 = (uint32_t)s->pfile_in_zip_read->stream.total_out;
1463             s->pfile_in_zip_read->bstream.total_out_hi32 = s->pfile_in_zip_read->stream.total_out >> 32;
1464
1465             total_out_before = s->pfile_in_zip_read->bstream.total_out_lo32 +
1466                 (((uint32_t)s->pfile_in_zip_read->bstream.total_out_hi32) << 32);
1467             buf_before = (const uint8_t*)s->pfile_in_zip_read->bstream.next_out;
1468
1469             err = BZ2_bzDecompress(&s->pfile_in_zip_read->bstream);
1470
1471             total_out_after = s->pfile_in_zip_read->bstream.total_out_lo32 +
1472                 (((uint32_t)s->pfile_in_zip_read->bstream.total_out_hi32) << 32);
1473
1474             out_bytes = total_out_after - total_out_before;
1475
1476             s->pfile_in_zip_read->total_out_64 = s->pfile_in_zip_read->total_out_64 + out_bytes;
1477             s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes;
1478             s->pfile_in_zip_read->crc32 = crc32(s->pfile_in_zip_read->crc32, buf_before, (uint32_t)out_bytes);
1479
1480             read += (uint32_t)out_bytes;
1481
1482             s->pfile_in_zip_read->stream.next_in   = (uint8_t*)s->pfile_in_zip_read->bstream.next_in;
1483             s->pfile_in_zip_read->stream.avail_in  = s->pfile_in_zip_read->bstream.avail_in;
1484             s->pfile_in_zip_read->stream.total_in  = s->pfile_in_zip_read->bstream.total_in_lo32;
1485             s->pfile_in_zip_read->stream.next_out  = (uint8_t*)s->pfile_in_zip_read->bstream.next_out;
1486             s->pfile_in_zip_read->stream.avail_out = s->pfile_in_zip_read->bstream.avail_out;
1487             s->pfile_in_zip_read->stream.total_out = s->pfile_in_zip_read->bstream.total_out_lo32;
1488
1489             if (err == BZ_STREAM_END)
1490                 return (read == 0) ? UNZ_EOF : read;
1491             if (err != BZ_OK)
1492                 break;
1493 #endif
1494         }
1495 #ifdef HAVE_APPLE_COMPRESSION
1496         else
1497         {
1498             uint64_t total_out_before = 0;
1499             uint64_t total_out_after = 0;
1500             uint64_t out_bytes = 0;
1501             const uint8_t *buf_before = NULL;
1502
1503             s->pfile_in_zip_read->astream.src_ptr = s->pfile_in_zip_read->stream.next_in;
1504             s->pfile_in_zip_read->astream.src_size = s->pfile_in_zip_read->stream.avail_in;
1505             s->pfile_in_zip_read->astream.dst_ptr = s->pfile_in_zip_read->stream.next_out;
1506             s->pfile_in_zip_read->astream.dst_size = len;
1507
1508             total_out_before = s->pfile_in_zip_read->stream.total_out;
1509             buf_before = s->pfile_in_zip_read->stream.next_out;
1510
1511             compression_status status;
1512             compression_stream_flags flags;
1513
1514             if (s->pfile_in_zip_read->stream.avail_in == 0)
1515             {
1516                 flags = COMPRESSION_STREAM_FINALIZE;
1517             }
1518
1519             status = compression_stream_process(&s->pfile_in_zip_read->astream, flags);
1520
1521             total_out_after = len - s->pfile_in_zip_read->astream.dst_size;
1522             out_bytes = total_out_after - total_out_before;
1523
1524             s->pfile_in_zip_read->total_out_64 += out_bytes;
1525             s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes;
1526             s->pfile_in_zip_read->crc32 =
1527                 crc32(s->pfile_in_zip_read->crc32, buf_before, (uint32_t)out_bytes);
1528
1529             read += (uint32_t)out_bytes;
1530
1531             s->pfile_in_zip_read->stream.next_in = s->pfile_in_zip_read->astream.src_ptr;
1532             s->pfile_in_zip_read->stream.avail_in = s->pfile_in_zip_read->astream.src_size;
1533             s->pfile_in_zip_read->stream.next_out = s->pfile_in_zip_read->astream.dst_ptr;
1534             s->pfile_in_zip_read->stream.avail_out = s->pfile_in_zip_read->astream.dst_size;
1535
1536             if (status == COMPRESSION_STATUS_END)
1537                 return (read == 0) ? UNZ_EOF : read;
1538             if (status == COMPRESSION_STATUS_ERROR)
1539                 return Z_DATA_ERROR;
1540             return read;
1541         }
1542 #else
1543         else
1544         {
1545             uint64_t total_out_before = 0;
1546             uint64_t total_out_after = 0;
1547             uint64_t out_bytes = 0;
1548             const uint8_t *buf_before = NULL;
1549             int flush = Z_SYNC_FLUSH;
1550
1551             total_out_before = s->pfile_in_zip_read->stream.total_out;
1552             buf_before = s->pfile_in_zip_read->stream.next_out;
1553
1554             /*
1555             if ((pfile_in_zip_read_info->rest_read_uncompressed ==
1556                      pfile_in_zip_read_info->stream.avail_out) &&
1557                 (pfile_in_zip_read_info->rest_read_compressed == 0))
1558                 flush = Z_FINISH;
1559             */
1560             err = inflate(&s->pfile_in_zip_read->stream, flush);
1561
1562             if ((err >= 0) && (s->pfile_in_zip_read->stream.msg != NULL))
1563                 err = Z_DATA_ERROR;
1564
1565             total_out_after = s->pfile_in_zip_read->stream.total_out;
1566             out_bytes = total_out_after - total_out_before;
1567
1568             s->pfile_in_zip_read->total_out_64 += out_bytes;
1569             s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes;
1570             s->pfile_in_zip_read->crc32 =
1571                 (uint32_t)crc32(s->pfile_in_zip_read->crc32, buf_before, (uint32_t)out_bytes);
1572
1573             read += (uint32_t)out_bytes;
1574
1575             if (err == Z_STREAM_END)
1576                 return (read == 0) ? UNZ_EOF : read;
1577             if (err != Z_OK)
1578                 break;
1579         }
1580 #endif
1581     }
1582     while (s->pfile_in_zip_read->stream.avail_out > 0);
1583
1584     if (err == Z_OK)
1585         return read;
1586     return err;
1587 }
1588
1589 extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, uint32_t len)
1590 {
1591     unz64_internal *s = NULL;
1592     uint64_t size_to_read = 0;
1593     uint32_t read_now = 0;
1594
1595     if (file == NULL)
1596         return UNZ_PARAMERROR;
1597     s = (unz64_internal*)file;
1598     if (s->pfile_in_zip_read == NULL)
1599         return UNZ_PARAMERROR;
1600
1601     size_to_read = s->pfile_in_zip_read->size_local_extrafield - s->pfile_in_zip_read->pos_local_extrafield;
1602
1603     if (buf == NULL)
1604         return (int)size_to_read;
1605
1606     if (len > size_to_read)
1607         read_now = (uint32_t)size_to_read;
1608     else
1609         read_now = len;
1610
1611     if (read_now == 0)
1612         return 0;
1613
1614     if (ZSEEK64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream,
1615         s->pfile_in_zip_read->offset_local_extrafield + s->pfile_in_zip_read->pos_local_extrafield,
1616         ZLIB_FILEFUNC_SEEK_SET) != 0)
1617         return UNZ_ERRNO;
1618
1619     if (ZREAD64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream, buf, read_now) != read_now)
1620         return UNZ_ERRNO;
1621
1622     return (int)read_now;
1623 }
1624
1625 extern int ZEXPORT unzCloseCurrentFile(unzFile file)
1626 {
1627     unz64_internal *s = NULL;
1628     file_in_zip64_read_info_s *pfile_in_zip_read_info = NULL;
1629     int err = UNZ_OK;
1630
1631     if (file == NULL)
1632         return UNZ_PARAMERROR;
1633     s = (unz64_internal*)file;
1634     pfile_in_zip_read_info = s->pfile_in_zip_read;
1635     if (pfile_in_zip_read_info == NULL)
1636         return UNZ_PARAMERROR;
1637
1638 #ifdef HAVE_AES
1639     if (s->cur_file_info.compression_method == AES_METHOD)
1640     {
1641         unsigned char authcode[AES_AUTHCODESIZE];
1642         unsigned char rauthcode[AES_AUTHCODESIZE];
1643
1644         if (ZREAD64(s->z_filefunc, s->filestream, authcode, AES_AUTHCODESIZE) != AES_AUTHCODESIZE)
1645             return UNZ_ERRNO;
1646
1647         if (fcrypt_end(rauthcode, &s->pfile_in_zip_read->aes_ctx) != AES_AUTHCODESIZE)
1648             err = UNZ_CRCERROR;
1649         if (memcmp(authcode, rauthcode, AES_AUTHCODESIZE) != 0)
1650             err = UNZ_CRCERROR;
1651     }
1652     /* AES zip version AE-1 will expect a valid crc as well */
1653     if ((s->cur_file_info.compression_method != AES_METHOD) ||
1654         (s->cur_file_info_internal.aes_version == 0x0001))
1655 #endif
1656     {
1657         if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
1658             (!pfile_in_zip_read_info->raw))
1659         {
1660             if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_expected)
1661                 err = UNZ_CRCERROR;
1662         }
1663     }
1664
1665     TRYFREE(pfile_in_zip_read_info->read_buffer);
1666     pfile_in_zip_read_info->read_buffer = NULL;
1667     if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
1668     {
1669 #ifdef HAVE_APPLE_COMPRESSION
1670         if (compression_stream_destroy)
1671             compression_stream_destroy(&pfile_in_zip_read_info->astream);
1672 #else
1673         inflateEnd(&pfile_in_zip_read_info->stream);
1674 #endif
1675     }
1676 #ifdef HAVE_BZIP2
1677     else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED)
1678         BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);
1679 #endif
1680
1681     pfile_in_zip_read_info->stream_initialised = 0;
1682     TRYFREE(pfile_in_zip_read_info);
1683
1684     s->pfile_in_zip_read = NULL;
1685
1686     return err;
1687 }
1688
1689 extern int ZEXPORT unzGoToFirstFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
1690     uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
1691 {
1692     unz64_internal *s = NULL;
1693     int err = UNZ_OK;
1694
1695     if (file == NULL)
1696         return UNZ_PARAMERROR;
1697     s = (unz64_internal*)file;
1698
1699     if (s->gi.number_entry == 0)
1700         return UNZ_END_OF_LIST_OF_FILE;
1701
1702     s->pos_in_central_dir = s->offset_central_dir;
1703     s->num_file = 0;
1704
1705     err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal,
1706             filename, filename_size, extrafield, extrafield_size, comment, comment_size);
1707
1708     s->current_file_ok = (err == UNZ_OK);
1709     if ((err == UNZ_OK) && (pfile_info != NULL))
1710         memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64));
1711
1712     return err;
1713 }
1714
1715 extern int ZEXPORT unzGoToFirstFile(unzFile file)
1716 {
1717     return unzGoToFirstFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0);
1718 }
1719
1720 extern int ZEXPORT unzGoToNextFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
1721     uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
1722 {
1723     unz64_internal *s = NULL;
1724     int err = UNZ_OK;
1725
1726     if (file == NULL)
1727         return UNZ_PARAMERROR;
1728     s = (unz64_internal*)file;
1729
1730     if (!s->current_file_ok)
1731         return UNZ_END_OF_LIST_OF_FILE;
1732     if (s->gi.number_entry != UINT16_MAX)    /* 2^16 files overflow hack */
1733     {
1734         if (s->num_file+1 == s->gi.number_entry)
1735             return UNZ_END_OF_LIST_OF_FILE;
1736     }
1737
1738     s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
1739             s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment;
1740     s->num_file += 1;
1741
1742     err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal,
1743             filename, filename_size, extrafield, extrafield_size, comment, comment_size);
1744
1745     s->current_file_ok = (err == UNZ_OK);
1746     if ((err == UNZ_OK) && (pfile_info != NULL))
1747         memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64));
1748
1749     return err;
1750 }
1751
1752 extern int ZEXPORT unzGoToNextFile(unzFile file)
1753 {
1754     return unzGoToNextFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0);
1755 }
1756
1757 extern int ZEXPORT unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func)
1758 {
1759     unz64_internal *s = NULL;
1760     unz_file_info64 cur_file_info_saved;
1761     unz_file_info64_internal cur_file_info_internal_saved;
1762     uint64_t num_file_saved = 0;
1763     uint64_t pos_in_central_dir_saved = 0;
1764     char current_filename[UNZ_MAXFILENAMEINZIP+1];
1765     int err = UNZ_OK;
1766
1767     if (file == NULL)
1768         return UNZ_PARAMERROR;
1769     if (strlen(filename) >= UNZ_MAXFILENAMEINZIP)
1770         return UNZ_PARAMERROR;
1771     s = (unz64_internal*)file;
1772     if (!s->current_file_ok)
1773         return UNZ_END_OF_LIST_OF_FILE;
1774
1775     /* Save the current state */
1776     num_file_saved = s->num_file;
1777     pos_in_central_dir_saved = s->pos_in_central_dir;
1778     cur_file_info_saved = s->cur_file_info;
1779     cur_file_info_internal_saved = s->cur_file_info_internal;
1780
1781     err = unzGoToFirstFile2(file, NULL, current_filename, sizeof(current_filename)-1, NULL, 0, NULL, 0);
1782
1783     while (err == UNZ_OK)
1784     {
1785         if (filename_compare_func != NULL)
1786             err = filename_compare_func(file, current_filename, filename);
1787         else
1788             err = strcmp(current_filename, filename);
1789         if (err == 0)
1790             return UNZ_OK;
1791         err = unzGoToNextFile2(file, NULL, current_filename, sizeof(current_filename)-1, NULL, 0, NULL, 0);
1792     }
1793
1794     /* We failed, so restore the state of the 'current file' to where we were. */
1795     s->num_file = num_file_saved;
1796     s->pos_in_central_dir = pos_in_central_dir_saved;
1797     s->cur_file_info = cur_file_info_saved;
1798     s->cur_file_info_internal = cur_file_info_internal_saved;
1799     return err;
1800 }
1801
1802 extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos *file_pos)
1803 {
1804     unz64_file_pos file_pos64;
1805     int err = unzGetFilePos64(file, &file_pos64);
1806     if (err == UNZ_OK)
1807     {
1808         file_pos->pos_in_zip_directory = (uint32_t)file_pos64.pos_in_zip_directory;
1809         file_pos->num_of_file = (uint32_t)file_pos64.num_of_file;
1810     }
1811     return err;
1812 }
1813
1814 extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos *file_pos)
1815 {
1816     unz64_file_pos file_pos64;
1817     if (file_pos == NULL)
1818         return UNZ_PARAMERROR;
1819     file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;
1820     file_pos64.num_of_file = file_pos->num_of_file;
1821     return unzGoToFilePos64(file, &file_pos64);
1822 }
1823
1824 extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos *file_pos)
1825 {
1826     unz64_internal *s = NULL;
1827
1828     if (file == NULL || file_pos == NULL)
1829         return UNZ_PARAMERROR;
1830     s = (unz64_internal*)file;
1831     if (!s->current_file_ok)
1832         return UNZ_END_OF_LIST_OF_FILE;
1833
1834     file_pos->pos_in_zip_directory  = s->pos_in_central_dir;
1835     file_pos->num_of_file = s->num_file;
1836     return UNZ_OK;
1837 }
1838
1839 extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos)
1840 {
1841     unz64_internal *s = NULL;
1842     int err = UNZ_OK;
1843
1844     if (file == NULL || file_pos == NULL)
1845         return UNZ_PARAMERROR;
1846     s = (unz64_internal*)file;
1847
1848     /* Jump to the right spot */
1849     s->pos_in_central_dir = file_pos->pos_in_zip_directory;
1850     s->num_file = file_pos->num_of_file;
1851
1852     /* Set the current file */
1853     err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0);
1854     /* Return results */
1855     s->current_file_ok = (err == UNZ_OK);
1856     return err;
1857 }
1858
1859 extern int32_t ZEXPORT unzGetOffset(unzFile file)
1860 {
1861     uint64_t offset64 = 0;
1862
1863     if (file == NULL)
1864         return UNZ_PARAMERROR;
1865     offset64 = unzGetOffset64(file);
1866     return (int32_t)offset64;
1867 }
1868
1869 extern int64_t ZEXPORT unzGetOffset64(unzFile file)
1870 {
1871     unz64_internal *s = NULL;
1872
1873     if (file == NULL)
1874         return UNZ_PARAMERROR;
1875     s = (unz64_internal*)file;
1876     if (!s->current_file_ok)
1877         return 0;
1878     if (s->gi.number_entry != 0 && s->gi.number_entry != UINT16_MAX)
1879     {
1880         if (s->num_file == s->gi.number_entry)
1881             return 0;
1882     }
1883     return s->pos_in_central_dir;
1884 }
1885
1886 extern int ZEXPORT unzSetOffset(unzFile file, uint32_t pos)
1887 {
1888     return unzSetOffset64(file, pos);
1889 }
1890
1891 extern int ZEXPORT unzSetOffset64(unzFile file, uint64_t pos)
1892 {
1893     unz64_internal *s = NULL;
1894     int err = UNZ_OK;
1895
1896     if (file == NULL)
1897         return UNZ_PARAMERROR;
1898     s = (unz64_internal*)file;
1899     s->pos_in_central_dir = pos;
1900     s->num_file = s->gi.number_entry; /* hack */
1901
1902     err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0);
1903
1904     s->current_file_ok = (err == UNZ_OK);
1905     return err;
1906 }
1907
1908 extern int32_t ZEXPORT unzTell(unzFile file)
1909 {
1910     unz64_internal *s = NULL;
1911     if (file == NULL)
1912         return UNZ_PARAMERROR;
1913     s = (unz64_internal*)file;
1914     if (s->pfile_in_zip_read == NULL)
1915         return UNZ_PARAMERROR;
1916     return (int32_t)s->pfile_in_zip_read->stream.total_out;
1917 }
1918
1919 extern int64_t ZEXPORT unzTell64(unzFile file)
1920 {
1921     unz64_internal *s = NULL;
1922     if (file == NULL)
1923         return UNZ_PARAMERROR;
1924     s = (unz64_internal*)file;
1925     if (s->pfile_in_zip_read == NULL)
1926         return UNZ_PARAMERROR;
1927     return s->pfile_in_zip_read->total_out_64;
1928 }
1929
1930 extern int ZEXPORT unzSeek(unzFile file, uint32_t offset, int origin)
1931 {
1932     return unzSeek64(file, offset, origin);
1933 }
1934
1935 extern int ZEXPORT unzSeek64(unzFile file, uint64_t offset, int origin)
1936 {
1937     unz64_internal *s = NULL;
1938     uint64_t stream_pos_begin = 0;
1939     uint64_t stream_pos_end = 0;
1940     uint64_t position = 0;
1941     int is_within_buffer = 0;
1942
1943     if (file == NULL)
1944         return UNZ_PARAMERROR;
1945     s = (unz64_internal*)file;
1946
1947     if (s->pfile_in_zip_read == NULL)
1948         return UNZ_ERRNO;
1949     if (s->pfile_in_zip_read->compression_method != 0)
1950         return UNZ_ERRNO;
1951
1952     if (origin == SEEK_SET)
1953         position = offset;
1954     else if (origin == SEEK_CUR)
1955         position = s->pfile_in_zip_read->total_out_64 + offset;
1956     else if (origin == SEEK_END)
1957         position = s->cur_file_info.compressed_size + offset;
1958     else
1959         return UNZ_PARAMERROR;
1960
1961     if (position > s->cur_file_info.compressed_size)
1962         return UNZ_PARAMERROR;
1963
1964     stream_pos_end = s->pfile_in_zip_read->pos_in_zipfile;
1965     stream_pos_begin = stream_pos_end;
1966
1967     if (stream_pos_begin > UNZ_BUFSIZE)
1968         stream_pos_begin -= UNZ_BUFSIZE;
1969     else
1970         stream_pos_begin = 0;
1971
1972     is_within_buffer =
1973         (s->pfile_in_zip_read->stream.avail_in != 0) &&
1974         (s->pfile_in_zip_read->rest_read_compressed != 0 || s->cur_file_info.compressed_size < UNZ_BUFSIZE) &&
1975         (position >= stream_pos_begin && position < stream_pos_end);
1976
1977     if (is_within_buffer)
1978     {
1979         s->pfile_in_zip_read->stream.next_in += position - s->pfile_in_zip_read->total_out_64;
1980         s->pfile_in_zip_read->stream.avail_in = (uInt)(stream_pos_end - position);
1981     }
1982     else
1983     {
1984         s->pfile_in_zip_read->stream.avail_in = 0;
1985         s->pfile_in_zip_read->stream.next_in = 0;
1986
1987         s->pfile_in_zip_read->pos_in_zipfile = s->pfile_in_zip_read->offset_local_extrafield + position;
1988         s->pfile_in_zip_read->rest_read_compressed = s->cur_file_info.compressed_size - position;
1989     }
1990
1991     s->pfile_in_zip_read->rest_read_uncompressed -= (position - s->pfile_in_zip_read->total_out_64);
1992     s->pfile_in_zip_read->stream.total_out = (uint32_t)position;
1993     s->pfile_in_zip_read->total_out_64 = position;
1994
1995     return UNZ_OK;
1996 }
1997
1998 extern int ZEXPORT unzEndOfFile(unzFile file)
1999 {
2000     unz64_internal *s = NULL;
2001     if (file == NULL)
2002         return UNZ_PARAMERROR;
2003     s = (unz64_internal*)file;
2004     if (s->pfile_in_zip_read == NULL)
2005         return UNZ_PARAMERROR;
2006     if (s->pfile_in_zip_read->rest_read_uncompressed == 0)
2007         return 1;
2008     return 0;
2009 }