1 /******************************************************************************
2  *
3  * Project:  CPL - Common Portability Library
4  * Author:   Frank Warmerdam, warmerdam@pobox.com
5  * Purpose:  Adjusted minizip "zip.c" source code for zip services.
6  *
7  * Modified version by Even Rouault. :
8  *   - Decoration of symbol names unz* -> cpl_unz*
9  *   - Undef EXPORT so that we are sure the symbols are not exported
10  *   - Remove old C style function prototypes
11  *   - Added CPL* simplified API at bottom.
12  *
13  *   Original license available in port/LICENCE_minizip
14  *
15  *****************************************************************************/
16 
17 /* zip.c -- IO on .zip files using zlib
18    Version 1.1, February 14h, 2010
19    part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
20 
21          Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
22 
23          Modifications for Zip64 support
24          Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
25 
26          For more info read MiniZip_info.txt
27 
28          Changes
29    Oct-2009 - Mathias Svensson - Remove old C style function prototypes
30    Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives
31    Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions.
32    Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data
33                                  It is used when recreting zip archive with RAW when deleting items from a zip.
34                                  ZIP64 data is automatically added to items that needs it, and existing ZIP64 data need to be removed.
35    Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required)
36    Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer
37 
38    Copyright (c) 2010-2018, Even Rouault <even dot rouault at spatialys.com>
39 
40 */
41 
42 #include "cpl_port.h"
43 #include "cpl_minizip_zip.h"
44 
45 #include <cassert>
46 #include <cstddef>
47 #include <cstdlib>
48 #include <cstring>
49 #if HAVE_FCNTL_H
50 #include <fcntl.h>
51 #endif
52 
53 #include "cpl_conv.h"
54 #include "cpl_error.h"
55 #include "cpl_minizip_unzip.h"
56 #include "cpl_string.h"
57 #include "cpl_vsi_virtual.h"
58 
59 #ifdef NO_ERRNO_H
60     extern int errno;
61 #else
62 #   include <errno.h>
63 #endif
64 
65 CPL_CVSID("$Id: cpl_minizip_zip.cpp a530d0e8e49140f2dcc38504b31bc3e658107728 2021-03-11 12:00:21 +0100 Even Rouault $")
66 
67 #ifndef VERSIONMADEBY
68 # define VERSIONMADEBY   (0x0) /* platform dependent */
69 #endif
70 
71 #ifndef Z_BUFSIZE
72 #define Z_BUFSIZE (16384)
73 #endif
74 
75 #ifndef ALLOC
76 # define ALLOC(size) (malloc(size))
77 #endif
78 #ifndef TRYFREE
79 # define TRYFREE(p) {if (p) free(p);}
80 #endif
81 
82 /*
83 #define SIZECENTRALDIRITEM (0x2e)
84 #define SIZEZIPLOCALHEADER (0x1e)
85 */
86 
87 /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined... */
88 
89 #ifndef SEEK_CUR
90 #define SEEK_CUR    1
91 #endif
92 
93 #ifndef SEEK_END
94 #define SEEK_END    2
95 #endif
96 
97 #ifndef SEEK_SET
98 #define SEEK_SET    0
99 #endif
100 
101 #ifndef DEF_MEM_LEVEL
102 #if MAX_MEM_LEVEL >= 8
103 #  define DEF_MEM_LEVEL 8
104 #else
105 #  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
106 #endif
107 #endif
108 
109 CPL_UNUSED static const char zip_copyright[] =
110     " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
111 
112 #define SIZEDATA_INDATABLOCK (4096-(4*4))
113 
114 #define LOCALHEADERMAGIC    (0x04034b50)
115 #define CENTRALHEADERMAGIC  (0x02014b50)
116 #define ENDHEADERMAGIC      (0x06054b50)
117 #define ZIP64ENDHEADERMAGIC      (0x6064b50)
118 #define ZIP64ENDLOCHEADERMAGIC   (0x7064b50)
119 
120 #define FLAG_LOCALHEADER_OFFSET (0x06)
121 #define CRC_LOCALHEADER_OFFSET  (0x0e)
122 
123 #define SIZECENTRALHEADER (0x2e) /* 46 */
124 
125 typedef struct linkedlist_datablock_internal_s
126 {
127   struct linkedlist_datablock_internal_s* next_datablock;
128   uLong  avail_in_this_block;
129   uLong  filled_in_this_block;
130   uLong  unused;  // For future use and alignment.
131   unsigned char data[SIZEDATA_INDATABLOCK];
132 } linkedlist_datablock_internal;
133 
134 typedef struct linkedlist_data_s
135 {
136     linkedlist_datablock_internal* first_block;
137     linkedlist_datablock_internal* last_block;
138 } linkedlist_data;
139 
140 typedef struct
141 {
142     z_stream stream;            /* zLib stream structure for inflate */
143     int  stream_initialised;    /* 1 is stream is initialized */
144     uInt pos_in_buffered_data;  /* last written byte in buffered_data */
145 
146     ZPOS64_T pos_local_header;     /* offset of the local header of the file
147                                      currently writing */
148     char* local_header;
149     uInt size_local_header;
150     uInt size_local_header_extrafield;
151 
152     char* central_header;       /* central header data for the current file */
153     uLong size_centralExtra;
154     uLong size_centralheader;   /* size of the central header for cur file */
155     uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */
156     uLong flag;                 /* flag of the file currently writing */
157 
158     // TODO: What is "wr"?  "to"?
159     int  method;                /* compression method of file currently wr.*/
160     int  raw;                   /* 1 for directly writing raw data */
161     Byte buffered_data[Z_BUFSIZE]; /* buffer contain compressed data to be
162                                         written. */
163     uLong dosDate;
164     uLong crc32;
165     int  encrypt;
166     ZPOS64_T pos_zip64extrainfo;
167     ZPOS64_T totalCompressedData;
168     ZPOS64_T totalUncompressedData;
169 #ifndef NOCRYPT
170     unsigned long keys[3];     /* keys defining the pseudo-random sequence */
171     const unsigned long* pcrc_32_tab;
172     int crypt_header_size;
173 #endif
174 } curfile64_info;
175 
176 typedef struct
177 {
178     zlib_filefunc_def z_filefunc;
179     voidpf filestream;        /* IO structure of the zipfile */
180     linkedlist_data central_dir;/* datablock with central dir in construction*/
181     int  in_opened_file_inzip;  /* 1 if a file in the zip is currently writ.*/
182     curfile64_info ci;            /* info on the file currently writing */
183 
184     ZPOS64_T begin_pos;            /* position of the beginning of the zipfile */
185     ZPOS64_T add_position_when_writing_offset;
186     ZPOS64_T number_entry;
187 #ifndef NO_ADDFILEINEXISTINGZIP
188     char *globalcomment;
189 #endif
190     int use_cpl_io;
191     vsi_l_offset vsi_raw_length_before;
192     VSIVirtualHandle* vsi_deflate_handle;
193 } zip64_internal;
194 
195 #ifndef NOCRYPT
196 #define INCLUDECRYPTINGCODE_IFCRYPTALLOWED
197 #include "crypt.h"
198 #endif
199 
allocate_new_datablock()200 static linkedlist_datablock_internal* allocate_new_datablock()
201 {
202     linkedlist_datablock_internal* ldi;
203     ldi = static_cast<linkedlist_datablock_internal*>(
204                  ALLOC(sizeof(linkedlist_datablock_internal)));
205     if (ldi!=nullptr)
206     {
207         ldi->next_datablock = nullptr;
208         ldi->filled_in_this_block = 0;
209         ldi->avail_in_this_block = SIZEDATA_INDATABLOCK;
210     }
211     return ldi;
212 }
213 
free_datablock(linkedlist_datablock_internal * ldi)214 static void free_datablock(linkedlist_datablock_internal*ldi)
215 {
216     while (ldi!=nullptr)
217     {
218         linkedlist_datablock_internal* ldinext = ldi->next_datablock;
219         TRYFREE(ldi);
220         ldi = ldinext;
221     }
222 }
223 
init_linkedlist(linkedlist_data * ll)224 static void init_linkedlist(linkedlist_data*ll)
225 {
226     ll->first_block = ll->last_block = nullptr;
227 }
228 
free_linkedlist(linkedlist_data * ll)229 static void free_linkedlist(linkedlist_data* ll)
230 {
231     free_datablock(ll->first_block);
232     ll->first_block = ll->last_block = nullptr;
233 }
234 
add_data_in_datablock(linkedlist_data * ll,const void * buf,uLong len)235 static int add_data_in_datablock(linkedlist_data*ll,
236                                 const void *buf, uLong len)
237 {
238     linkedlist_datablock_internal* ldi;
239     const unsigned char* from_copy;
240 
241     if (ll==nullptr)
242         return ZIP_INTERNALERROR;
243 
244     if (ll->last_block == nullptr)
245     {
246         ll->first_block = ll->last_block = allocate_new_datablock();
247         if (ll->first_block == nullptr)
248             return ZIP_INTERNALERROR;
249     }
250 
251     ldi = ll->last_block;
252     from_copy = reinterpret_cast<const unsigned char*>(buf);
253 
254     while (len>0)
255     {
256         uInt copy_this;
257         uInt i;
258         unsigned char* to_copy;
259 
260         if (ldi->avail_in_this_block==0)
261         {
262             ldi->next_datablock = allocate_new_datablock();
263             if (ldi->next_datablock == nullptr)
264                 return ZIP_INTERNALERROR;
265             ldi = ldi->next_datablock;
266             ll->last_block = ldi;
267         }
268 
269         if (ldi->avail_in_this_block < len)
270             copy_this = static_cast<uInt>(ldi->avail_in_this_block);
271         else
272             copy_this = static_cast<uInt>(len);
273 
274         to_copy = &(ldi->data[ldi->filled_in_this_block]);
275 
276         for (i=0;i<copy_this;i++)
277             *(to_copy+i)=*(from_copy+i);
278 
279         ldi->filled_in_this_block += copy_this;
280         ldi->avail_in_this_block -= copy_this;
281         from_copy += copy_this;
282         len -= copy_this;
283     }
284     return ZIP_OK;
285 }
286 
287 /****************************************************************************/
288 
289 #ifndef NO_ADDFILEINEXISTINGZIP
290 /* ===========================================================================
291    Inputs a long in LSB order to the given file
292    nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T)
293 */
294 
zip64local_putValue(const zlib_filefunc_def * pzlib_filefunc_def,voidpf filestream,ZPOS64_T x,int nbByte)295 static int zip64local_putValue (const zlib_filefunc_def*pzlib_filefunc_def,
296                               voidpf filestream, ZPOS64_T x, int nbByte)
297 {
298     unsigned char buf[8];
299     for (int n = 0; n < nbByte; n++)
300     {
301         buf[n] = static_cast<unsigned char>(x & 0xff);
302         x >>= 8;
303     }
304     if (x != 0)
305       {     /* data overflow - hack for ZIP64 (X Roche) */
306       for (int n = 0; n < nbByte; n++)
307         {
308           buf[n] = 0xff;
309         }
310       }
311 
312     if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=static_cast<uLong>(nbByte))
313         return ZIP_ERRNO;
314     else
315         return ZIP_OK;
316 }
317 
zip64local_putValue_inmemory(void * dest,ZPOS64_T x,int nbByte)318 static void zip64local_putValue_inmemory (void *dest, ZPOS64_T x, int nbByte)
319 {
320     unsigned char* buf= reinterpret_cast<unsigned char*>(dest);
321     for (int n = 0; n < nbByte; n++) {
322         buf[n] = static_cast<unsigned char>(x & 0xff);
323         x >>= 8;
324     }
325 
326     if (x != 0)
327     {     /* data overflow - hack for ZIP64 */
328        for (int n = 0; n < nbByte; n++)
329        {
330           buf[n] = 0xff;
331        }
332     }
333 }
334 
335 /****************************************************************************/
336 
zip64local_TmzDateToDosDate(const tm_zip * ptm)337 static uLong zip64local_TmzDateToDosDate(const tm_zip *ptm)
338 {
339     uLong year = static_cast<uLong>(ptm->tm_year);
340     if (year>1980)
341         year-=1980;
342     else if (year>80)
343         year-=80;
344     return
345       static_cast<uLong>(((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) |
346         ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * static_cast<uLong>(ptm->tm_hour)));
347 }
348 
349 /****************************************************************************/
350 
zip64local_getByte(const zlib_filefunc_def * pzlib_filefunc_def,voidpf filestream,int * pi)351 static int zip64local_getByte( const zlib_filefunc_def* pzlib_filefunc_def,
352                              voidpf filestream, int *pi )
353 {
354     unsigned char c = 0;
355     const int err =
356         static_cast<int>(ZREAD64(*pzlib_filefunc_def, filestream, &c, 1));
357     if (err==1)
358     {
359         *pi = static_cast<int>(c);
360         return ZIP_OK;
361     }
362     else
363     {
364         if (ZERROR64(*pzlib_filefunc_def,filestream))
365             return ZIP_ERRNO;
366         else
367             return ZIP_EOF;
368     }
369 }
370 
371 /* ===========================================================================
372    Reads a long in LSB order from the given gz_stream. Sets
373 */
zip64local_getShort(const zlib_filefunc_def * pzlib_filefunc_def,voidpf filestream,uLong * pX)374 static int zip64local_getShort (const zlib_filefunc_def* pzlib_filefunc_def,
375                               voidpf filestream, uLong *pX)
376 {
377     int i = 0;
378     int err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
379     uLong x = static_cast<uLong>(i);
380 
381     if (err==ZIP_OK)
382         err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
383     x += static_cast<uLong>(i)<<8;
384 
385     if (err==ZIP_OK)
386         *pX = x;
387     else
388         *pX = 0;
389     return err;
390 }
391 
zip64local_getLong(const zlib_filefunc_def * pzlib_filefunc_def,voidpf filestream,uLong * pX)392 static int zip64local_getLong (
393     const zlib_filefunc_def* pzlib_filefunc_def,
394     voidpf filestream,
395     uLong *pX )
396 {
397     int i = 0;
398     int err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
399     uLong x = static_cast<uLong>(i);
400 
401     if (err==ZIP_OK)
402         err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
403     x += static_cast<uLong>(i)<<8;
404 
405     if (err==ZIP_OK)
406         err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
407     x += static_cast<uLong>(i)<<16;
408 
409     if (err==ZIP_OK)
410         err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
411     x += static_cast<uLong>(i)<<24;
412 
413     if (err==ZIP_OK)
414         *pX = x;
415     else
416         *pX = 0;
417     return err;
418 }
419 
420 
zip64local_getLong64(const zlib_filefunc_def * pzlib_filefunc_def,voidpf filestream,ZPOS64_T * pX)421 static int zip64local_getLong64 (const zlib_filefunc_def* pzlib_filefunc_def,
422                                  voidpf filestream, ZPOS64_T *pX)
423 {
424   ZPOS64_T x;
425   int i = 0;
426   int err;
427 
428   err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
429   x = static_cast<ZPOS64_T>(i);
430 
431   if (err==ZIP_OK)
432     err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
433   x += static_cast<ZPOS64_T>(i)<<8;
434 
435   if (err==ZIP_OK)
436     err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
437   x += static_cast<ZPOS64_T>(i)<<16;
438 
439   if (err==ZIP_OK)
440     err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
441   x += static_cast<ZPOS64_T>(i)<<24;
442 
443   if (err==ZIP_OK)
444     err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
445   x += static_cast<ZPOS64_T>(i)<<32;
446 
447   if (err==ZIP_OK)
448     err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
449   x += static_cast<ZPOS64_T>(i)<<40;
450 
451   if (err==ZIP_OK)
452     err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
453   x += static_cast<ZPOS64_T>(i)<<48;
454 
455   if (err==ZIP_OK)
456     err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
457   x += static_cast<ZPOS64_T>(i)<<56;
458 
459   if (err==ZIP_OK)
460     *pX = x;
461   else
462     *pX = 0;
463 
464   return err;
465 }
466 
467 #ifndef BUFREADCOMMENT
468 #define BUFREADCOMMENT (0x400)
469 #endif
470 /*
471   Locate the Central directory of a zipfile (at the end, just before
472     the global comment)
473 */
zip64local_SearchCentralDir(const zlib_filefunc_def * pzlib_filefunc_def,voidpf filestream)474 static ZPOS64_T zip64local_SearchCentralDir(
475     const zlib_filefunc_def* pzlib_filefunc_def,
476     voidpf filestream )
477 {
478   ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
479   ZPOS64_T uPosFound=0;
480 
481   if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
482     return 0;
483 
484   ZPOS64_T uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
485 
486   if (uMaxBack>uSizeFile)
487     uMaxBack = uSizeFile;
488 
489   unsigned char* buf = static_cast<unsigned char*>(ALLOC(BUFREADCOMMENT+4));
490   if (buf==nullptr)
491     return 0;
492 
493   ZPOS64_T uBackRead = 4;
494   while (uBackRead<uMaxBack)
495   {
496     if (uBackRead+BUFREADCOMMENT>uMaxBack)
497       uBackRead = uMaxBack;
498     else
499       uBackRead+=BUFREADCOMMENT;
500     ZPOS64_T uReadPos = uSizeFile-uBackRead;
501 
502     uLong uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
503                      (BUFREADCOMMENT+4) : static_cast<uLong>(uSizeFile-uReadPos);
504     if(ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET) != 0)
505       break;
506 
507     if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
508       break;
509 
510     for( int i = static_cast<int>(uReadSize) - 3; (i--) > 0;)
511       if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
512          ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
513       {
514         uPosFound = uReadPos+i;
515         break;
516     }
517 
518     if (uPosFound!=0)
519       break;
520   }
521   TRYFREE(buf);
522   return uPosFound;
523 }
524 
525 /*
526 Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before
527 the global comment)
528 */
zip64local_SearchCentralDir64(const zlib_filefunc_def * pzlib_filefunc_def,voidpf filestream)529 static ZPOS64_T zip64local_SearchCentralDir64(
530     const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream)
531 {
532   unsigned char* buf;
533   ZPOS64_T uSizeFile;
534   ZPOS64_T uBackRead;
535   ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
536   ZPOS64_T uPosFound=0;
537   uLong uL;
538   ZPOS64_T relativeOffset;
539 
540   if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
541     return 0;
542 
543   uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
544 
545   if (uMaxBack>uSizeFile)
546     uMaxBack = uSizeFile;
547 
548   buf = static_cast<unsigned char*>(ALLOC(BUFREADCOMMENT+4));
549   if (buf==nullptr)
550     return 0;
551 
552   uBackRead = 4;
553   while (uBackRead<uMaxBack)
554   {
555     uLong uReadSize;
556     ZPOS64_T uReadPos;
557     int i;
558     if (uBackRead+BUFREADCOMMENT>uMaxBack)
559       uBackRead = uMaxBack;
560     else
561       uBackRead+=BUFREADCOMMENT;
562     uReadPos = uSizeFile-uBackRead ;
563 
564     uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
565       (BUFREADCOMMENT+4) : static_cast<uLong>(uSizeFile-uReadPos);
566     if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
567       break;
568 
569     if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
570       break;
571 
572     for (i=static_cast<int>(uReadSize)-3; (i--)>0;)
573     {
574       // Signature "0x07064b50" Zip64 end of central directory locater
575       if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))
576       {
577         uPosFound = uReadPos+i;
578         break;
579       }
580     }
581 
582       if (uPosFound!=0)
583         break;
584   }
585 
586   TRYFREE(buf);
587   if (uPosFound == 0)
588     return 0;
589 
590   /* Zip64 end of central directory locator */
591   if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
592     return 0;
593 
594   /* the signature, already checked */
595   if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
596     return 0;
597 
598   /* number of the disk with the start of the zip64 end of  central directory */
599   if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
600     return 0;
601   if (uL != 0)
602     return 0;
603 
604   /* relative offset of the zip64 end of central directory record */
605   if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK)
606     return 0;
607 
608   /* total number of disks */
609   if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
610     return 0;
611   /* Some .zip declare 0 disks, such as in http://trac.osgeo.org/gdal/ticket/5615 */
612   if (uL != 0 && uL != 1)
613     return 0;
614 
615   /* Goto Zip64 end of central directory record */
616   if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)
617     return 0;
618 
619   /* the signature */
620   if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
621     return 0;
622 
623   if (uL != 0x06064b50) // signature of 'Zip64 end of central directory'
624     return 0;
625 
626   return relativeOffset;
627 }
628 
LoadCentralDirectoryRecord(zip64_internal * pziinit)629 static int LoadCentralDirectoryRecord(zip64_internal* pziinit)
630 {
631   int err=ZIP_OK;
632   ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
633 
634   ZPOS64_T size_central_dir;     /* size of the central directory  */
635   ZPOS64_T offset_central_dir;   /* offset of start of central directory */
636   ZPOS64_T central_pos;
637   uLong uL;
638 
639   uLong number_disk;          /* number of the current dist, used for
640                               spanning ZIP, unsupported, always 0*/
641   uLong number_disk_with_CD;  /* number the the disk with central dir, used
642                               for spanning ZIP, unsupported, always 0*/
643   ZPOS64_T number_entry;
644   ZPOS64_T number_entry_CD;      /* total number of entries in
645                                 the central dir
646                                 (same than number_entry on nospan) */
647   uLong VersionMadeBy;
648   uLong VersionNeeded;
649   uLong size_comment;
650 
651   int hasZIP64Record = 0;
652 
653   // check first if we find a ZIP64 record
654   central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream);
655   if(central_pos > 0)
656   {
657     hasZIP64Record = 1;
658   }
659   else if(central_pos == 0)
660   {
661     central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream);
662   }
663 
664 /* disable to allow appending to empty ZIP archive
665         if (central_pos==0)
666             err=ZIP_ERRNO;
667 */
668 
669   if(hasZIP64Record)
670   {
671     ZPOS64_T sizeEndOfCentralDirectory;
672     if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
673       err=ZIP_ERRNO;
674 
675     /* the signature, already checked */
676     if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK)
677       err=ZIP_ERRNO;
678 
679     /* size of zip64 end of central directory record */
680     if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK)
681       err=ZIP_ERRNO;
682 
683     /* version made by */
684     if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK)
685       err=ZIP_ERRNO;
686 
687     /* version needed to extract */
688     if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK)
689       err=ZIP_ERRNO;
690 
691     /* number of this disk */
692     if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK)
693       err=ZIP_ERRNO;
694 
695     /* number of the disk with the start of the central directory */
696     if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK)
697       err=ZIP_ERRNO;
698 
699     /* total number of entries in the central directory on this disk */
700     if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK)
701       err=ZIP_ERRNO;
702 
703     /* total number of entries in the central directory */
704     if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK)
705       err=ZIP_ERRNO;
706 
707     if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0))
708       err=ZIP_BADZIPFILE;
709 
710     /* size of the central directory */
711     if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK)
712       err=ZIP_ERRNO;
713 
714     /* offset of start of central directory with respect to the
715     starting disk number */
716     if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK)
717       err=ZIP_ERRNO;
718 
719     // TODO..
720     // read the comment from the standard central header.
721     size_comment = 0;
722   }
723   else
724   {
725     // Read End of central Directory info
726     if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
727       err=ZIP_ERRNO;
728 
729     /* the signature, already checked */
730     if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK)
731       err=ZIP_ERRNO;
732 
733     /* number of this disk */
734     if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK)
735       err=ZIP_ERRNO;
736 
737     /* number of the disk with the start of the central directory */
738     if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK)
739       err=ZIP_ERRNO;
740 
741     /* total number of entries in the central dir on this disk */
742     number_entry = 0;
743     if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
744       err=ZIP_ERRNO;
745     else
746       number_entry = uL;
747 
748     /* total number of entries in the central dir */
749     number_entry_CD = 0;
750     if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
751       err=ZIP_ERRNO;
752     else
753       number_entry_CD = uL;
754 
755     if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0))
756       err=ZIP_BADZIPFILE;
757 
758     /* size of the central directory */
759     size_central_dir = 0;
760     if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
761       err=ZIP_ERRNO;
762     else
763       size_central_dir = uL;
764 
765     /* offset of start of central directory with respect to the starting disk number */
766     offset_central_dir = 0;
767     if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
768       err=ZIP_ERRNO;
769     else
770       offset_central_dir = uL;
771 
772 
773     /* zipfile global comment length */
774     if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK)
775       err=ZIP_ERRNO;
776   }
777 
778   if ((central_pos<offset_central_dir+size_central_dir) &&
779     (err==ZIP_OK))
780     err=ZIP_BADZIPFILE;
781 
782   if (err!=ZIP_OK)
783   {
784     ZCLOSE64(pziinit->z_filefunc, pziinit->filestream);
785     return ZIP_ERRNO;
786   }
787 
788   if (size_comment>0)
789   {
790     pziinit->globalcomment = static_cast<char*>(ALLOC(size_comment+1));
791     if (pziinit->globalcomment)
792     {
793       size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment);
794       pziinit->globalcomment[size_comment]=0;
795     }
796   }
797 
798   byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir);
799   pziinit->add_position_when_writing_offset = byte_before_the_zipfile;
800 
801   {
802     ZPOS64_T size_central_dir_to_read = size_central_dir;
803     size_t buf_size = SIZEDATA_INDATABLOCK;
804     void* buf_read = ALLOC(buf_size);
805     if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
806       err=ZIP_ERRNO;
807 
808     while ((size_central_dir_to_read>0) && (err==ZIP_OK))
809     {
810       ZPOS64_T read_this = SIZEDATA_INDATABLOCK;
811       if (read_this > size_central_dir_to_read)
812         read_this = size_central_dir_to_read;
813 
814       if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,static_cast<uLong>(read_this)) != read_this)
815         err=ZIP_ERRNO;
816 
817       if (err==ZIP_OK)
818         err = add_data_in_datablock(&pziinit->central_dir,buf_read, static_cast<uLong>(read_this));
819 
820       size_central_dir_to_read-=read_this;
821     }
822     TRYFREE(buf_read);
823   }
824   pziinit->begin_pos = byte_before_the_zipfile;
825   pziinit->number_entry = number_entry_CD;
826 
827   if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0)
828     err=ZIP_ERRNO;
829 
830   return err;
831 }
832 
833 #endif /* !NO_ADDFILEINEXISTINGZIP*/
834 
835 /************************************************************/
cpl_zipOpen2(const char * pathname,int append,zipcharpc * globalcomment,zlib_filefunc_def * pzlib_filefunc_def)836 extern zipFile ZEXPORT cpl_zipOpen2 (
837     const char *pathname,
838     int append,
839     zipcharpc* globalcomment,
840     zlib_filefunc_def* pzlib_filefunc_def )
841 {
842     zip64_internal ziinit;
843     memset(&ziinit, 0, sizeof(ziinit));
844 
845     if (pzlib_filefunc_def==nullptr)
846         cpl_fill_fopen_filefunc(&ziinit.z_filefunc);
847     else
848         ziinit.z_filefunc = *pzlib_filefunc_def;
849 
850     ziinit.filestream = (*(ziinit.z_filefunc.zopen_file))
851                  (ziinit.z_filefunc.opaque,
852                   pathname,
853                   (append == APPEND_STATUS_CREATE) ?
854                   (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) :
855                     (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING));
856 
857     if (ziinit.filestream == nullptr)
858         return nullptr;
859 
860     if (append == APPEND_STATUS_CREATEAFTER)
861         ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END);
862 
863     ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream);
864     ziinit.in_opened_file_inzip = 0;
865     ziinit.ci.stream_initialised = 0;
866     ziinit.number_entry = 0;
867     ziinit.add_position_when_writing_offset = 0;
868     ziinit.use_cpl_io = (pzlib_filefunc_def == nullptr) ? 1 : 0;
869     ziinit.vsi_raw_length_before = 0;
870     ziinit.vsi_deflate_handle = nullptr;
871     init_linkedlist(&(ziinit.central_dir));
872 
873     zip64_internal* zi = static_cast<zip64_internal*>(ALLOC(sizeof(zip64_internal)));
874     if (zi==nullptr)
875     {
876         ZCLOSE64(ziinit.z_filefunc,ziinit.filestream);
877         return nullptr;
878     }
879 
880     /* now we add file in a zipfile */
881 #    ifndef NO_ADDFILEINEXISTINGZIP
882     ziinit.globalcomment = nullptr;
883 
884     int err=ZIP_OK;
885     if (append == APPEND_STATUS_ADDINZIP)
886     {
887         // Read and Cache Central Directory Records
888       err = LoadCentralDirectoryRecord(&ziinit);
889     }
890 
891     if (globalcomment)
892     {
893       *globalcomment = ziinit.globalcomment;
894     }
895 #    endif /* !NO_ADDFILEINEXISTINGZIP*/
896 
897     if (err != ZIP_OK)
898     {
899 #    ifndef NO_ADDFILEINEXISTINGZIP
900         TRYFREE(ziinit.globalcomment);
901 #    endif /* !NO_ADDFILEINEXISTINGZIP*/
902         TRYFREE(zi);
903         return nullptr;
904     }
905     else
906     {
907         *zi = ziinit;
908         return static_cast<zipFile>(zi);
909     }
910 }
911 
cpl_zipOpen(const char * pathname,int append)912 extern zipFile ZEXPORT cpl_zipOpen (const char *pathname, int append)
913 {
914     return cpl_zipOpen2(pathname,append,nullptr,nullptr);
915 }
916 
917 
zip64local_putValue_inmemory_update(char ** dest,ZPOS64_T x,int nbByte)918 static void zip64local_putValue_inmemory_update(char **dest, ZPOS64_T x, int nbByte)
919 {
920     zip64local_putValue_inmemory(*dest, x, nbByte);
921     *dest += nbByte;
922 }
923 
Write_LocalFileHeader(zip64_internal * zi,const char * filename,uInt size_extrafield_local,const void * extrafield_local,int zip64)924 static int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local, int zip64)
925 {
926   /* write the local header */
927   int err = ZIP_OK;
928   uInt size_filename = static_cast<uInt>(strlen(filename));
929   uInt size_extrafield = size_extrafield_local;
930 
931   if(zip64)
932   {
933     size_extrafield += 20;
934   }
935 
936   uInt size_local_header = 30 + size_filename + size_extrafield;
937   char* local_header = static_cast<char*>(ALLOC(size_local_header));
938   char* p = local_header;
939 
940   zip64local_putValue_inmemory_update(&p,LOCALHEADERMAGIC, 4);
941   if(zip64)
942       zip64local_putValue_inmemory_update(&p,45,2);/* version needed to extract */
943   else
944       zip64local_putValue_inmemory_update(&p,20,2);/* version needed to extract */
945 
946   zip64local_putValue_inmemory_update(&p,zi->ci.flag,2);
947 
948   zip64local_putValue_inmemory_update(&p,zi->ci.method,2);
949 
950   zip64local_putValue_inmemory_update(&p,zi->ci.dosDate,4);
951 
952   // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later
953   zip64local_putValue_inmemory_update(&p,0,4); /* crc 32, unknown */
954 
955   if(zip64)
956       zip64local_putValue_inmemory_update(&p,0xFFFFFFFFU,4); /* compressed size, unknown */
957   else
958       zip64local_putValue_inmemory_update(&p,0,4); /* compressed size, unknown */
959 
960   if(zip64)
961       zip64local_putValue_inmemory_update(&p,0xFFFFFFFFU,4); /* uncompressed size, unknown */
962   else
963       zip64local_putValue_inmemory_update(&p,0,4); /* uncompressed size, unknown */
964 
965   zip64local_putValue_inmemory_update(&p,size_filename,2);
966 
967   zi->ci.size_local_header_extrafield = size_extrafield;
968 
969   zip64local_putValue_inmemory_update(&p,size_extrafield,2);
970 
971   if (size_filename > 0)
972   {
973     memcpy(p, filename,size_filename);
974     p += size_filename;
975   }
976 
977   if (size_extrafield_local > 0)
978   {
979     memcpy(p, extrafield_local,size_extrafield_local);
980     p += size_extrafield_local;
981   }
982 
983   if (zip64)
984   {
985       // write the Zip64 extended info
986       short HeaderID = 1;
987       short DataSize = 16;
988       ZPOS64_T CompressedSize = 0;
989       ZPOS64_T UncompressedSize = 0;
990 
991       // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file)
992       zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream) + p - local_header;
993 
994       zip64local_putValue_inmemory_update(&p,HeaderID,2);
995       zip64local_putValue_inmemory_update(&p,DataSize,2);
996 
997       zip64local_putValue_inmemory_update(&p,UncompressedSize,8);
998       zip64local_putValue_inmemory_update(&p,CompressedSize,8);
999   }
1000   assert(p == local_header + size_local_header);
1001 
1002   if( ZWRITE64(zi->z_filefunc, zi->filestream,
1003                local_header, size_local_header) != size_local_header)
1004       err = ZIP_ERRNO;
1005 
1006   zi->ci.local_header = local_header;
1007   zi->ci.size_local_header = size_local_header;
1008 
1009   return err;
1010 }
1011 
cpl_zipOpenNewFileInZip3(zipFile file,const char * filename,const zip_fileinfo * zipfi,const void * extrafield_local,uInt size_extrafield_local,const void * extrafield_global,uInt size_extrafield_global,const char * comment,int method,int level,int raw,int windowBits,int memLevel,int strategy,const char * password,uLong)1012 extern int ZEXPORT cpl_zipOpenNewFileInZip3 (
1013     zipFile file,
1014     const char* filename,
1015     const zip_fileinfo* zipfi,
1016     const void* extrafield_local,
1017     uInt size_extrafield_local,
1018     const void* extrafield_global,
1019     uInt size_extrafield_global,
1020     const char* comment,
1021     int method,
1022     int level,
1023     int raw,
1024     int windowBits,
1025     int memLevel,
1026     int strategy,
1027     const char* password,
1028 #ifdef NOCRYPT
1029     uLong /* crcForCrypting */
1030 #else
1031     uLong crcForCrypting
1032 #endif
1033  )
1034 {
1035     zip64_internal* zi;
1036     uInt size_filename;
1037     uInt size_comment;
1038     uInt i;
1039     int err = ZIP_OK;
1040     uLong flagBase = 0;
1041 
1042 #    ifdef NOCRYPT
1043     if (password != nullptr)
1044         return ZIP_PARAMERROR;
1045 #    endif
1046 
1047     if (file == nullptr)
1048         return ZIP_PARAMERROR;
1049     if ((method!=0) && (method!=Z_DEFLATED))
1050         return ZIP_PARAMERROR;
1051 
1052     zi = reinterpret_cast<zip64_internal*>(file);
1053 
1054     if (zi->in_opened_file_inzip == 1)
1055     {
1056         err = cpl_zipCloseFileInZip (file);
1057         if (err != ZIP_OK)
1058             return err;
1059     }
1060 
1061     if (filename==nullptr)
1062         filename="-";
1063 
1064     if (comment==nullptr)
1065         size_comment = 0;
1066     else
1067         size_comment = static_cast<uInt>(strlen(comment));
1068 
1069     size_filename = static_cast<uInt>(strlen(filename));
1070 
1071     if (zipfi == nullptr)
1072         zi->ci.dosDate = 0;
1073     else
1074     {
1075         if (zipfi->dosDate != 0)
1076             zi->ci.dosDate = zipfi->dosDate;
1077         else
1078           zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date);
1079     }
1080 
1081     zi->ci.flag = flagBase;
1082     if ((level==8) || (level==9))
1083       zi->ci.flag |= 2;
1084     if (level==2)
1085       zi->ci.flag |= 4;
1086     if (level==1)
1087       zi->ci.flag |= 6;
1088 #ifndef NOCRYPT
1089     if (password != nullptr)
1090       zi->ci.flag |= 1;
1091 #endif
1092 
1093     zi->ci.crc32 = 0;
1094     zi->ci.method = method;
1095     zi->ci.encrypt = 0;
1096     zi->ci.stream_initialised = 0;
1097     zi->ci.pos_in_buffered_data = 0;
1098     zi->ci.raw = raw;
1099     zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream);
1100 
1101     zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename +
1102                                       size_extrafield_global + size_comment;
1103     zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data
1104 
1105     zi->ci.central_header = static_cast<char*>(ALLOC(static_cast<uInt>(zi->ci.size_centralheader + zi->ci.size_centralExtraFree)));
1106 
1107     zi->ci.size_centralExtra = size_extrafield_global;
1108     zip64local_putValue_inmemory(zi->ci.central_header,CENTRALHEADERMAGIC,4);
1109     /* version info */
1110     zip64local_putValue_inmemory(zi->ci.central_header+4,VERSIONMADEBY,2);
1111     zip64local_putValue_inmemory(zi->ci.central_header+6,20,2);
1112     zip64local_putValue_inmemory(zi->ci.central_header+8,static_cast<uLong>(zi->ci.flag),2);
1113     zip64local_putValue_inmemory(zi->ci.central_header+10,static_cast<uLong>(zi->ci.method),2);
1114     zip64local_putValue_inmemory(zi->ci.central_header+12,static_cast<uLong>(zi->ci.dosDate),4);
1115     zip64local_putValue_inmemory(zi->ci.central_header+16,0,4); /*crc*/
1116     zip64local_putValue_inmemory(zi->ci.central_header+20,0,4); /*compr size*/
1117     zip64local_putValue_inmemory(zi->ci.central_header+24,0,4); /*uncompr size*/
1118     zip64local_putValue_inmemory(zi->ci.central_header+28,static_cast<uLong>(size_filename),2);
1119     zip64local_putValue_inmemory(zi->ci.central_header+30,static_cast<uLong>(size_extrafield_global),2);
1120     zip64local_putValue_inmemory(zi->ci.central_header+32,static_cast<uLong>(size_comment),2);
1121     zip64local_putValue_inmemory(zi->ci.central_header+34,0,2); /*disk nm start*/
1122 
1123     if (zipfi==nullptr)
1124         zip64local_putValue_inmemory(zi->ci.central_header+36,0,2);
1125     else
1126         zip64local_putValue_inmemory(zi->ci.central_header+36,static_cast<uLong>(zipfi->internal_fa),2);
1127 
1128     if (zipfi==nullptr)
1129         zip64local_putValue_inmemory(zi->ci.central_header+38,0,4);
1130     else
1131         zip64local_putValue_inmemory(zi->ci.central_header+38,static_cast<uLong>(zipfi->external_fa),4);
1132 
1133     if(zi->ci.pos_local_header >= 0xffffffff)
1134       zip64local_putValue_inmemory(zi->ci.central_header+42,static_cast<uLong>(0xffffffff),4);
1135     else
1136       zip64local_putValue_inmemory(zi->ci.central_header+42,static_cast<uLong>(zi->ci.pos_local_header)- zi->add_position_when_writing_offset,4);
1137 
1138     for (i=0;i<size_filename;i++)
1139         *(zi->ci.central_header+SIZECENTRALHEADER+i) = *(filename+i);
1140 
1141     for (i=0;i<size_extrafield_global;i++)
1142         *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+i) =
1143               *((reinterpret_cast<const char*>(extrafield_global))+i);
1144 
1145     for (i=0;i<size_comment;i++)
1146         *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+
1147               size_extrafield_global+i) = *(comment+i);
1148     if (zi->ci.central_header == nullptr)
1149         return ZIP_INTERNALERROR;
1150 
1151     zi->ci.totalCompressedData = 0;
1152     zi->ci.totalUncompressedData = 0;
1153     zi->ci.pos_zip64extrainfo = 0;
1154 
1155     // For now default is to generate zip64 extra fields
1156     const bool bZip64 = CPLTestBool(CPLGetConfigOption("CPL_CREATE_ZIP64", "ON"));
1157     err = Write_LocalFileHeader(zi, filename, size_extrafield_local,
1158         extrafield_local, bZip64 ? 1 : 0);
1159 
1160     zi->ci.stream.avail_in = 0;
1161     zi->ci.stream.avail_out = Z_BUFSIZE;
1162     zi->ci.stream.next_out = zi->ci.buffered_data;
1163     zi->ci.stream.total_in = 0;
1164     zi->ci.stream.total_out = 0;
1165     zi->ci.stream.data_type = Z_UNKNOWN;
1166 
1167     if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
1168     {
1169         zi->ci.stream.zalloc = nullptr;
1170         zi->ci.stream.zfree = nullptr;
1171         zi->ci.stream.opaque = nullptr;
1172 
1173         if (windowBits>0)
1174             windowBits = -windowBits;
1175 
1176         if( zi->use_cpl_io )
1177         {
1178             auto fpRaw = reinterpret_cast<VSIVirtualHandle*>(zi->filestream);
1179             zi->vsi_raw_length_before = fpRaw->Tell();
1180             zi->vsi_deflate_handle =
1181                 VSICreateGZipWritable( fpRaw,
1182                                        CPL_DEFLATE_TYPE_RAW_DEFLATE, false);
1183             err = Z_OK;
1184         }
1185         else
1186         {
1187             err = deflateInit2(&zi->ci.stream, level,
1188                 Z_DEFLATED, windowBits, memLevel, strategy);
1189         }
1190 
1191         if (err==Z_OK)
1192             zi->ci.stream_initialised = 1;
1193     }
1194 #ifndef NOCRYPT
1195     zi->ci.crypt_header_size = 0;
1196     if ((err==Z_OK) && (password != nullptr))
1197     {
1198         unsigned char bufHead[RAND_HEAD_LEN];
1199         unsigned int sizeHead = 0;
1200         zi->ci.encrypt = 1;
1201         zi->ci.pcrc_32_tab = get_crc_table();
1202         /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/
1203 
1204         sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting);
1205         zi->ci.crypt_header_size = sizeHead;
1206 
1207         if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead)
1208                 err = ZIP_ERRNO;
1209     }
1210 #endif
1211 
1212     if (err==Z_OK)
1213         zi->in_opened_file_inzip = 1;
1214     else
1215     {
1216         free(zi->ci.central_header);
1217         zi->ci.central_header = nullptr;
1218         free(zi->ci.local_header);
1219         zi->ci.local_header = nullptr;
1220     }
1221 
1222     return err;
1223 }
1224 
cpl_zipOpenNewFileInZip2(zipFile file,const char * filename,const zip_fileinfo * zipfi,const void * extrafield_local,uInt size_extrafield_local,const void * extrafield_global,uInt size_extrafield_global,const char * comment,int method,int level,int raw)1225 extern int ZEXPORT cpl_zipOpenNewFileInZip2(
1226     zipFile file,
1227     const char* filename,
1228     const zip_fileinfo* zipfi,
1229     const void* extrafield_local,
1230     uInt size_extrafield_local,
1231     const void* extrafield_global,
1232     uInt size_extrafield_global,
1233     const char* comment,
1234     int method,
1235     int level,
1236     int raw )
1237 {
1238     return cpl_zipOpenNewFileInZip3 (file, filename, zipfi,
1239                                  extrafield_local, size_extrafield_local,
1240                                  extrafield_global, size_extrafield_global,
1241                                  comment, method, level, raw,
1242                                  -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
1243                                  nullptr, 0);
1244 }
1245 
cpl_zipOpenNewFileInZip(zipFile file,const char * filename,const zip_fileinfo * zipfi,const void * extrafield_local,uInt size_extrafield_local,const void * extrafield_global,uInt size_extrafield_global,const char * comment,int method,int level)1246 extern int ZEXPORT cpl_zipOpenNewFileInZip (
1247     zipFile file,
1248     const char* filename,
1249     const zip_fileinfo* zipfi,
1250     const void* extrafield_local,
1251     uInt size_extrafield_local,
1252     const void* extrafield_global,
1253     uInt size_extrafield_global,
1254     const char* comment,
1255     int method,
1256     int level )
1257 {
1258     return cpl_zipOpenNewFileInZip2 (file, filename, zipfi,
1259                                  extrafield_local, size_extrafield_local,
1260                                  extrafield_global, size_extrafield_global,
1261                                  comment, method, level, 0);
1262 }
1263 
zip64FlushWriteBuffer(zip64_internal * zi)1264 static int zip64FlushWriteBuffer(
1265     zip64_internal* zi )
1266 {
1267     int err=ZIP_OK;
1268 
1269     if (zi->ci.encrypt != 0)
1270     {
1271 #ifndef NOCRYPT
1272         int t = 0;
1273         for (uInt i=0;i<zi->ci.pos_in_buffered_data;i++)
1274             zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab,
1275                                        zi->ci.buffered_data[i],t);
1276 #endif
1277     }
1278     if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) !=zi->ci.pos_in_buffered_data)
1279       err = ZIP_ERRNO;
1280 
1281     zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data;
1282     zi->ci.totalUncompressedData += zi->ci.stream.total_in;
1283     zi->ci.stream.total_in = 0;
1284 
1285     zi->ci.pos_in_buffered_data = 0;
1286     return err;
1287 }
1288 
cpl_zipWriteInFileInZip(zipFile file,const void * buf,unsigned len)1289 extern int ZEXPORT cpl_zipWriteInFileInZip (
1290     zipFile file,
1291     const void* buf,
1292     unsigned len )
1293 {
1294     if (file == nullptr)
1295         return ZIP_PARAMERROR;
1296 
1297     zip64_internal* zi = reinterpret_cast<zip64_internal*>(file);
1298 
1299     if (zi->in_opened_file_inzip == 0)
1300         return ZIP_PARAMERROR;
1301 
1302     zi->ci.stream.next_in = reinterpret_cast<Bytef*>(const_cast<void*>(buf));
1303     zi->ci.stream.avail_in = len;
1304     zi->ci.crc32 = crc32(zi->ci.crc32, reinterpret_cast<const Bytef *>(buf),len);
1305 
1306     int err=ZIP_OK;
1307     while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
1308     {
1309         if (zi->ci.stream.avail_out == 0)
1310         {
1311             if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
1312                 err = ZIP_ERRNO;
1313             zi->ci.stream.avail_out = Z_BUFSIZE;
1314             zi->ci.stream.next_out = zi->ci.buffered_data;
1315         }
1316 
1317         if(err != ZIP_OK)
1318             break;
1319 
1320         if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
1321         {
1322             if( zi->vsi_deflate_handle )
1323             {
1324                 zi->ci.totalUncompressedData += len;
1325                 if( zi->vsi_deflate_handle->Write(buf, 1, len) < len )
1326                     err = ZIP_INTERNALERROR;
1327                 zi->ci.stream.avail_in = 0;
1328             }
1329             else
1330             {
1331                 uLong uTotalOutBefore = zi->ci.stream.total_out;
1332                 err=deflate(&zi->ci.stream,  Z_NO_FLUSH);
1333                 zi->ci.pos_in_buffered_data += static_cast<uInt>(zi->ci.stream.total_out - uTotalOutBefore) ;
1334             }
1335         }
1336         else
1337         {
1338             uInt copy_this;
1339             if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
1340                 copy_this = zi->ci.stream.avail_in;
1341             else
1342                 copy_this = zi->ci.stream.avail_out;
1343             for (uInt i=0;i<copy_this;i++)
1344                 *((reinterpret_cast<char*>(zi->ci.stream.next_out))+i) =
1345                     *((reinterpret_cast<const char*>(zi->ci.stream.next_in))+i);
1346             {
1347                 zi->ci.stream.avail_in -= copy_this;
1348                 zi->ci.stream.avail_out-= copy_this;
1349                 zi->ci.stream.next_in+= copy_this;
1350                 zi->ci.stream.next_out+= copy_this;
1351                 zi->ci.stream.total_in+= copy_this;
1352                 zi->ci.stream.total_out+= copy_this;
1353                 zi->ci.pos_in_buffered_data += copy_this;
1354             }
1355         }
1356     }
1357 
1358     return err;
1359 }
1360 
cpl_zipCloseFileInZipRaw(zipFile file,ZPOS64_T uncompressed_size,uLong crc32)1361 extern int ZEXPORT cpl_zipCloseFileInZipRaw (
1362     zipFile file,
1363     ZPOS64_T uncompressed_size,
1364     uLong crc32 )
1365 {
1366     if (file == nullptr)
1367         return ZIP_PARAMERROR;
1368 
1369     zip64_internal* zi = reinterpret_cast<zip64_internal*>(file);
1370 
1371     if (zi->in_opened_file_inzip == 0)
1372         return ZIP_PARAMERROR;
1373     zi->ci.stream.avail_in = 0;
1374 
1375     int err=ZIP_OK;
1376     if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
1377     {
1378         if( zi->vsi_deflate_handle )
1379         {
1380             auto fpRaw = reinterpret_cast<VSIVirtualHandle*>(zi->filestream);
1381             delete zi->vsi_deflate_handle;
1382             zi->vsi_deflate_handle = nullptr;
1383             zi->ci.totalCompressedData =
1384                 fpRaw->Tell() - zi->vsi_raw_length_before;
1385         }
1386         else
1387         {
1388             while (err==ZIP_OK)
1389             {
1390                 if (zi->ci.stream.avail_out == 0)
1391                 {
1392                     if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
1393                     {
1394                         err = ZIP_ERRNO;
1395                         break;
1396                     }
1397                     zi->ci.stream.avail_out = Z_BUFSIZE;
1398                     zi->ci.stream.next_out = zi->ci.buffered_data;
1399                 }
1400                 uLong uTotalOutBefore = zi->ci.stream.total_out;
1401                 err=deflate(&zi->ci.stream,  Z_FINISH);
1402                 zi->ci.pos_in_buffered_data += static_cast<uInt>(zi->ci.stream.total_out - uTotalOutBefore) ;
1403             }
1404         }
1405     }
1406 
1407     if (err==Z_STREAM_END)
1408         err=ZIP_OK; /* this is normal */
1409 
1410     if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK))
1411         if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO)
1412             err = ZIP_ERRNO;
1413 
1414     if ( !zi->use_cpl_io && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
1415     {
1416         err=deflateEnd(&zi->ci.stream);
1417         zi->ci.stream_initialised = 0;
1418     }
1419 
1420     if (!zi->ci.raw)
1421     {
1422         crc32 = static_cast<uLong>(zi->ci.crc32);
1423         uncompressed_size = zi->ci.totalUncompressedData;
1424     }
1425     ZPOS64_T compressed_size = zi->ci.totalCompressedData;
1426 #ifndef NOCRYPT
1427     compressed_size += zi->ci.crypt_header_size;
1428 #endif
1429 
1430 #ifdef disabled
1431     // Code finally disabled since it causes compatibility issues with
1432     // libreoffice for .xlsx or .ods files
1433     if( zi->ci.pos_zip64extrainfo &&
1434         uncompressed_size < 0xffffffff && compressed_size < 0xffffffff )
1435     {
1436         // Update the LocalFileHeader to be a regular one and not a ZIP64 one
1437         // by removing its trailing 20 bytes, and moving it in the file
1438         // 20 bytes further of its original position.
1439 
1440         ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream);
1441 
1442         if (ZSEEK64(zi->z_filefunc,zi->filestream,
1443                 zi->ci.pos_local_header,ZLIB_FILEFUNC_SEEK_SET)!=0)
1444             err = ZIP_ERRNO;
1445 
1446         // Insert leading padding
1447         constexpr uInt nZIP64ExtraBytes = 20;
1448         char padding[nZIP64ExtraBytes];
1449         memset(padding, 0, sizeof(padding));
1450         if( ZWRITE64(zi->z_filefunc,zi->filestream,
1451             padding,nZIP64ExtraBytes) != nZIP64ExtraBytes )
1452             err = ZIP_ERRNO;
1453 
1454         // Correct version needed to extract
1455         zip64local_putValue_inmemory(
1456             zi->ci.local_header + 4, 20, 2);
1457 
1458         // Correct extra field length
1459         zi->ci.size_local_header_extrafield -= nZIP64ExtraBytes;
1460         zip64local_putValue_inmemory(
1461             zi->ci.local_header + 28,
1462             zi->ci.size_local_header_extrafield, 2 );
1463 
1464         zi->ci.size_local_header -= nZIP64ExtraBytes;
1465 
1466         // Rewrite local header
1467         if( ZWRITE64(zi->z_filefunc,zi->filestream,
1468                 zi->ci.local_header,
1469                 zi->ci.size_local_header ) != zi->ci.size_local_header )
1470             err = ZIP_ERRNO;
1471 
1472         if (ZSEEK64(zi->z_filefunc,zi->filestream,
1473                   cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0)
1474             err = ZIP_ERRNO;
1475 
1476         zi->ci.pos_zip64extrainfo = 0;
1477 
1478         // Correct central header offset to local header
1479         zi->ci.pos_local_header += nZIP64ExtraBytes;
1480         if(zi->ci.pos_local_header >= 0xffffffff)
1481             zip64local_putValue_inmemory(zi->ci.central_header+42,static_cast<uLong>(0xffffffff),4);
1482         else
1483             zip64local_putValue_inmemory(zi->ci.central_header+42,static_cast<uLong>(zi->ci.pos_local_header)- zi->add_position_when_writing_offset,4);
1484     }
1485 #endif
1486 
1487     // update Current Item crc and sizes,
1488     if( zi->ci.pos_zip64extrainfo ||
1489         compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff)
1490     {
1491       /*version Made by*/
1492       zip64local_putValue_inmemory(zi->ci.central_header+4,45,2);
1493       /*version needed*/
1494       zip64local_putValue_inmemory(zi->ci.central_header+6,45,2);
1495 
1496     }
1497 
1498     zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/
1499 
1500     const uLong invalidValue = 0xffffffff;
1501     if(compressed_size >= 0xffffffff)
1502       zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/
1503     else
1504       zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/
1505 
1506     /// set internal file attributes field
1507     if (zi->ci.stream.data_type == Z_ASCII)
1508         zip64local_putValue_inmemory(zi->ci.central_header+36,Z_ASCII,2);
1509 
1510     if(uncompressed_size >= 0xffffffff)
1511       zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/
1512     else
1513       zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/
1514 
1515     short datasize = 0;
1516     // Add ZIP64 extra info field for uncompressed size
1517     if(uncompressed_size >= 0xffffffff)
1518       datasize += 8;
1519 
1520     // Add ZIP64 extra info field for compressed size
1521     if(compressed_size >= 0xffffffff)
1522       datasize += 8;
1523 
1524     // Add ZIP64 extra info field for relative offset to local file header of current file
1525     if(zi->ci.pos_local_header >= 0xffffffff)
1526       datasize += 8;
1527 
1528     if(datasize > 0)
1529     {
1530       char* p = nullptr;
1531 
1532       if(static_cast<uLong>(datasize + 4) > zi->ci.size_centralExtraFree)
1533       {
1534         // we can not write more data to the buffer that we have room for.
1535         return ZIP_BADZIPFILE;
1536       }
1537 
1538       p = zi->ci.central_header + zi->ci.size_centralheader;
1539 
1540       // Add Extra Information Header for 'ZIP64 information'
1541       zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID
1542       p += 2;
1543       zip64local_putValue_inmemory(p, datasize, 2); // DataSize
1544       p += 2;
1545 
1546       if(uncompressed_size >= 0xffffffff)
1547       {
1548         zip64local_putValue_inmemory(p, uncompressed_size, 8);
1549         p += 8;
1550       }
1551 
1552       if(compressed_size >= 0xffffffff)
1553       {
1554         zip64local_putValue_inmemory(p, compressed_size, 8);
1555         p += 8;
1556       }
1557 
1558       if(zi->ci.pos_local_header >= 0xffffffff)
1559       {
1560         zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8);
1561         //p += 8;
1562       }
1563 
1564       // Update how much extra free space we got in the memory buffer
1565       // and increase the centralheader size so the new ZIP64 fields are included
1566       // ( 4 below is the size of HeaderID and DataSize field )
1567       zi->ci.size_centralExtraFree -= datasize + 4;
1568       zi->ci.size_centralheader += datasize + 4;
1569 
1570       // Update the extra info size field
1571       zi->ci.size_centralExtra += datasize + 4;
1572       zip64local_putValue_inmemory(zi->ci.central_header+30,static_cast<uLong>(zi->ci.size_centralExtra),2);
1573     }
1574 
1575     if (err==ZIP_OK)
1576         err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header,
1577                                        static_cast<uLong>(zi->ci.size_centralheader));
1578     free(zi->ci.central_header);
1579     zi->ci.central_header = nullptr;
1580     free(zi->ci.local_header);
1581     zi->ci.local_header = nullptr;
1582 
1583     if (err==ZIP_OK)
1584     {
1585         // Update the LocalFileHeader with the new values.
1586 
1587         ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream);
1588 
1589         if (ZSEEK64(zi->z_filefunc,zi->filestream,
1590                   zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0)
1591             err = ZIP_ERRNO;
1592 
1593         if (err==ZIP_OK)
1594             err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */
1595 
1596         if(uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff )
1597         {
1598           if(zi->ci.pos_zip64extrainfo > 0)
1599           {
1600             // Update the size in the ZIP64 extended field.
1601             if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0)
1602               err = ZIP_ERRNO;
1603 
1604             if (err==ZIP_OK) /* compressed size, unknown */
1605               err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8);
1606 
1607             if (err==ZIP_OK) /* uncompressed size, unknown */
1608               err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8);
1609           }
1610           else
1611               err = ZIP_BADZIPFILE; // Caller passed zip64 = 0, so no room for zip64 info -> fatal
1612         }
1613         else
1614         {
1615           if (err==ZIP_OK) /* compressed size, unknown */
1616               err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4);
1617 
1618           if (err==ZIP_OK) /* uncompressed size, unknown */
1619               err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4);
1620         }
1621         if (ZSEEK64(zi->z_filefunc,zi->filestream,
1622                   cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0)
1623             err = ZIP_ERRNO;
1624     }
1625 
1626     zi->number_entry ++;
1627     zi->in_opened_file_inzip = 0;
1628 
1629     return err;
1630 }
1631 
cpl_zipCloseFileInZip(zipFile file)1632 extern int ZEXPORT cpl_zipCloseFileInZip (
1633     zipFile file )
1634 {
1635     return cpl_zipCloseFileInZipRaw (file,0,0);
1636 }
1637 
Write_Zip64EndOfCentralDirectoryLocator(zip64_internal * zi,ZPOS64_T zip64eocd_pos_inzip)1638 static int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip)
1639 {
1640   int err = ZIP_OK;
1641   ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writing_offset;
1642 
1643   err = zip64local_putValue(&zi->z_filefunc,zi->filestream,ZIP64ENDLOCHEADERMAGIC,4);
1644 
1645   /*num disks*/
1646     if (err==ZIP_OK) /* number of the disk with the start of the central directory */
1647       err = zip64local_putValue(&zi->z_filefunc,zi->filestream,0,4);
1648 
1649   /*relative offset*/
1650     if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */
1651       err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8);
1652 
1653   /*total disks*/ /* Do not support spawning of disk so always say 1 here*/
1654     if (err==ZIP_OK) /* number of the disk with the start of the central directory */
1655       err = zip64local_putValue(&zi->z_filefunc,zi->filestream,1,4);
1656 
1657     return err;
1658 }
1659 
Write_Zip64EndOfCentralDirectoryRecord(zip64_internal * zi,uLong size_centraldir,ZPOS64_T centraldir_pos_inzip)1660 static int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip)
1661 {
1662   int err = ZIP_OK;
1663 
1664   uLong Zip64DataSize = 44;
1665 
1666   err = zip64local_putValue(&zi->z_filefunc,zi->filestream,ZIP64ENDHEADERMAGIC,4);
1667 
1668   if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */
1669     err = zip64local_putValue(&zi->z_filefunc,zi->filestream,Zip64DataSize,8); // why ZPOS64_T of this ?
1670 
1671   if (err==ZIP_OK) /* version made by */
1672     err = zip64local_putValue(&zi->z_filefunc,zi->filestream,45,2);
1673 
1674   if (err==ZIP_OK) /* version needed */
1675     err = zip64local_putValue(&zi->z_filefunc,zi->filestream,45,2);
1676 
1677   if (err==ZIP_OK) /* number of this disk */
1678     err = zip64local_putValue(&zi->z_filefunc,zi->filestream,0,4);
1679 
1680   if (err==ZIP_OK) /* number of the disk with the start of the central directory */
1681     err = zip64local_putValue(&zi->z_filefunc,zi->filestream,0,4);
1682 
1683   if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
1684     err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8);
1685 
1686   if (err==ZIP_OK) /* total number of entries in the central dir */
1687     err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8);
1688 
1689   if (err==ZIP_OK) /* size of the central directory */
1690     err = zip64local_putValue(&zi->z_filefunc,zi->filestream,size_centraldir,8);
1691 
1692   if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */
1693   {
1694     ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset;
1695     err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8);
1696   }
1697   return err;
1698 }
1699 
Write_EndOfCentralDirectoryRecord(zip64_internal * zi,uLong size_centraldir,ZPOS64_T centraldir_pos_inzip)1700 static int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip)
1701 {
1702   int err = ZIP_OK;
1703 
1704   /*signature*/
1705   err = zip64local_putValue(&zi->z_filefunc,zi->filestream,ENDHEADERMAGIC,4);
1706 
1707   if (err==ZIP_OK) /* number of this disk */
1708     err = zip64local_putValue(&zi->z_filefunc,zi->filestream,0,2);
1709 
1710   if (err==ZIP_OK) /* number of the disk with the start of the central directory */
1711     err = zip64local_putValue(&zi->z_filefunc,zi->filestream,0,2);
1712 
1713   if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
1714   {
1715     {
1716       if(zi->number_entry >= 0xFFFF)
1717         err = zip64local_putValue(&zi->z_filefunc,zi->filestream,0xffff,2); // use value in ZIP64 record
1718       else
1719         err = zip64local_putValue(&zi->z_filefunc,zi->filestream,zi->number_entry,2);
1720     }
1721   }
1722 
1723   if (err==ZIP_OK) /* total number of entries in the central dir */
1724   {
1725     if(zi->number_entry >= 0xFFFF)
1726       err = zip64local_putValue(&zi->z_filefunc,zi->filestream,0xffff,2); // use value in ZIP64 record
1727     else
1728       err = zip64local_putValue(&zi->z_filefunc,zi->filestream,zi->number_entry,2);
1729   }
1730 
1731   if (err==ZIP_OK) /* size of the central directory */
1732     err = zip64local_putValue(&zi->z_filefunc,zi->filestream,size_centraldir,4);
1733 
1734   if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */
1735   {
1736     ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset;
1737     if(pos >= 0xffffffff)
1738     {
1739       err = zip64local_putValue(&zi->z_filefunc,zi->filestream, 0xffffffff,4);
1740     }
1741     else
1742       err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (centraldir_pos_inzip - zi->add_position_when_writing_offset),4);
1743   }
1744 
1745    return err;
1746 }
1747 
Write_GlobalComment(zip64_internal * zi,const char * global_comment)1748 static int Write_GlobalComment(zip64_internal* zi, const char* global_comment)
1749 {
1750   int err = ZIP_OK;
1751   uInt size_global_comment = 0;
1752 
1753   if(global_comment != nullptr)
1754     size_global_comment = static_cast<uInt>(strlen(global_comment));
1755 
1756   err = zip64local_putValue(&zi->z_filefunc,zi->filestream,size_global_comment,2);
1757 
1758   if (err == ZIP_OK && size_global_comment > 0)
1759   {
1760     if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment)
1761       err = ZIP_ERRNO;
1762   }
1763   return err;
1764 }
1765 
cpl_zipClose(zipFile file,const char * global_comment)1766 extern int ZEXPORT cpl_zipClose (
1767     zipFile file,
1768     const char* global_comment)
1769 {
1770     int err = 0;
1771     uLong size_centraldir = 0;
1772     ZPOS64_T centraldir_pos_inzip;
1773     ZPOS64_T pos;
1774 
1775     if (file == nullptr)
1776         return ZIP_PARAMERROR;
1777 
1778     zip64_internal* zi = reinterpret_cast<zip64_internal*>(file);
1779 
1780     if (zi->in_opened_file_inzip == 1)
1781     {
1782         err = cpl_zipCloseFileInZip (file);
1783     }
1784 
1785 #ifndef NO_ADDFILEINEXISTINGZIP
1786     if (global_comment==nullptr)
1787         global_comment = zi->globalcomment;
1788 #endif
1789 
1790     centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream);
1791     if (err==ZIP_OK)
1792     {
1793         linkedlist_datablock_internal* ldi = zi->central_dir.first_block;
1794         while (ldi!=nullptr)
1795         {
1796             if ((err==ZIP_OK) && (ldi->filled_in_this_block>0))
1797                 if (ZWRITE64(zi->z_filefunc,zi->filestream,
1798                            ldi->data,ldi->filled_in_this_block)
1799                               !=ldi->filled_in_this_block )
1800                     err = ZIP_ERRNO;
1801 
1802             size_centraldir += ldi->filled_in_this_block;
1803             ldi = ldi->next_datablock;
1804         }
1805     }
1806     free_linkedlist(&(zi->central_dir));
1807 
1808     pos = centraldir_pos_inzip - zi->add_position_when_writing_offset;
1809     if(pos >= 0xffffffff || zi->number_entry > 0xFFFF)
1810     {
1811       ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream);
1812       Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip);
1813 
1814       Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos);
1815     }
1816 
1817     if (err==ZIP_OK)
1818       err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip);
1819 
1820     if(err == ZIP_OK)
1821       err = Write_GlobalComment(zi, global_comment);
1822 
1823     if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0)
1824         if (err == ZIP_OK)
1825             err = ZIP_ERRNO;
1826 
1827 #ifndef NO_ADDFILEINEXISTINGZIP
1828     TRYFREE(zi->globalcomment);
1829 #endif
1830     TRYFREE(zi);
1831 
1832     return err;
1833 }
1834 
1835 /************************************************************************/
1836 /* ==================================================================== */
1837 /*   The following is a simplified CPL API for creating ZIP files       */
1838 /*   exported from cpl_conv.h.                                          */
1839 /* ==================================================================== */
1840 /************************************************************************/
1841 
1842 #include "cpl_minizip_unzip.h"
1843 
1844 typedef struct
1845 {
1846     zipFile   hZip;
1847     char    **papszFilenames;
1848 } CPLZip;
1849 
1850 /************************************************************************/
1851 /*                            CPLCreateZip()                            */
1852 /************************************************************************/
1853 
1854 /** Create ZIP file */
CPLCreateZip(const char * pszZipFilename,char ** papszOptions)1855 void *CPLCreateZip( const char *pszZipFilename, char **papszOptions )
1856 
1857 {
1858     const bool bAppend =
1859         CPLTestBool(CSLFetchNameValueDef(papszOptions, "APPEND", "FALSE"));
1860     char** papszFilenames = nullptr;
1861 
1862     if( bAppend )
1863     {
1864         zipFile unzF = cpl_unzOpen(pszZipFilename);
1865         if( unzF != nullptr )
1866         {
1867             if( cpl_unzGoToFirstFile(unzF) == UNZ_OK )
1868             {
1869                 do
1870                 {
1871                     char fileName[8193];
1872                     unz_file_info file_info;
1873                     cpl_unzGetCurrentFileInfo (unzF, &file_info, fileName,
1874                                             sizeof(fileName) - 1, nullptr, 0, nullptr, 0);
1875                     fileName[sizeof(fileName) - 1] = '\0';
1876                     papszFilenames = CSLAddString(papszFilenames, fileName);
1877                 }
1878                 while( cpl_unzGoToNextFile(unzF) == UNZ_OK );
1879             }
1880             cpl_unzClose(unzF);
1881         }
1882     }
1883 
1884     zipFile hZip = cpl_zipOpen( pszZipFilename, bAppend ? APPEND_STATUS_ADDINZIP : APPEND_STATUS_CREATE);
1885     if( hZip == nullptr )
1886     {
1887         CSLDestroy(papszFilenames);
1888         return nullptr;
1889     }
1890 
1891     CPLZip* psZip = static_cast<CPLZip *>(CPLMalloc(sizeof(CPLZip)));
1892     psZip->hZip = hZip;
1893     psZip->papszFilenames = papszFilenames;
1894     return psZip;
1895 }
1896 
1897 /************************************************************************/
1898 /*                         CPLCreateFileInZip()                         */
1899 /************************************************************************/
1900 
1901 /** Create a file in a ZIP file */
CPLCreateFileInZip(void * hZip,const char * pszFilename,char ** papszOptions)1902 CPLErr CPLCreateFileInZip( void *hZip, const char *pszFilename,
1903                            char **papszOptions )
1904 
1905 {
1906     if( hZip == nullptr )
1907         return CE_Failure;
1908 
1909     CPLZip* psZip = static_cast<CPLZip*>(hZip);
1910 
1911     if( CSLFindString(psZip->papszFilenames, pszFilename ) >= 0)
1912     {
1913         CPLError(CE_Failure, CPLE_AppDefined,
1914                 "%s already exists in ZIP file", pszFilename);
1915         return CE_Failure;
1916     }
1917 
1918     const bool bCompressed =
1919         CPLTestBool(CSLFetchNameValueDef(papszOptions, "COMPRESSED", "TRUE"));
1920 
1921     // If the filename is ASCII only, then no need for an extended field
1922     bool bIsAscii = true;
1923     for( int i=0; pszFilename[i] != '\0'; i++ )
1924     {
1925         if( (reinterpret_cast<const GByte*>(pszFilename))[i] > 127 )
1926         {
1927             bIsAscii = false;
1928             break;
1929         }
1930     }
1931 
1932     char* pszCPFilename = nullptr;
1933     unsigned int nExtraLength = 0;
1934     GByte* pabyExtra = nullptr;
1935     if( !bIsAscii )
1936     {
1937         const char* pszDestEncoding = CPLGetConfigOption("CPL_ZIP_ENCODING",
1938 #if defined(_WIN32) && !defined(HAVE_ICONV)
1939                                                         "CP_OEMCP"
1940 #else
1941                                                         "CP437"
1942 #endif
1943                                                         );
1944 
1945         pszCPFilename = CPLRecode(pszFilename, CPL_ENC_UTF8, pszDestEncoding);
1946 
1947         /* Create a Info-ZIP Unicode Path Extra Field (0x7075) */
1948         const GUInt16 nDataLength = 1 + 4 +
1949                                     static_cast<GUInt16>(strlen(pszFilename));
1950         nExtraLength = 2 + 2 + nDataLength;
1951         pabyExtra = static_cast<GByte*>(CPLMalloc(nExtraLength));
1952         const GUInt16 nHeaderIdLE = CPL_LSBWORD16(0x7075);
1953         memcpy(pabyExtra, &nHeaderIdLE, 2);
1954         const GUInt16 nDataLengthLE = CPL_LSBWORD16(nDataLength);
1955         memcpy(pabyExtra + 2, &nDataLengthLE, 2);
1956         const GByte nVersion = 1;
1957         memcpy(pabyExtra + 2 + 2, &nVersion, 1);
1958         const GUInt32 nNameCRC32 = static_cast<GUInt32>(crc32(0,
1959                 reinterpret_cast<const Bytef*>(pszCPFilename),
1960                 static_cast<uInt>(strlen(pszCPFilename))));
1961         const GUInt32 nNameCRC32LE = CPL_LSBWORD32(nNameCRC32);
1962         memcpy(pabyExtra + 2 + 2 + 1, &nNameCRC32LE, 4);
1963         memcpy(pabyExtra + 2 + 2 + 1 + 4, pszFilename, strlen(pszFilename));
1964     }
1965     else
1966     {
1967         pszCPFilename = CPLStrdup(pszFilename);
1968     }
1969 
1970     const int nErr =
1971         cpl_zipOpenNewFileInZip(
1972             psZip->hZip, pszCPFilename, nullptr,
1973             pabyExtra, nExtraLength, pabyExtra, nExtraLength, "",
1974             bCompressed ? Z_DEFLATED : 0,
1975             bCompressed ? Z_DEFAULT_COMPRESSION : 0 );
1976 
1977     CPLFree( pabyExtra );
1978     CPLFree( pszCPFilename );
1979 
1980     if( nErr != ZIP_OK )
1981         return CE_Failure;
1982 
1983     psZip->papszFilenames = CSLAddString(psZip->papszFilenames, pszFilename);
1984     return CE_None;
1985 }
1986 
1987 /************************************************************************/
1988 /*                         CPLWriteFileInZip()                          */
1989 /************************************************************************/
1990 
1991 /** Write in current file inside a ZIP file */
CPLWriteFileInZip(void * hZip,const void * pBuffer,int nBufferSize)1992 CPLErr CPLWriteFileInZip( void *hZip, const void *pBuffer, int nBufferSize )
1993 
1994 {
1995     if( hZip == nullptr )
1996         return CE_Failure;
1997 
1998     CPLZip* psZip = static_cast<CPLZip*>(hZip);
1999 
2000     int nErr = cpl_zipWriteInFileInZip( psZip->hZip, pBuffer,
2001                                     static_cast<unsigned int>(nBufferSize) );
2002 
2003     if( nErr != ZIP_OK )
2004         return CE_Failure;
2005 
2006     return CE_None;
2007 }
2008 
2009 /************************************************************************/
2010 /*                         CPLCloseFileInZip()                          */
2011 /************************************************************************/
2012 
2013 /** Close current file inside ZIP file */
CPLCloseFileInZip(void * hZip)2014 CPLErr CPLCloseFileInZip( void *hZip )
2015 
2016 {
2017     if( hZip == nullptr )
2018         return CE_Failure;
2019 
2020     CPLZip* psZip = static_cast<CPLZip*>(hZip);
2021 
2022     int nErr = cpl_zipCloseFileInZip( psZip->hZip );
2023 
2024     if( nErr != ZIP_OK )
2025         return CE_Failure;
2026 
2027     return CE_None;
2028 }
2029 
2030 /************************************************************************/
2031 /*                            CPLCloseZip()                             */
2032 /************************************************************************/
2033 
2034 /** Close ZIP file */
CPLCloseZip(void * hZip)2035 CPLErr CPLCloseZip( void *hZip )
2036 {
2037     if( hZip == nullptr )
2038         return CE_Failure;
2039 
2040     CPLZip* psZip = static_cast<CPLZip*>(hZip);
2041 
2042     int nErr = cpl_zipClose(psZip->hZip, nullptr);
2043 
2044     psZip->hZip = nullptr;
2045     CSLDestroy(psZip->papszFilenames);
2046     psZip->papszFilenames = nullptr;
2047     CPLFree(psZip);
2048 
2049     if( nErr != ZIP_OK )
2050         return CE_Failure;
2051 
2052     return CE_None;
2053 }
2054