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