1 /* Modified version by Even Rouault. :
2      - Addition of cpl_unzGetCurrentFileZStreamPos
3      - Decoration of symbol names unz* -> cpl_unz*
4      - Undef EXPORT so that we are sure the symbols are not exported
5      - Remove old C style function prototypes
6      - Add support for ZIP64
7      - Recode filename to UTF-8 if GP 11 is unset
8      - Use Info-ZIP Unicode Path Extra Field (0x7075) to get UTF-8 filenames
9      - ZIP64: accept number_disk == 0 in unzlocal_SearchCentralDir64()
10 
11  * Copyright (c) 2008-2014, Even Rouault <even dot rouault at spatialys.com>
12 
13    Original licence available in port/LICENCE_minizip
14 */
15 
16 /* unzip.c -- IO for uncompress .zip files using zlib
17    Version 1.01e, February 12th, 2005
18 
19    Copyright (C) 1998-2005 Gilles Vollant
20 
21    Read unzip.h for more info
22 */
23 
24 /* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of
25 compatibility with older software. The following is from the original crypt.c. Code
26 woven in by Terry Thorsen 1/2003.
27 */
28 /*
29   Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
30 
31   See the accompanying file LICENSE, version 2000-Apr-09 or later
32   (the contents of which are also included in zip.h) for terms of use.
33   If, for some reason, all these files are missing, the Info-ZIP license
34   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
35 */
36 /*
37   crypt.c (full version) by Info-ZIP.      Last revised:  [see crypt.h]
38 
39   The encryption/decryption parts of this source code (as opposed to the
40   non-echoing password parts) were originally written in Europe.  The
41   whole source package can be freely distributed, including from the USA.
42   (Prior to January 2000, re-export from the US was a violation of US law.)
43  */
44 
45 /*
46   This encryption code is a direct transcription of the algorithm from
47   Roger Schlafly, described by Phil Katz in the file appnote.txt.  This
48   file (appnote.txt) is distributed with the PKZIP program (even in the
49   version without encryption capabilities).
50  */
51 
52 #include "cpl_port.h"
53 #include "cpl_minizip_unzip.h"
54 
55 #include <cstddef>
56 #include <cstdlib>
57 #include <cstring>
58 
59 #include "cpl_conv.h"
60 #include "cpl_string.h"
61 
62 #ifdef NO_ERRNO_H
63     extern int errno;
64 #else
65 #   include <errno.h>
66 #endif
67 
68 CPL_CVSID("$Id: cpl_minizip_unzip.cpp f7598b073b8e1d8db5d2c4f7dd98a23783ebaa3a 2021-03-11 11:59:15 +0100 Even Rouault $")
69 
70 #ifndef CASESENSITIVITYDEFAULT_NO
71 #  if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES)
72 #    define CASESENSITIVITYDEFAULT_NO
73 #  endif
74 #endif
75 
76 #ifndef UNZ_BUFSIZE
77 #define UNZ_BUFSIZE (16384)
78 #endif
79 
80 #ifndef UNZ_MAXFILENAMEINZIP
81 #define UNZ_MAXFILENAMEINZIP (256)
82 #endif
83 
84 #ifndef ALLOC
85 # define ALLOC(size) (malloc(size))
86 #endif
87 #ifndef TRYFREE
88 # define TRYFREE(p) {if (p) free(p);}
89 #endif
90 
91 #define SIZECENTRALDIRITEM (0x2e)
92 #define SIZEZIPLOCALHEADER (0x1e)
93 
94 const char unz_copyright[] =
95    " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
96 
97 /* unz_file_info_internal contain internal info about a file in zipfile */
98 typedef struct unz_file_info_internal_s
99 {
100     uLong64 offset_curfile;/* relative offset of local header 4 bytes */
101 } unz_file_info_internal;
102 
103 /* file_in_zip_read_info_s contain internal information about a file in zipfile,
104     when reading and decompress it */
105 typedef struct
106 {
107     char  *read_buffer;         /* internal buffer for compressed data */
108     z_stream stream;            /* zLib stream structure for inflate */
109 
110     uLong64 pos_in_zipfile;       /* position in byte on the zipfile, for fseek */
111     uLong stream_initialised;   /* flag set if stream structure is initialized */
112 
113     uLong64 offset_local_extrafield;/* offset of the local extra field */
114     uInt  size_local_extrafield;/* size of the local extra field */
115     uLong64 pos_local_extrafield;   /* position in the local extra field in read */
116 
117     uLong crc32;                /* crc32 of all data uncompressed */
118     uLong crc32_wait;           /* crc32 we must obtain after decompress all */
119     uLong64 rest_read_compressed; /* number of byte to be decompressed */
120     uLong64 rest_read_uncompressed;/*number of byte to be obtained after decomp */
121     zlib_filefunc_def z_filefunc;
122     voidpf filestream;        /* IO structure of the zipfile */
123     uLong compression_method;   /* compression method (0==store) */
124     uLong64 byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
125     int   raw;
126 } file_in_zip_read_info_s;
127 
128 /* unz_s contain internal information about the zipfile
129 */
130 typedef struct
131 {
132     zlib_filefunc_def z_filefunc;
133     voidpf filestream;        /* IO structure of the zipfile */
134     unz_global_info gi;       /* public global information */
135     uLong64 byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
136     uLong64 num_file;             /* number of the current file in the zipfile*/
137     uLong64 pos_in_central_dir;   /* pos of the current file in the central dir*/
138     uLong64 current_file_ok;      /* flag about the usability of the current file*/
139     uLong64 central_pos;          /* position of the beginning of the central dir*/
140 
141     uLong64 size_central_dir;     /* size of the central directory  */
142     uLong64 offset_central_dir;   /* offset of start of central directory with
143                                    respect to the starting disk number */
144 
145     unz_file_info cur_file_info; /* public info about the current file in zip*/
146     unz_file_info_internal cur_file_info_internal; /* private info about it*/
147     file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current
148                                         file if we are decompressing it */
149     int encrypted;
150 
151     int isZip64;
152 
153 #    ifndef NOUNCRYPT
154     unsigned long keys[3];     /* keys defining the pseudo-random sequence */
155     const unsigned long* pcrc_32_tab;
156 #    endif
157 } unz_s;
158 
159 #ifndef NOUNCRYPT
160 #include "crypt.h"
161 #endif
162 
163 /* ===========================================================================
164      Read a byte from a gz_stream; update next_in and avail_in. Return EOF
165    for end of file.
166    IN assertion: the stream s has been successfully opened for reading.
167 */
168 
unzlocal_getByte(const zlib_filefunc_def * pzlib_filefunc_def,voidpf filestream,int * pi)169 static int unzlocal_getByte( const zlib_filefunc_def* pzlib_filefunc_def,
170                              voidpf filestream, int *pi )
171 {
172     unsigned char c = 0;
173     const int err =
174         static_cast<int>(ZREAD(*pzlib_filefunc_def, filestream, &c, 1));
175     if (err==1)
176     {
177         *pi = static_cast<int>(c);
178         return UNZ_OK;
179     }
180     else
181     {
182         if (ZERROR(*pzlib_filefunc_def,filestream))
183             return UNZ_ERRNO;
184         else
185             return UNZ_EOF;
186     }
187 }
188 
189 /* ===========================================================================
190    Reads a long in LSB order from the given gz_stream. Sets
191 */
unzlocal_getShort(const zlib_filefunc_def * pzlib_filefunc_def,voidpf filestream,uLong * pX)192 static int unzlocal_getShort (const zlib_filefunc_def* pzlib_filefunc_def,
193                              voidpf filestream,
194                              uLong *pX)
195 {
196     int i = 0;
197     int err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
198     uLong x = static_cast<uLong>(i);
199 
200     if (err==UNZ_OK)
201         err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
202     x += static_cast<uLong>(i)<<8;
203 
204     if (err==UNZ_OK)
205         *pX = x;
206     else
207         *pX = 0;
208     return err;
209 }
210 
unzlocal_getLong(const zlib_filefunc_def * pzlib_filefunc_def,voidpf filestream,uLong * pX)211 static int unzlocal_getLong (const zlib_filefunc_def* pzlib_filefunc_def,
212                             voidpf filestream,
213                             uLong *pX)
214 {
215     int i = 0;
216     int err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
217     uLong x = static_cast<uLong>(i);
218 
219     if (err==UNZ_OK)
220         err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
221     x += static_cast<uLong>(i)<<8;
222 
223     if (err==UNZ_OK)
224         err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
225     x += static_cast<uLong>(i)<<16;
226 
227     if (err==UNZ_OK)
228         err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
229     x += static_cast<uLong>(i)<<24;
230 
231     if (err==UNZ_OK)
232         *pX = x;
233     else
234         *pX = 0;
235     return err;
236 }
237 
unzlocal_getLong64(const zlib_filefunc_def * pzlib_filefunc_def,voidpf filestream,uLong64 * pX)238 static int unzlocal_getLong64 (const zlib_filefunc_def* pzlib_filefunc_def,
239                             voidpf filestream,
240                             uLong64 *pX)
241 {
242     int i = 0;
243     int err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
244     uLong64 x = static_cast<uLong64>(i);
245 
246     if (err==UNZ_OK)
247         err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
248     x += static_cast<uLong64>(i)<<8;
249 
250     if (err==UNZ_OK)
251         err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
252     x += static_cast<uLong64>(i)<<16;
253 
254     if (err==UNZ_OK)
255         err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
256     x += static_cast<uLong64>(i)<<24;
257 
258     if (err==UNZ_OK)
259         err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
260     x += static_cast<uLong64>(i)<<32;
261 
262     if (err==UNZ_OK)
263         err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
264     x += static_cast<uLong64>(i)<<40;
265 
266     if (err==UNZ_OK)
267         err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
268     x += static_cast<uLong64>(i)<<48;
269 
270     if (err==UNZ_OK)
271         err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
272     x += static_cast<uLong64>(i)<<56;
273 
274     if (err==UNZ_OK)
275         *pX = x;
276     else
277         *pX = 0;
278     return err;
279 }
280 
281 /* My own strcmpi / strcasecmp */
strcmpcasenosensitive_internal(const char * fileName1,const char * fileName2)282 static int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2)
283 {
284     for (;;)
285     {
286         char c1=*(fileName1++);
287         char c2=*(fileName2++);
288         if ((c1>='a') && (c1<='z'))
289             c1 -= 0x20;
290         if ((c2>='a') && (c2<='z'))
291             c2 -= 0x20;
292         if (c1=='\0')
293             return ((c2=='\0') ? 0 : -1);
294         if (c2=='\0')
295             return 1;
296         if (c1<c2)
297             return -1;
298         if (c1>c2)
299             return 1;
300     }
301 }
302 
303 #ifdef  CASESENSITIVITYDEFAULT_NO
304 #define CASESENSITIVITYDEFAULTVALUE 2
305 #else
306 #define CASESENSITIVITYDEFAULTVALUE 1
307 #endif
308 
309 #ifndef STRCMPCASENOSENTIVEFUNCTION
310 #define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
311 #endif
312 
313 /*
314    Compare two filename (fileName1,fileName2).
315    If iCaseSenisivity = 1, comparison is case sensitivity (like strcmp)
316    If iCaseSenisivity = 2, comparison is not case sensitivity (like strcmpi
317                                                                or strcasecmp)
318    If iCaseSenisivity = 0, case sensitivity is default of your operating system
319         (like 1 on Unix, 2 on Windows)
320 
321 */
cpl_unzStringFileNameCompare(const char * fileName1,const char * fileName2,int iCaseSensitivity)322 extern int ZEXPORT cpl_unzStringFileNameCompare (const char*  fileName1,
323                                                  const char*  fileName2,
324                                                  int iCaseSensitivity)
325 
326 {
327     if (iCaseSensitivity==0)
328         iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
329 
330     if (iCaseSensitivity==1)
331         return strcmp(fileName1,fileName2);
332 
333     return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
334 }
335 
336 #ifndef BUFREADCOMMENT
337 #define BUFREADCOMMENT (0x400)
338 #endif
339 
340 /*
341   Locate the Central directory of a zipfile (at the end, just before
342     the global comment)
343 */
unzlocal_SearchCentralDir(const zlib_filefunc_def * pzlib_filefunc_def,voidpf filestream)344 static uLong64 unzlocal_SearchCentralDir(const zlib_filefunc_def* pzlib_filefunc_def,
345                                       voidpf filestream)
346 {
347     if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
348         return 0;
349 
350     unsigned char* buf = static_cast<unsigned char*>(ALLOC(BUFREADCOMMENT+4));
351     if (buf==nullptr)
352         return 0;
353 
354     const uLong64 uSizeFile = ZTELL(*pzlib_filefunc_def,filestream);
355 
356     uLong64 uMaxBack=0xffff; /* maximum size of global comment */
357     if (uMaxBack>uSizeFile)
358         uMaxBack = uSizeFile;
359 
360     uLong64 uPosFound=0;
361     uLong64 uBackRead = 4;
362     while (uBackRead<uMaxBack)
363     {
364         if (uBackRead+BUFREADCOMMENT>uMaxBack)
365             uBackRead = uMaxBack;
366         else
367             uBackRead+=BUFREADCOMMENT;
368         const uLong64 uReadPos = uSizeFile - uBackRead;
369 
370         const uLong uReadSize =
371             ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
372             (BUFREADCOMMENT+4) : static_cast<uLong>(uSizeFile-uReadPos);
373         if( ZSEEK(*pzlib_filefunc_def, filestream, uReadPos,
374                   ZLIB_FILEFUNC_SEEK_SET) != 0 )
375             break;
376 
377         if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
378             break;
379 
380         // TODO(schwehr): Fix where the decrement is in this for loop.
381         for( int i = static_cast<int>(uReadSize)  -3; (i--) > 0; )
382             if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
383                 ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
384             {
385                 uPosFound = uReadPos+i;
386                 break;
387             }
388 
389         if (uPosFound!=0)
390             break;
391     }
392     TRYFREE(buf);
393     return uPosFound;
394 }
395 
396 /*
397   Locate the Central directory 64 of a zipfile (at the end, just before
398     the global comment)
399 */
400 static uLong64
unzlocal_SearchCentralDir64(const zlib_filefunc_def * pzlib_filefunc_def,voidpf filestream)401 unzlocal_SearchCentralDir64( const zlib_filefunc_def* pzlib_filefunc_def,
402                              voidpf filestream )
403 {
404     unsigned char* buf;
405     uLong64 uSizeFile;
406     uLong64 uBackRead;
407     uLong64 uMaxBack=0xffff; /* maximum size of global comment */
408     uLong64 uPosFound=0;
409     uLong uL;
410 
411     if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
412         return 0;
413 
414     uSizeFile = ZTELL(*pzlib_filefunc_def,filestream);
415 
416     if (uMaxBack>uSizeFile)
417         uMaxBack = uSizeFile;
418 
419     buf = static_cast<unsigned char*>(ALLOC(BUFREADCOMMENT+4));
420     if (buf==nullptr)
421         return 0;
422 
423     uBackRead = 4;
424     while (uBackRead<uMaxBack)
425     {
426         uLong uReadSize;
427         uLong64 uReadPos;
428         if (uBackRead+BUFREADCOMMENT>uMaxBack)
429             uBackRead = uMaxBack;
430         else
431             uBackRead+=BUFREADCOMMENT;
432         uReadPos = uSizeFile-uBackRead;
433 
434         uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
435                      (BUFREADCOMMENT+4) : static_cast<uLong>(uSizeFile-uReadPos);
436         if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
437             break;
438 
439         if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
440             break;
441 
442         for( int i =static_cast<int>(uReadSize) - 3; (i--) > 0; )
443             if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
444                 ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))
445             {
446                 uPosFound = uReadPos+i;
447                 break;
448             }
449 
450         if (uPosFound!=0)
451             break;
452     }
453     TRYFREE(buf);
454     if (uPosFound == 0)
455         return 0;
456 
457     /* Zip64 end of central directory locator */
458     if (ZSEEK(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
459         return 0;
460 
461     /* the signature, already checked */
462     if (unzlocal_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
463         return 0;
464 
465     /* number of the disk with the start of the zip64 end of  central directory */
466     if (unzlocal_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
467         return 0;
468     if (uL != 0)
469         return 0;
470 
471     /* relative offset of the zip64 end of central directory record */
472     uLong64 relativeOffset;
473     if (unzlocal_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK)
474         return 0;
475 
476     /* total number of disks */
477     if (unzlocal_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
478         return 0;
479     /* Some .zip declare 0 disks, such as in http://trac.osgeo.org/gdal/ticket/5615 */
480     if (uL != 1 && uL != 0)
481         return 0;
482 
483     /* Goto end of central directory record */
484     if (ZSEEK(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)
485         return 0;
486 
487      /* the signature */
488     if (unzlocal_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
489         return 0;
490 
491     if (uL != 0x06064b50)
492         return 0;
493 
494     return relativeOffset;
495 }
496 
497 /*
498   Open a Zip file. path contain the full pathname (by example,
499      on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer
500      "zlib/zlib114.zip".
501      If the zipfile cannot be opened (file doesn't exist or in not valid), the
502        return value is NULL.
503      Else, the return value is a unzFile Handle, usable with other function
504        of this unzip package.
505 */
cpl_unzOpen2(const char * path,zlib_filefunc_def * pzlib_filefunc_def)506 extern unzFile ZEXPORT cpl_unzOpen2 (const char *path,
507                                      zlib_filefunc_def* pzlib_filefunc_def)
508 {
509     unz_s us;
510     unz_s *s;
511     uLong64 central_pos;
512     uLong   uL;
513 
514     uLong number_disk;          /* number of the current dist, used for
515                                    spanning ZIP, unsupported, always 0*/
516     uLong number_disk_with_CD;  /* number the disk with central dir, used
517                                    for spanning ZIP, unsupported, always 0*/
518     uLong64 number_entry_CD;      /* total number of entries in
519                                    the central dir
520                                    (same than number_entry on nospan) */
521 
522     int err=UNZ_OK;
523 
524     memset(&us, 0, sizeof(us));
525 
526     // Must be a trick to ensure that unz_copyright remains in the binary!
527     // cppcheck-suppress knownConditionTrueFalse
528     if (unz_copyright[0]!=' ')
529         return nullptr;
530 
531     if (pzlib_filefunc_def==nullptr)
532         cpl_fill_fopen_filefunc(&us.z_filefunc);
533     else
534         us.z_filefunc = *pzlib_filefunc_def;
535 
536     us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque,
537                                                  path,
538                                                  ZLIB_FILEFUNC_MODE_READ |
539                                                  ZLIB_FILEFUNC_MODE_EXISTING);
540     if (us.filestream==nullptr)
541         return nullptr;
542 
543     central_pos = unzlocal_SearchCentralDir64(&us.z_filefunc,us.filestream);
544     if (central_pos)
545     {
546         uLong uS;
547         uLong64 uL64;
548 
549         us.isZip64 = 1;
550 
551         if (ZSEEK(us.z_filefunc, us.filestream,
552                                       central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
553         err=UNZ_ERRNO;
554 
555         /* the signature, already checked */
556         if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
557             err=UNZ_ERRNO;
558 
559         /* size of zip64 end of central directory record */
560         if (unzlocal_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK)
561             err=UNZ_ERRNO;
562 
563         /* version made by */
564         if (unzlocal_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)
565             err=UNZ_ERRNO;
566 
567         /* version needed to extract */
568         if (unzlocal_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)
569             err=UNZ_ERRNO;
570 
571         /* number of this disk */
572         if (unzlocal_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
573             err=UNZ_ERRNO;
574 
575         /* number of the disk with the start of the central directory */
576         if (unzlocal_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
577             err=UNZ_ERRNO;
578 
579         /* total number of entries in the central directory on this disk */
580         if (unzlocal_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK)
581             err=UNZ_ERRNO;
582 
583         /* total number of entries in the central directory */
584         if (unzlocal_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK)
585             err=UNZ_ERRNO;
586 
587         if ((number_entry_CD!=us.gi.number_entry) ||
588             (number_disk_with_CD!=0) ||
589             (number_disk!=0))
590             err=UNZ_BADZIPFILE;
591 
592         /* size of the central directory */
593         if (unzlocal_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK)
594             err=UNZ_ERRNO;
595 
596         /* offset of start of central directory with respect to the
597           starting disk number */
598         if (unzlocal_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK)
599             err=UNZ_ERRNO;
600 
601         us.gi.size_comment = 0;
602     }
603     else
604     {
605         central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream);
606         if (central_pos==0)
607             err=UNZ_ERRNO;
608 
609         us.isZip64 = 0;
610 
611         if (ZSEEK(us.z_filefunc, us.filestream,
612                                         central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
613             err=UNZ_ERRNO;
614 
615         /* the signature, already checked */
616         if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
617             err=UNZ_ERRNO;
618 
619         /* number of this disk */
620         if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
621             err=UNZ_ERRNO;
622 
623         /* number of the disk with the start of the central directory */
624         if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
625             err=UNZ_ERRNO;
626 
627         /* total number of entries in the central dir on this disk */
628         if (unzlocal_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
629             err=UNZ_ERRNO;
630         us.gi.number_entry = uL;
631 
632         /* total number of entries in the central dir */
633         if (unzlocal_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
634             err=UNZ_ERRNO;
635         number_entry_CD = uL;
636 
637         if ((number_entry_CD!=us.gi.number_entry) ||
638             (number_disk_with_CD!=0) ||
639             (number_disk!=0))
640             err=UNZ_BADZIPFILE;
641 
642         /* size of the central directory */
643         if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
644             err=UNZ_ERRNO;
645         us.size_central_dir = uL;
646 
647         /* offset of start of central directory with respect to the
648             starting disk number */
649         if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
650             err=UNZ_ERRNO;
651         us.offset_central_dir = uL;
652 
653         /* zipfile comment length */
654         if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK)
655             err=UNZ_ERRNO;
656     }
657 
658     if ((central_pos<us.offset_central_dir+us.size_central_dir) &&
659         (err==UNZ_OK))
660         err=UNZ_BADZIPFILE;
661 
662     if (err!=UNZ_OK)
663     {
664         ZCLOSE(us.z_filefunc, us.filestream);
665         return nullptr;
666     }
667 
668     us.byte_before_the_zipfile = central_pos -
669                             (us.offset_central_dir+us.size_central_dir);
670     us.central_pos = central_pos;
671     us.pfile_in_zip_read = nullptr;
672     us.encrypted = 0;
673     us.num_file = 0;
674     us.pos_in_central_dir = 0;
675     us.current_file_ok = 0;
676 
677     s=static_cast<unz_s*>(ALLOC(sizeof(unz_s)));
678     *s=us;
679     cpl_unzGoToFirstFile(reinterpret_cast<unzFile>(s));
680     return reinterpret_cast<unzFile>(s);
681 }
682 
cpl_unzOpen(const char * path)683 extern unzFile ZEXPORT cpl_unzOpen (const char *path)
684 {
685     return cpl_unzOpen2(path, nullptr);
686 }
687 
688 /*
689   Close a ZipFile opened with unzipOpen.
690   If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
691     these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
692   return UNZ_OK if there is no problem. */
cpl_unzClose(unzFile file)693 extern int ZEXPORT cpl_unzClose (unzFile file)
694 {
695     unz_s* s;
696     if (file==nullptr)
697         return UNZ_PARAMERROR;
698     s=reinterpret_cast<unz_s*>(file);
699 
700     if (s->pfile_in_zip_read!=nullptr)
701         cpl_unzCloseCurrentFile(file);
702 
703     ZCLOSE(s->z_filefunc, s->filestream);
704     TRYFREE(s);
705     return UNZ_OK;
706 }
707 
708 /*
709   Write info about the ZipFile in the *pglobal_info structure.
710   No preparation of the structure is needed
711   return UNZ_OK if there is no problem. */
cpl_unzGetGlobalInfo(unzFile file,unz_global_info * pglobal_info)712 extern int ZEXPORT cpl_unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info)
713 {
714     unz_s* s;
715     if (file==nullptr)
716         return UNZ_PARAMERROR;
717     s=reinterpret_cast<unz_s*>(file);
718     *pglobal_info=s->gi;
719     return UNZ_OK;
720 }
721 
722 /*
723    Translate date/time from Dos format to tm_unz (readable more easily).
724 */
unzlocal_DosDateToTmuDate(uLong64 ulDosDate,tm_unz * ptm)725 static void unzlocal_DosDateToTmuDate (uLong64 ulDosDate, tm_unz* ptm)
726 {
727     uLong64 uDate;
728     uDate = static_cast<uLong64>(ulDosDate>>16);
729     ptm->tm_mday = static_cast<uInt>(uDate&0x1f);
730     ptm->tm_mon =  static_cast<uInt>(((uDate)&0x1E0)/0x20);
731     if( ptm->tm_mon )
732         ptm->tm_mon --;
733     ptm->tm_year = static_cast<uInt>(((uDate&0x0FE00)/0x0200)+1980);
734 
735     ptm->tm_hour = static_cast<uInt>((ulDosDate &0xF800)/0x800);
736     ptm->tm_min =  static_cast<uInt>((ulDosDate&0x7E0)/0x20);
737     ptm->tm_sec =  static_cast<uInt>(2*(ulDosDate&0x1f));
738 }
739 
740 /*
741   Get Info about the current file in the zipfile, with internal only info
742 */
unzlocal_GetCurrentFileInfoInternal(unzFile file,unz_file_info * pfile_info,unz_file_info_internal * pfile_info_internal,char * szFileName,uLong fileNameBufferSize,void *,uLong,char *,uLong)743 static int unzlocal_GetCurrentFileInfoInternal (
744     unzFile file,
745     unz_file_info *pfile_info,
746     unz_file_info_internal
747     *pfile_info_internal,
748     char *szFileName,
749     uLong fileNameBufferSize,
750     void * /* extraField */,
751     uLong /* extraFieldBufferSize */,
752     char * /* szComment */,
753     uLong /* commentBufferSize */ )
754 {
755     unz_s* s;
756     unz_file_info file_info;
757     unz_file_info_internal file_info_internal;
758     int err=UNZ_OK;
759     uLong uMagic;
760     long lSeek=0;
761     uLong uL;
762     bool bHasUTF8Filename = false;
763 
764     if (file==nullptr)
765         return UNZ_PARAMERROR;
766     s=reinterpret_cast<unz_s*>(file);
767     if (ZSEEK(s->z_filefunc, s->filestream,
768               s->pos_in_central_dir+s->byte_before_the_zipfile,
769               ZLIB_FILEFUNC_SEEK_SET)!=0)
770         err=UNZ_ERRNO;
771 
772     /* we check the magic */
773     if (err==UNZ_OK)
774     {
775         if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
776             err=UNZ_ERRNO;
777         else if (uMagic!=0x02014b50)
778             err=UNZ_BADZIPFILE;
779     }
780 
781     if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK)
782         err=UNZ_ERRNO;
783 
784     if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK)
785         err=UNZ_ERRNO;
786 
787     if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK)
788         err=UNZ_ERRNO;
789 
790     if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK)
791         err=UNZ_ERRNO;
792 
793     if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK)
794         err=UNZ_ERRNO;
795 
796     unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
797 
798     if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK)
799         err=UNZ_ERRNO;
800 
801     if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
802         err=UNZ_ERRNO;
803     file_info.compressed_size = uL;
804 
805     if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
806         err=UNZ_ERRNO;
807     file_info.uncompressed_size = uL;
808 
809     if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK)
810         err=UNZ_ERRNO;
811 
812     if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK)
813         err=UNZ_ERRNO;
814 
815     if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK)
816         err=UNZ_ERRNO;
817 
818     if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)
819         err=UNZ_ERRNO;
820 
821     if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK)
822         err=UNZ_ERRNO;
823 
824     if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK)
825         err=UNZ_ERRNO;
826 
827     if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
828         err=UNZ_ERRNO;
829     file_info_internal.offset_curfile = uL;
830 
831     lSeek+=file_info.size_filename;
832     if ((err==UNZ_OK) && (szFileName!=nullptr))
833     {
834         uLong uSizeRead = 0;
835         if (file_info.size_filename<fileNameBufferSize)
836         {
837             *(szFileName+file_info.size_filename)='\0';
838             uSizeRead = file_info.size_filename;
839         }
840         else
841             uSizeRead = fileNameBufferSize;
842 
843         if ((file_info.size_filename>0) && (fileNameBufferSize>0))
844         {
845             if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead)
846                 err=UNZ_ERRNO;
847         }
848         lSeek -= uSizeRead;
849     }
850 
851 #if 0
852     if ((err==UNZ_OK) && (extraField != nullptr))
853     {
854         uLong64 uSizeRead = 0;
855         if (file_info.size_file_extra<extraFieldBufferSize)
856             uSizeRead = file_info.size_file_extra;
857         else
858             uSizeRead = extraFieldBufferSize;
859 
860         if (lSeek!=0)
861         {
862             if (ZSEEK(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
863                 lSeek=0;
864             else
865                 err=UNZ_ERRNO;
866         }
867 
868         if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
869             if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead)
870                 err=UNZ_ERRNO;
871         lSeek += file_info.size_file_extra - uSizeRead;
872     }
873     else
874         lSeek+=file_info.size_file_extra;
875 #endif
876     if ((err==UNZ_OK) && (file_info.size_file_extra != 0))
877     {
878         if (lSeek!=0)
879         {
880             if (ZSEEK(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
881             {
882                 lSeek=0;
883                 CPL_IGNORE_RET_VAL(lSeek);
884             }
885             else
886                 err=UNZ_ERRNO;
887         }
888 
889         uLong acc = 0;
890         while(acc < file_info.size_file_extra)
891         {
892             uLong headerId;
893             if (unzlocal_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK)
894                 err=UNZ_ERRNO;
895 
896             uLong dataSize;
897             if (unzlocal_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK)
898                 err=UNZ_ERRNO;
899 
900             /* ZIP64 extra fields */
901             if (headerId == 0x0001)
902             {
903                 uLong64 u64;
904                 if( file_info.uncompressed_size == 0xFFFFFFFF )
905                 {
906                     if (unzlocal_getLong64(&s->z_filefunc, s->filestream,&u64) != UNZ_OK)
907                         err=UNZ_ERRNO;
908                     file_info.uncompressed_size = u64;
909                 }
910 
911                 if( file_info.compressed_size == 0xFFFFFFFF )
912                 {
913                     if (unzlocal_getLong64(&s->z_filefunc, s->filestream,&u64) != UNZ_OK)
914                         err=UNZ_ERRNO;
915                     file_info.compressed_size = u64;
916                 }
917 
918                 /* Relative Header offset */
919                 if( file_info_internal.offset_curfile == 0xFFFFFFFF )
920                 {
921                     if (unzlocal_getLong64(&s->z_filefunc, s->filestream,&u64) != UNZ_OK)
922                         err=UNZ_ERRNO;
923                     file_info_internal.offset_curfile = u64;
924                 }
925 
926                 /* Disk Start Number */
927                 if( file_info.disk_num_start == 0xFFFF )
928                 {
929                     uLong uLstart;
930                     if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uLstart) != UNZ_OK)
931                         err=UNZ_ERRNO;
932                     file_info.disk_num_start = uLstart;
933                 }
934             }
935             /* Info-ZIP Unicode Path Extra Field (0x7075) */
936             else if( headerId == 0x7075 && dataSize > 5 &&
937                      file_info.size_filename<=fileNameBufferSize &&
938                      szFileName != nullptr )
939             {
940                 int version = 0;
941                 if (unzlocal_getByte(&s->z_filefunc, s->filestream,&version) != UNZ_OK)
942                     err=UNZ_ERRNO;
943                 if( version != 1 )
944                 {
945                     /* If version != 1, ignore that extra field */
946                     if (ZSEEK(s->z_filefunc, s->filestream,dataSize - 1,ZLIB_FILEFUNC_SEEK_CUR)!=0)
947                         err=UNZ_ERRNO;
948                 }
949                 else
950                 {
951                     uLong nameCRC32;
952                     if (unzlocal_getLong(&s->z_filefunc, s->filestream,&nameCRC32) != UNZ_OK)
953                         err=UNZ_ERRNO;
954 
955                     /* Check expected CRC for filename */
956                     if( nameCRC32 == crc32(0, reinterpret_cast<const Bytef*>(szFileName), static_cast<uInt>(file_info.size_filename)) )
957                     {
958                         const uLong utf8Size = dataSize - 1 - 4;
959                         uLong uSizeRead = 0;
960 
961                         bHasUTF8Filename = true;
962 
963                         if (utf8Size<fileNameBufferSize)
964                         {
965                             *(szFileName+utf8Size)='\0';
966                             uSizeRead = utf8Size;
967                         }
968                         else
969                             uSizeRead = fileNameBufferSize;
970 
971                         if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead)
972                             err=UNZ_ERRNO;
973                         else if( utf8Size > fileNameBufferSize )
974                         {
975                             if (ZSEEK(s->z_filefunc, s->filestream,utf8Size - fileNameBufferSize,ZLIB_FILEFUNC_SEEK_CUR)!=0)
976                                 err=UNZ_ERRNO;
977                         }
978                     }
979                     else
980                     {
981                         /* ignore unicode name if CRC mismatch */
982                         if (ZSEEK(s->z_filefunc, s->filestream,dataSize - 1- 4,ZLIB_FILEFUNC_SEEK_CUR)!=0)
983                                 err=UNZ_ERRNO;
984                     }
985                 }
986             }
987             else
988             {
989                 if (ZSEEK(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0)
990                     err=UNZ_ERRNO;
991             }
992 
993             acc += 2 + 2 + dataSize;
994         }
995     }
996 
997     if( !bHasUTF8Filename && szFileName != nullptr &&
998         (file_info.flag & (1 << 11)) == 0 &&
999         file_info.size_filename<fileNameBufferSize )
1000     {
1001         const char* pszSrcEncoding = CPLGetConfigOption("CPL_ZIP_ENCODING",
1002 #if defined(_WIN32) && !defined(HAVE_ICONV)
1003                                                         "CP_OEMCP"
1004 #else
1005                                                         "CP437"
1006 #endif
1007                                                         );
1008         char* pszRecoded = CPLRecode(szFileName, pszSrcEncoding, CPL_ENC_UTF8);
1009         if( pszRecoded != nullptr && strlen(pszRecoded) < fileNameBufferSize)
1010         {
1011             strcpy(szFileName, pszRecoded);
1012         }
1013         CPLFree(pszRecoded);
1014     }
1015 
1016 #if 0
1017     if ((err==UNZ_OK) && (szComment != nullptr))
1018     {
1019         uLong64 uSizeRead = 0;
1020         if (file_info.size_file_comment<commentBufferSize)
1021         {
1022             *(szComment+file_info.size_file_comment)='\0';
1023             uSizeRead = file_info.size_file_comment;
1024         }
1025         else
1026             uSizeRead = commentBufferSize;
1027 
1028         if (lSeek!=0)
1029         {
1030             if (ZSEEK(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
1031                 lSeek=0;
1032             else
1033                 err=UNZ_ERRNO;
1034         }
1035 
1036         if ((file_info.size_file_comment>0) && (commentBufferSize>0))
1037             if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)
1038                 err=UNZ_ERRNO;
1039         lSeek+=file_info.size_file_comment - uSizeRead;
1040     }
1041     else
1042         lSeek+=file_info.size_file_comment;
1043 #endif
1044 
1045     if ((err==UNZ_OK) && (pfile_info!=nullptr))
1046         *pfile_info=file_info;
1047 
1048     if ((err==UNZ_OK) && (pfile_info_internal!=nullptr))
1049         *pfile_info_internal=file_info_internal;
1050 
1051     return err;
1052 }
1053 
1054 /*
1055   Write info about the ZipFile in the *pglobal_info structure.
1056   No preparation of the structure is needed
1057   return UNZ_OK if there is no problem.
1058 */
cpl_unzGetCurrentFileInfo(unzFile file,unz_file_info * pfile_info,char * szFileName,uLong fileNameBufferSize,void * extraField,uLong extraFieldBufferSize,char * szComment,uLong commentBufferSize)1059 extern int ZEXPORT cpl_unzGetCurrentFileInfo (unzFile file,
1060                                           unz_file_info * pfile_info,
1061                                           char * szFileName, uLong fileNameBufferSize,
1062                                           void *extraField, uLong extraFieldBufferSize,
1063                                           char* szComment,  uLong commentBufferSize)
1064 {
1065     return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,nullptr,
1066                                                 szFileName,fileNameBufferSize,
1067                                                 extraField,extraFieldBufferSize,
1068                                                 szComment,commentBufferSize);
1069 }
1070 
1071 /*
1072   Set the current file of the zipfile to the first file.
1073   return UNZ_OK if there is no problem
1074 */
cpl_unzGoToFirstFile(unzFile file)1075 extern int ZEXPORT cpl_unzGoToFirstFile (unzFile file)
1076 {
1077     int err=UNZ_OK;
1078     unz_s* s;
1079     if (file==nullptr)
1080         return UNZ_PARAMERROR;
1081     s=reinterpret_cast<unz_s*>(file);
1082     s->pos_in_central_dir=s->offset_central_dir;
1083     s->num_file=0;
1084     err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
1085                                              &s->cur_file_info_internal,
1086                                              nullptr,0,nullptr,0,nullptr,0);
1087     s->current_file_ok = (err == UNZ_OK);
1088     return err;
1089 }
1090 
1091 /*
1092   Set the current file of the zipfile to the next file.
1093   return UNZ_OK if there is no problem
1094   return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
1095 */
cpl_unzGoToNextFile(unzFile file)1096 extern int ZEXPORT cpl_unzGoToNextFile (unzFile  file)
1097 {
1098     unz_s* s;
1099 
1100     if (file==nullptr)
1101         return UNZ_PARAMERROR;
1102     s=reinterpret_cast<unz_s*>(file);
1103     if (!s->current_file_ok)
1104         return UNZ_END_OF_LIST_OF_FILE;
1105     if (s->gi.number_entry != 0xffff)    /* 2^16 files overflow hack */
1106       if (s->num_file+1==s->gi.number_entry)
1107         return UNZ_END_OF_LIST_OF_FILE;
1108 
1109     s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
1110             s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment;
1111     s->num_file++;
1112     int err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
1113                                                &s->cur_file_info_internal,
1114                                                nullptr,0,nullptr,0,nullptr,0);
1115     s->current_file_ok = (err == UNZ_OK);
1116     return err;
1117 }
1118 
1119 /*
1120   Try locate the file szFileName in the zipfile.
1121   For the iCaseSensitivity signification, see unzipStringFileNameCompare
1122 
1123   return value :
1124   UNZ_OK if the file is found. It becomes the current file.
1125   UNZ_END_OF_LIST_OF_FILE if the file is not found
1126 */
cpl_unzLocateFile(unzFile file,const char * szFileName,int iCaseSensitivity)1127 extern int ZEXPORT cpl_unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity)
1128 {
1129     unz_s* s;
1130 
1131     /* We remember the 'current' position in the file so that we can jump
1132      * back there if we fail.
1133      */
1134     unz_file_info cur_file_infoSaved;
1135     unz_file_info_internal cur_file_info_internalSaved;
1136     uLong64 num_fileSaved;
1137     uLong64 pos_in_central_dirSaved;
1138 
1139     if (file==nullptr)
1140         return UNZ_PARAMERROR;
1141 
1142     if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
1143         return UNZ_PARAMERROR;
1144 
1145     s=reinterpret_cast<unz_s*>(file);
1146     if (!s->current_file_ok)
1147         return UNZ_END_OF_LIST_OF_FILE;
1148 
1149     /* Save the current state */
1150     num_fileSaved = s->num_file;
1151     pos_in_central_dirSaved = s->pos_in_central_dir;
1152     cur_file_infoSaved = s->cur_file_info;
1153     cur_file_info_internalSaved = s->cur_file_info_internal;
1154 
1155     int err = cpl_unzGoToFirstFile(file);
1156 
1157     while (err == UNZ_OK)
1158     {
1159         char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
1160         err = cpl_unzGetCurrentFileInfo(file,nullptr,
1161                                     szCurrentFileName,sizeof(szCurrentFileName)-1,
1162                                     nullptr,0,nullptr,0);
1163         if (err == UNZ_OK)
1164         {
1165             if (cpl_unzStringFileNameCompare(szCurrentFileName,
1166                                             szFileName,iCaseSensitivity)==0)
1167                 return UNZ_OK;
1168             err = cpl_unzGoToNextFile(file);
1169         }
1170     }
1171 
1172     /* We failed, so restore the state of the 'current file' to where we
1173      * were.
1174      */
1175     s->num_file = num_fileSaved;
1176     s->pos_in_central_dir = pos_in_central_dirSaved;
1177     s->cur_file_info = cur_file_infoSaved;
1178     s->cur_file_info_internal = cur_file_info_internalSaved;
1179     return err;
1180 }
1181 
1182 /*
1183 ///////////////////////////////////////////
1184 // Contributed by Ryan Haksi (mailto://cryogen@infoserve.net)
1185 // I need random access
1186 //
1187 // Further optimization could be realized by adding an ability
1188 // to cache the directory in memory. The goal being a single
1189 // comprehensive file read to put the file I need in a memory.
1190 */
1191 
1192 /*
1193 typedef struct unz_file_pos_s
1194 {
1195     uLong64 pos_in_zip_directory;   // offset in file
1196     uLong64 num_of_file;            // # of file
1197 } unz_file_pos;
1198 */
1199 
cpl_unzGetFilePos(unzFile file,unz_file_pos * file_pos)1200 extern int ZEXPORT cpl_unzGetFilePos(unzFile file, unz_file_pos*  file_pos)
1201 {
1202     unz_s* s;
1203 
1204     if (file==nullptr || file_pos==nullptr)
1205         return UNZ_PARAMERROR;
1206     s=reinterpret_cast<unz_s*>(file);
1207     if (!s->current_file_ok)
1208         return UNZ_END_OF_LIST_OF_FILE;
1209 
1210     file_pos->pos_in_zip_directory  = s->pos_in_central_dir;
1211     file_pos->num_of_file           = s->num_file;
1212 
1213     return UNZ_OK;
1214 }
1215 
cpl_unzGoToFilePos(unzFile file,unz_file_pos * file_pos)1216 extern int ZEXPORT cpl_unzGoToFilePos(unzFile file, unz_file_pos* file_pos)
1217 {
1218     unz_s* s;
1219 
1220     if (file==nullptr || file_pos==nullptr)
1221         return UNZ_PARAMERROR;
1222     s=reinterpret_cast<unz_s*>(file);
1223 
1224     /* jump to the right spot */
1225     s->pos_in_central_dir = file_pos->pos_in_zip_directory;
1226     s->num_file           = file_pos->num_of_file;
1227 
1228     /* set the current file */
1229     int err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
1230                                                   &s->cur_file_info_internal,
1231                                                   nullptr,0,nullptr,0,nullptr,0);
1232     /* return results */
1233     s->current_file_ok = (err == UNZ_OK);
1234     return err;
1235 }
1236 
1237 /*
1238 // Unzip Helper Functions - should be here?
1239 ///////////////////////////////////////////
1240 */
1241 
1242 /*
1243   Read the local header of the current zipfile
1244   Check the coherency of the local header and info in the end of central
1245         directory about this file
1246   store in *piSizeVar the size of extra info in local header
1247         (filename and size of extra field data)
1248 */
unzlocal_CheckCurrentFileCoherencyHeader(unz_s * s,uInt * piSizeVar,uLong64 * poffset_local_extrafield,uInt * psize_local_extrafield)1249 static int unzlocal_CheckCurrentFileCoherencyHeader (unz_s* s, uInt* piSizeVar,
1250                                                     uLong64 * poffset_local_extrafield,
1251                                                     uInt  * psize_local_extrafield)
1252 {
1253     uLong uMagic,uData,uFlags;
1254     uLong size_filename;
1255     uLong size_extra_field;
1256     int err=UNZ_OK;
1257 
1258     *piSizeVar = 0;
1259     *poffset_local_extrafield = 0;
1260     *psize_local_extrafield = 0;
1261 
1262     if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile +
1263                                 s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)
1264         return UNZ_ERRNO;
1265 
1266     if (err==UNZ_OK)
1267     {
1268         if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
1269             err=UNZ_ERRNO;
1270         else if (uMagic!=0x04034b50)
1271             err=UNZ_BADZIPFILE;
1272     }
1273 
1274     if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
1275         err=UNZ_ERRNO;
1276 /*
1277     else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
1278         err=UNZ_BADZIPFILE;
1279 */
1280     if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK)
1281         err=UNZ_ERRNO;
1282 
1283     if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
1284         err=UNZ_ERRNO;
1285     else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
1286         err=UNZ_BADZIPFILE;
1287 
1288     if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
1289                          (s->cur_file_info.compression_method!=Z_DEFLATED))
1290     {
1291         if( s->cur_file_info.compression_method == 9 )
1292         {
1293             // Could potentially be handled by using the (unsupported)
1294             // code at https://github.com/madler/zlib/tree/master/contrib/infback9
1295             // Actually the infack9 API doesn't look very suitable as it
1296             // processes the whole stream with in() and out() callbacks...
1297             CPLError(CE_Failure, CPLE_NotSupported,
1298                      "A file in the ZIP archive uses the Deflate64 unsupported "
1299                      "compression method. You can uncompress priorly with the "
1300                      "unzip utility.");
1301         }
1302         else
1303         {
1304             CPLError(CE_Failure, CPLE_NotSupported,
1305                      "A file in the ZIP archive uses a unsupported "
1306                      "compression method (%lu)",
1307                      s->cur_file_info.compression_method);
1308         }
1309         err=UNZ_BADZIPFILE;
1310     }
1311 
1312     if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */
1313         err=UNZ_ERRNO;
1314 
1315     if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */
1316         err=UNZ_ERRNO;
1317     else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&
1318                               ((uFlags & 8)==0))
1319         err=UNZ_BADZIPFILE;
1320 
1321     if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */
1322         err=UNZ_ERRNO;
1323     else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&
1324                               ((uFlags & 8)==0))
1325         err=UNZ_BADZIPFILE;
1326 
1327     if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */
1328         err=UNZ_ERRNO;
1329     else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) &&
1330                               ((uFlags & 8)==0))
1331         err=UNZ_BADZIPFILE;
1332 
1333     if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK)
1334         err=UNZ_ERRNO;
1335     else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
1336         err=UNZ_BADZIPFILE;
1337 
1338     *piSizeVar += static_cast<uInt>(size_filename);
1339 
1340     if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK)
1341         err=UNZ_ERRNO;
1342     *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
1343                                     SIZEZIPLOCALHEADER + size_filename;
1344     *psize_local_extrafield = static_cast<uInt>(size_extra_field);
1345 
1346     *piSizeVar += static_cast<uInt>(size_extra_field);
1347 
1348     return err;
1349 }
1350 
1351 /*
1352   Open for reading data the current file in the zipfile.
1353   If there is no error and the file is opened, the return value is UNZ_OK.
1354 */
cpl_unzOpenCurrentFile3(unzFile file,int * method,int * level,int raw,const char * password)1355 extern int ZEXPORT cpl_unzOpenCurrentFile3 (unzFile file, int* method,
1356                                             int* level, int raw, const char* password)
1357 {
1358     int err=UNZ_OK;
1359     uInt iSizeVar;
1360     unz_s* s;
1361     file_in_zip_read_info_s* pfile_in_zip_read_info;
1362     uLong64 offset_local_extrafield;  /* offset of the local extra field */
1363     uInt  size_local_extrafield;    /* size of the local extra field */
1364 #    ifndef NOUNCRYPT
1365     char source[12];
1366 #    else
1367     if (password != nullptr)
1368         return UNZ_PARAMERROR;
1369 #    endif
1370 
1371     if (file==nullptr)
1372         return UNZ_PARAMERROR;
1373     s=reinterpret_cast<unz_s*>(file);
1374     if (!s->current_file_ok)
1375         return UNZ_PARAMERROR;
1376 
1377     if (s->pfile_in_zip_read != nullptr)
1378         cpl_unzCloseCurrentFile(file);
1379 
1380     if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,
1381                 &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
1382         return UNZ_BADZIPFILE;
1383 
1384     pfile_in_zip_read_info = static_cast<file_in_zip_read_info_s*>(
1385                                         ALLOC(sizeof(file_in_zip_read_info_s)));
1386     if (pfile_in_zip_read_info==nullptr)
1387         return UNZ_INTERNALERROR;
1388 
1389     pfile_in_zip_read_info->read_buffer =
1390         static_cast<char *>(ALLOC(UNZ_BUFSIZE));
1391     pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
1392     pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
1393     pfile_in_zip_read_info->pos_local_extrafield=0;
1394     pfile_in_zip_read_info->raw=raw;
1395 
1396     if (pfile_in_zip_read_info->read_buffer==nullptr)
1397     {
1398         TRYFREE(pfile_in_zip_read_info);
1399         return UNZ_INTERNALERROR;
1400     }
1401 
1402     pfile_in_zip_read_info->stream_initialised=0;
1403 
1404     if (method!=nullptr)
1405         *method = static_cast<int>(s->cur_file_info.compression_method);
1406 
1407     if (level!=nullptr)
1408     {
1409         *level = 6;
1410         switch (s->cur_file_info.flag & 0x06)
1411         {
1412           case 6 : *level = 1; break;
1413           case 4 : *level = 2; break;
1414           case 2 : *level = 9; break;
1415         }
1416     }
1417 
1418     /*if ((s->cur_file_info.compression_method!=0) &&
1419         (s->cur_file_info.compression_method!=Z_DEFLATED))
1420         err=UNZ_BADZIPFILE;*/
1421 
1422     pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
1423     pfile_in_zip_read_info->crc32=0;
1424     pfile_in_zip_read_info->compression_method =
1425             s->cur_file_info.compression_method;
1426     pfile_in_zip_read_info->filestream=s->filestream;
1427     pfile_in_zip_read_info->z_filefunc=s->z_filefunc;
1428     pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
1429 
1430     pfile_in_zip_read_info->stream.total_out = 0;
1431 
1432     if ((s->cur_file_info.compression_method==Z_DEFLATED) &&
1433         (!raw))
1434     {
1435       pfile_in_zip_read_info->stream.zalloc = nullptr;
1436       pfile_in_zip_read_info->stream.zfree = nullptr;
1437       pfile_in_zip_read_info->stream.opaque = nullptr;
1438       pfile_in_zip_read_info->stream.next_in = nullptr;
1439       pfile_in_zip_read_info->stream.avail_in = 0;
1440 
1441       err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
1442       if (err == Z_OK)
1443         pfile_in_zip_read_info->stream_initialised=1;
1444       else
1445       {
1446         TRYFREE(pfile_in_zip_read_info);
1447         return err;
1448       }
1449         /* windowBits is passed < 0 to tell that there is no zlib header.
1450          * Note that in this case inflate *requires* an extra "dummy" byte
1451          * after the compressed stream in order to complete decompression and
1452          * return Z_STREAM_END.
1453          * In unzip, i don't wait absolutely Z_STREAM_END because I known the
1454          * size of both compressed and uncompressed data
1455          */
1456     }
1457     pfile_in_zip_read_info->rest_read_compressed =
1458             s->cur_file_info.compressed_size;
1459     pfile_in_zip_read_info->rest_read_uncompressed =
1460             s->cur_file_info.uncompressed_size;
1461 
1462     pfile_in_zip_read_info->pos_in_zipfile =
1463             s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
1464               iSizeVar;
1465 
1466     pfile_in_zip_read_info->stream.avail_in = 0;
1467 
1468     s->pfile_in_zip_read = pfile_in_zip_read_info;
1469 
1470 #    ifndef NOUNCRYPT
1471     if (password != nullptr)
1472     {
1473         s->pcrc_32_tab = get_crc_table();
1474         init_keys(password,s->keys,s->pcrc_32_tab);
1475         if (ZSEEK(s->z_filefunc, s->filestream,
1476                   s->pfile_in_zip_read->pos_in_zipfile +
1477                      s->pfile_in_zip_read->byte_before_the_zipfile,
1478                   SEEK_SET)!=0)
1479             return UNZ_INTERNALERROR;
1480         if(ZREAD(s->z_filefunc, s->filestream,source, 12)<12)
1481             return UNZ_INTERNALERROR;
1482 
1483         for( int i = 0; i<12; i++ )
1484             zdecode(s->keys,s->pcrc_32_tab,source[i]);
1485 
1486         s->pfile_in_zip_read->pos_in_zipfile+=12;
1487         s->encrypted=1;
1488     }
1489 #    endif
1490 
1491     return UNZ_OK;
1492 }
1493 
cpl_unzOpenCurrentFile(unzFile file)1494 extern int ZEXPORT cpl_unzOpenCurrentFile (unzFile file)
1495 {
1496     return cpl_unzOpenCurrentFile3(file, nullptr, nullptr, 0, nullptr);
1497 }
1498 
cpl_unzOpenCurrentFilePassword(unzFile file,const char * password)1499 extern int ZEXPORT cpl_unzOpenCurrentFilePassword (unzFile file, const char*  password)
1500 {
1501     return cpl_unzOpenCurrentFile3(file, nullptr, nullptr, 0, password);
1502 }
1503 
cpl_unzOpenCurrentFile2(unzFile file,int * method,int * level,int raw)1504 extern int ZEXPORT cpl_unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw)
1505 {
1506     return cpl_unzOpenCurrentFile3(file, method, level, raw, nullptr);
1507 }
1508 
1509 /** Addition for GDAL : START */
1510 
cpl_unzGetCurrentFileZStreamPos(unzFile file)1511 extern uLong64 ZEXPORT cpl_unzGetCurrentFileZStreamPos( unzFile file)
1512 {
1513     unz_s* s;
1514     file_in_zip_read_info_s* pfile_in_zip_read_info;
1515     s=reinterpret_cast<unz_s*>(file);
1516     if (file==nullptr)
1517         return 0;  // UNZ_PARAMERROR;
1518     pfile_in_zip_read_info=s->pfile_in_zip_read;
1519     if (pfile_in_zip_read_info==nullptr)
1520         return 0;  // UNZ_PARAMERROR;
1521     return pfile_in_zip_read_info->pos_in_zipfile +
1522                          pfile_in_zip_read_info->byte_before_the_zipfile;
1523 }
1524 
1525 /** Addition for GDAL : END */
1526 
1527 /*
1528   Read bytes from the current file.
1529   buf contain buffer where data must be copied
1530   len the size of buf.
1531 
1532   return the number of byte copied if some bytes are copied
1533   return 0 if the end of file was reached
1534   return <0 with error code if there is an error
1535     (UNZ_ERRNO for IO error, or zLib error for uncompress error)
1536 */
cpl_unzReadCurrentFile(unzFile file,voidp buf,unsigned len)1537 extern int ZEXPORT cpl_unzReadCurrentFile  (unzFile file, voidp buf, unsigned len)
1538 {
1539     int err=UNZ_OK;
1540     uInt iRead = 0;
1541     unz_s* s;
1542     file_in_zip_read_info_s* pfile_in_zip_read_info;
1543     if (file==nullptr)
1544         return UNZ_PARAMERROR;
1545     s=reinterpret_cast<unz_s*>(file);
1546     pfile_in_zip_read_info=s->pfile_in_zip_read;
1547 
1548     if (pfile_in_zip_read_info==nullptr)
1549         return UNZ_PARAMERROR;
1550 
1551     if (pfile_in_zip_read_info->read_buffer == nullptr)
1552         return UNZ_END_OF_LIST_OF_FILE;
1553     if (len==0)
1554         return 0;
1555 
1556     pfile_in_zip_read_info->stream.next_out = reinterpret_cast<Bytef*>(buf);
1557 
1558     pfile_in_zip_read_info->stream.avail_out = static_cast<uInt>(len);
1559 
1560     if ((len>pfile_in_zip_read_info->rest_read_uncompressed) &&
1561         (!(pfile_in_zip_read_info->raw)))
1562         pfile_in_zip_read_info->stream.avail_out =
1563             static_cast<uInt>(pfile_in_zip_read_info->rest_read_uncompressed);
1564 
1565     if ((len>pfile_in_zip_read_info->rest_read_compressed+
1566            pfile_in_zip_read_info->stream.avail_in) &&
1567          (pfile_in_zip_read_info->raw))
1568         pfile_in_zip_read_info->stream.avail_out =
1569             static_cast<uInt>(pfile_in_zip_read_info->rest_read_compressed)+
1570             pfile_in_zip_read_info->stream.avail_in;
1571 
1572     while (pfile_in_zip_read_info->stream.avail_out>0)
1573     {
1574         if ((pfile_in_zip_read_info->stream.avail_in==0) &&
1575             (pfile_in_zip_read_info->rest_read_compressed>0))
1576         {
1577             uInt uReadThis = UNZ_BUFSIZE;
1578             if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
1579                 uReadThis = static_cast<uInt>(pfile_in_zip_read_info->rest_read_compressed);
1580             if (uReadThis == 0)
1581                 return UNZ_EOF;
1582             if (ZSEEK(pfile_in_zip_read_info->z_filefunc,
1583                       pfile_in_zip_read_info->filestream,
1584                       pfile_in_zip_read_info->pos_in_zipfile +
1585                          pfile_in_zip_read_info->byte_before_the_zipfile,
1586                          ZLIB_FILEFUNC_SEEK_SET)!=0)
1587                 return UNZ_ERRNO;
1588             if (ZREAD(pfile_in_zip_read_info->z_filefunc,
1589                       pfile_in_zip_read_info->filestream,
1590                       pfile_in_zip_read_info->read_buffer,
1591                       uReadThis)!=uReadThis)
1592                 return UNZ_ERRNO;
1593 
1594 #            ifndef NOUNCRYPT
1595             if(s->encrypted)
1596             {
1597                 uInt i;
1598                 for(i=0;i<uReadThis;i++)
1599                   pfile_in_zip_read_info->read_buffer[i] =
1600                       zdecode(s->keys,s->pcrc_32_tab,
1601                               pfile_in_zip_read_info->read_buffer[i]);
1602             }
1603 #            endif
1604 
1605             pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
1606 
1607             pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
1608 
1609             pfile_in_zip_read_info->stream.next_in =
1610                 reinterpret_cast<Bytef*>(pfile_in_zip_read_info->read_buffer);
1611             pfile_in_zip_read_info->stream.avail_in = static_cast<uInt>(uReadThis);
1612         }
1613 
1614         if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw))
1615         {
1616             uInt uDoCopy = 0;
1617             uInt i = 0;
1618 
1619             if ((pfile_in_zip_read_info->stream.avail_in == 0) &&
1620                 (pfile_in_zip_read_info->rest_read_compressed == 0))
1621                 return (iRead==0) ? UNZ_EOF : iRead;
1622 
1623             if (pfile_in_zip_read_info->stream.avail_out <
1624                             pfile_in_zip_read_info->stream.avail_in)
1625                 uDoCopy = pfile_in_zip_read_info->stream.avail_out;
1626             else
1627                 uDoCopy = pfile_in_zip_read_info->stream.avail_in;
1628 
1629             for (i=0;i<uDoCopy;i++)
1630                 *(pfile_in_zip_read_info->stream.next_out+i) =
1631                         *(pfile_in_zip_read_info->stream.next_in+i);
1632 
1633             pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
1634                                 pfile_in_zip_read_info->stream.next_out,
1635                                 uDoCopy);
1636             pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
1637             pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
1638             pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
1639             pfile_in_zip_read_info->stream.next_out += uDoCopy;
1640             pfile_in_zip_read_info->stream.next_in += uDoCopy;
1641             pfile_in_zip_read_info->stream.total_out += uDoCopy;
1642             iRead += uDoCopy;
1643         }
1644         else
1645         {
1646             uLong64 uTotalOutBefore,uTotalOutAfter;
1647             const Bytef *bufBefore;
1648             uLong64 uOutThis;
1649             int flush=Z_SYNC_FLUSH;
1650 
1651             uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
1652             bufBefore = pfile_in_zip_read_info->stream.next_out;
1653 
1654             /*
1655             if ((pfile_in_zip_read_info->rest_read_uncompressed ==
1656                      pfile_in_zip_read_info->stream.avail_out) &&
1657                 (pfile_in_zip_read_info->rest_read_compressed == 0))
1658                 flush = Z_FINISH;
1659             */
1660             err=inflate(&pfile_in_zip_read_info->stream,flush);
1661 
1662             if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=nullptr))
1663               err = Z_DATA_ERROR;
1664 
1665             uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
1666             uOutThis = uTotalOutAfter-uTotalOutBefore;
1667 
1668             pfile_in_zip_read_info->crc32 =
1669                 crc32(pfile_in_zip_read_info->crc32,bufBefore,
1670                         static_cast<uInt>(uOutThis));
1671 
1672             pfile_in_zip_read_info->rest_read_uncompressed -=
1673                 uOutThis;
1674 
1675             iRead += static_cast<uInt>(uTotalOutAfter - uTotalOutBefore);
1676 
1677             if (err==Z_STREAM_END)
1678                 return (iRead==0) ? UNZ_EOF : iRead;
1679             if (err!=Z_OK)
1680                 break;
1681         }
1682     }
1683 
1684     if (err==Z_OK)
1685         return iRead;
1686     return err;
1687 }
1688 
1689 /*
1690   Give the current position in uncompressed data
1691 */
cpl_unztell(unzFile file)1692 extern z_off_t ZEXPORT cpl_unztell (unzFile file)
1693 {
1694     unz_s* s;
1695     file_in_zip_read_info_s* pfile_in_zip_read_info;
1696     if (file==nullptr)
1697         return UNZ_PARAMERROR;
1698     s=reinterpret_cast<unz_s*>(file);
1699     pfile_in_zip_read_info=s->pfile_in_zip_read;
1700 
1701     if (pfile_in_zip_read_info==nullptr)
1702         return UNZ_PARAMERROR;
1703 
1704     return static_cast<z_off_t>(pfile_in_zip_read_info->stream.total_out);
1705 }
1706 
1707 /*
1708   return 1 if the end of file was reached, 0 elsewhere
1709 */
cpl_unzeof(unzFile file)1710 extern int ZEXPORT cpl_unzeof (unzFile file)
1711 {
1712     unz_s* s;
1713     file_in_zip_read_info_s* pfile_in_zip_read_info;
1714     if (file==nullptr)
1715         return UNZ_PARAMERROR;
1716     s=reinterpret_cast<unz_s*>(file);
1717     pfile_in_zip_read_info=s->pfile_in_zip_read;
1718 
1719     if (pfile_in_zip_read_info==nullptr)
1720         return UNZ_PARAMERROR;
1721 
1722     if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
1723         return 1;
1724     else
1725         return 0;
1726 }
1727 
1728 /*
1729   Read extra field from the current file (opened by unzOpenCurrentFile)
1730   This is the local-header version of the extra field (sometimes, there is
1731     more info in the local-header version than in the central-header)
1732 
1733   if buf==NULL, it return the size of the local extra field that can be read
1734 
1735   if buf!=NULL, len is the size of the buffer, the extra header is copied in
1736     buf.
1737   the return value is the number of bytes copied in buf, or (if <0)
1738     the error code
1739 */
cpl_unzGetLocalExtrafield(unzFile file,voidp buf,unsigned len)1740 extern int ZEXPORT cpl_unzGetLocalExtrafield ( unzFile file, voidp buf,
1741                                                unsigned len )
1742 {
1743     unz_s* s;
1744     file_in_zip_read_info_s* pfile_in_zip_read_info;
1745     uInt read_now;
1746     uLong64 size_to_read;
1747 
1748     if (file==nullptr)
1749         return UNZ_PARAMERROR;
1750     s=reinterpret_cast<unz_s*>(file);
1751     pfile_in_zip_read_info=s->pfile_in_zip_read;
1752 
1753     if (pfile_in_zip_read_info==nullptr)
1754         return UNZ_PARAMERROR;
1755 
1756     size_to_read = (pfile_in_zip_read_info->size_local_extrafield -
1757                 pfile_in_zip_read_info->pos_local_extrafield);
1758 
1759     if (buf==nullptr)
1760       return static_cast<int>(size_to_read);
1761 
1762     if (len>size_to_read)
1763         read_now = static_cast<uInt>(size_to_read);
1764     else
1765       read_now = static_cast<uInt>(len);
1766 
1767     if (read_now==0)
1768         return 0;
1769 
1770     if (ZSEEK(pfile_in_zip_read_info->z_filefunc,
1771               pfile_in_zip_read_info->filestream,
1772               pfile_in_zip_read_info->offset_local_extrafield +
1773               pfile_in_zip_read_info->pos_local_extrafield,
1774               ZLIB_FILEFUNC_SEEK_SET)!=0)
1775         return UNZ_ERRNO;
1776 
1777     if (ZREAD(pfile_in_zip_read_info->z_filefunc,
1778               pfile_in_zip_read_info->filestream,
1779               buf,read_now)!=read_now)
1780         return UNZ_ERRNO;
1781 
1782     return static_cast<int>(read_now);
1783 }
1784 
1785 /*
1786   Close the file in zip opened with unzipOpenCurrentFile
1787   Return UNZ_CRCERROR if all the file was read but the CRC is not good
1788 */
cpl_unzCloseCurrentFile(unzFile file)1789 extern int ZEXPORT cpl_unzCloseCurrentFile (unzFile file)
1790 {
1791     int err=UNZ_OK;
1792 
1793     unz_s* s;
1794     file_in_zip_read_info_s* pfile_in_zip_read_info;
1795     if (file==nullptr)
1796         return UNZ_PARAMERROR;
1797     s=reinterpret_cast<unz_s*>(file);
1798     pfile_in_zip_read_info=s->pfile_in_zip_read;
1799 
1800     if (pfile_in_zip_read_info==nullptr)
1801         return UNZ_PARAMERROR;
1802 
1803     if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
1804         (!pfile_in_zip_read_info->raw))
1805     {
1806         if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
1807             err=UNZ_CRCERROR;
1808     }
1809 
1810     TRYFREE(pfile_in_zip_read_info->read_buffer);
1811     pfile_in_zip_read_info->read_buffer = nullptr;
1812     if (pfile_in_zip_read_info->stream_initialised)
1813         inflateEnd(&pfile_in_zip_read_info->stream);
1814 
1815     pfile_in_zip_read_info->stream_initialised = 0;
1816     TRYFREE(pfile_in_zip_read_info);
1817 
1818     s->pfile_in_zip_read=nullptr;
1819 
1820     return err;
1821 }
1822 
1823 /*
1824   Get the global comment string of the ZipFile, in the szComment buffer.
1825   uSizeBuf is the size of the szComment buffer.
1826   return the number of byte copied or an error code <0
1827 */
cpl_unzGetGlobalComment(unzFile file,char * szComment,uLong uSizeBuf)1828 extern int ZEXPORT cpl_unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf)
1829 {
1830     /* int err=UNZ_OK; */
1831     unz_s* s;
1832     uLong uReadThis;
1833     if (file==nullptr)
1834         return UNZ_PARAMERROR;
1835     s=reinterpret_cast<unz_s*>(file);
1836 
1837     uReadThis = uSizeBuf;
1838     if (uReadThis>s->gi.size_comment)
1839         uReadThis = s->gi.size_comment;
1840 
1841     if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0)
1842         return UNZ_ERRNO;
1843 
1844     if (uReadThis>0)
1845     {
1846       *szComment='\0';
1847       if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis)
1848         return UNZ_ERRNO;
1849     }
1850 
1851     if ((szComment != nullptr) && (uSizeBuf > s->gi.size_comment))
1852         *(szComment+s->gi.size_comment)='\0';
1853     return static_cast<int>(uReadThis);
1854 }
1855 
1856 // Additions by RX '2004.
cpl_unzGetOffset(unzFile file)1857 extern uLong64 ZEXPORT cpl_unzGetOffset (unzFile file)
1858 {
1859     unz_s* s;
1860 
1861     if (file==nullptr)
1862           return 0;  // UNZ_PARAMERROR;
1863     s=reinterpret_cast<unz_s*>(file);
1864     if (!s->current_file_ok)
1865       return 0;
1866     if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff)
1867       if (s->num_file==s->gi.number_entry)
1868          return 0;
1869     return s->pos_in_central_dir;
1870 }
1871 
cpl_unzSetOffset(unzFile file,uLong64 pos)1872 extern int ZEXPORT cpl_unzSetOffset (unzFile file, uLong64 pos)
1873 {
1874     unz_s* s;
1875 
1876     if (file==nullptr)
1877         return UNZ_PARAMERROR;
1878     s=reinterpret_cast<unz_s*>(file);
1879 
1880     s->pos_in_central_dir = pos;
1881     s->num_file = s->gi.number_entry;      /* hack */
1882     int err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
1883                                                   &s->cur_file_info_internal,
1884                                                   nullptr,0,nullptr,0,nullptr,0);
1885     s->current_file_ok = (err == UNZ_OK);
1886     return err;
1887 }
1888