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