Line data Source code
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 :
22 : Copyright (C) 1998-2010 Gilles Vollant (minizip) (
23 : http://www.winimage.com/zLibDll/minizip.html )
24 :
25 : Modifications for Zip64 support
26 : Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
27 :
28 : For more info read MiniZip_info.txt
29 :
30 : Changes
31 : Oct-2009 - Mathias Svensson - Remove old C style function prototypes
32 : Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file
33 : archives Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring
34 : to get better overview of some functions. Oct-2009 - Mathias Svensson - Added
35 : zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data It is
36 : used when recreating zip archive with RAW when deleting items from a zip.
37 : ZIP64 data is automatically added to items that
38 : needs it, and existing ZIP64 data need to be removed. Oct-2009 - Mathias
39 : Svensson - Added support for BZIP2 as compression mode (bzip2 lib is
40 : required) Jan-2010 - back to unzip and minizip 1.0 name scheme, with
41 : compatibility layer
42 :
43 : Copyright (c) 2010-2018, Even Rouault <even dot rouault at spatialys.com>
44 :
45 : */
46 :
47 : #include "cpl_port.h"
48 : #include "cpl_minizip_zip.h"
49 :
50 : #include <algorithm>
51 : #include <limits>
52 :
53 : #include <cassert>
54 : #include <cstddef>
55 : #include <cstdlib>
56 : #include <cstring>
57 : #if HAVE_FCNTL_H
58 : #include <fcntl.h>
59 : #endif
60 : #include <time.h>
61 :
62 : #include "cpl_conv.h"
63 : #include "cpl_error.h"
64 : #include "cpl_minizip_unzip.h"
65 : #include "cpl_string.h"
66 : #include "cpl_time.h"
67 : #include "cpl_vsi_virtual.h"
68 :
69 : #ifdef NO_ERRNO_H
70 : extern int errno;
71 : #else
72 : #include <errno.h>
73 : #endif
74 :
75 : #ifndef VERSIONMADEBY
76 : #define VERSIONMADEBY (0x0) /* platform dependent */
77 : #endif
78 :
79 : #ifndef Z_BUFSIZE
80 : #define Z_BUFSIZE (16384)
81 : #endif
82 :
83 : #ifndef ALLOC
84 : #define ALLOC(size) (malloc(size))
85 : #endif
86 : #ifndef TRYFREE
87 : #define TRYFREE(p) \
88 : { \
89 : if (p) \
90 : free(p); \
91 : }
92 : #endif
93 :
94 : /*
95 : #define SIZECENTRALDIRITEM (0x2e)
96 : #define SIZEZIPLOCALHEADER (0x1e)
97 : */
98 :
99 : /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined... */
100 :
101 : #ifndef SEEK_CUR
102 : #define SEEK_CUR 1
103 : #endif
104 :
105 : #ifndef SEEK_END
106 : #define SEEK_END 2
107 : #endif
108 :
109 : #ifndef SEEK_SET
110 : #define SEEK_SET 0
111 : #endif
112 :
113 : #ifndef DEF_MEM_LEVEL
114 : #if MAX_MEM_LEVEL >= 8
115 : #define DEF_MEM_LEVEL 8
116 : #else
117 : #define DEF_MEM_LEVEL MAX_MEM_LEVEL
118 : #endif
119 : #endif
120 :
121 : CPL_UNUSED static const char zip_copyright[] =
122 : " zip 1.01 Copyright 1998-2004 Gilles Vollant - "
123 : "http://www.winimage.com/zLibDll";
124 :
125 : #define SIZEDATA_INDATABLOCK (4096 - (4 * 4))
126 :
127 : #define LOCALHEADERMAGIC (0x04034b50)
128 : #define CENTRALHEADERMAGIC (0x02014b50)
129 : #define ENDHEADERMAGIC (0x06054b50)
130 : #define ZIP64ENDHEADERMAGIC (0x6064b50)
131 : #define ZIP64ENDLOCHEADERMAGIC (0x7064b50)
132 :
133 : #define FLAG_LOCALHEADER_OFFSET (0x06)
134 : #define CRC_LOCALHEADER_OFFSET (0x0e)
135 :
136 : #define SIZECENTRALHEADER (0x2e) /* 46 */
137 :
138 : typedef struct linkedlist_datablock_internal_s
139 : {
140 : struct linkedlist_datablock_internal_s *next_datablock;
141 : uLong avail_in_this_block;
142 : uLong filled_in_this_block;
143 : uLong unused; // For future use and alignment.
144 : unsigned char data[SIZEDATA_INDATABLOCK];
145 : } linkedlist_datablock_internal;
146 :
147 : typedef struct linkedlist_data_s
148 : {
149 : linkedlist_datablock_internal *first_block;
150 : linkedlist_datablock_internal *last_block;
151 : } linkedlist_data;
152 :
153 : typedef struct
154 : {
155 : z_stream stream; /* zLib stream structure for inflate */
156 : int stream_initialised; /* 1 is stream is initialized */
157 : uInt pos_in_buffered_data; /* last written byte in buffered_data */
158 :
159 : ZPOS64_T pos_local_header; /* offset of the local header of the file
160 : currently writing */
161 : char *local_header;
162 : uInt size_local_header;
163 : uInt size_local_header_extrafield;
164 :
165 : char *central_header; /* central header data for the current file */
166 : uLong size_centralExtra;
167 : uLong size_centralheader; /* size of the central header for cur file */
168 : uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader
169 : but that are not used */
170 : uLong flag; /* flag of the file currently writing */
171 :
172 : // TODO: What is "wr"? "to"?
173 : int method; /* compression method of file currently wr.*/
174 : int raw; /* 1 for directly writing raw data */
175 : Byte buffered_data[Z_BUFSIZE]; /* buffer contain compressed data to be
176 : written. */
177 : uLong dosDate;
178 : uLong crc32;
179 : int encrypt;
180 : ZPOS64_T pos_zip64extrainfo;
181 : ZPOS64_T totalCompressedData;
182 : ZPOS64_T totalUncompressedData;
183 : #ifndef NOCRYPT
184 : unsigned long keys[3]; /* keys defining the pseudo-random sequence */
185 : const unsigned long *pcrc_32_tab;
186 : int crypt_header_size;
187 : #endif
188 : } curfile64_info;
189 :
190 : typedef struct
191 : {
192 : zlib_filefunc_def z_filefunc;
193 : voidpf filestream; /* IO structure of the zipfile */
194 : linkedlist_data central_dir; /* datablock with central dir in construction*/
195 : int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/
196 : curfile64_info ci; /* info on the file currently writing */
197 :
198 : ZPOS64_T begin_pos; /* position of the beginning of the zipfile */
199 : ZPOS64_T add_position_when_writing_offset;
200 : ZPOS64_T number_entry;
201 : #ifndef NO_ADDFILEINEXISTINGZIP
202 : char *globalcomment;
203 : #endif
204 : int use_cpl_io;
205 : vsi_l_offset vsi_raw_length_before;
206 : VSIVirtualHandle *vsi_deflate_handle;
207 : size_t nChunkSize;
208 : int nThreads;
209 : size_t nOffsetSize;
210 : std::vector<uint8_t> *sozip_index;
211 : } zip64_internal;
212 :
213 : #ifndef NOCRYPT
214 : #define INCLUDECRYPTINGCODE_IFCRYPTALLOWED
215 : #include "crypt.h"
216 : #endif
217 :
218 386 : static linkedlist_datablock_internal *allocate_new_datablock()
219 : {
220 : linkedlist_datablock_internal *ldi;
221 : ldi = static_cast<linkedlist_datablock_internal *>(
222 386 : ALLOC(sizeof(linkedlist_datablock_internal)));
223 386 : if (ldi != nullptr)
224 : {
225 386 : ldi->next_datablock = nullptr;
226 386 : ldi->filled_in_this_block = 0;
227 386 : ldi->avail_in_this_block = SIZEDATA_INDATABLOCK;
228 : }
229 386 : return ldi;
230 : }
231 :
232 830 : static void free_datablock(linkedlist_datablock_internal *ldi)
233 : {
234 830 : while (ldi != nullptr)
235 : {
236 386 : linkedlist_datablock_internal *ldinext = ldi->next_datablock;
237 386 : TRYFREE(ldi);
238 386 : ldi = ldinext;
239 : }
240 444 : }
241 :
242 444 : static void init_linkedlist(linkedlist_data *ll)
243 : {
244 444 : ll->first_block = ll->last_block = nullptr;
245 444 : }
246 :
247 444 : static void free_linkedlist(linkedlist_data *ll)
248 : {
249 444 : free_datablock(ll->first_block);
250 444 : ll->first_block = ll->last_block = nullptr;
251 444 : }
252 :
253 860 : static int add_data_in_datablock(linkedlist_data *ll, const void *buf,
254 : uLong len)
255 : {
256 : linkedlist_datablock_internal *ldi;
257 : const unsigned char *from_copy;
258 :
259 860 : if (ll == nullptr)
260 0 : return ZIP_INTERNALERROR;
261 :
262 860 : if (ll->last_block == nullptr)
263 : {
264 385 : ll->first_block = ll->last_block = allocate_new_datablock();
265 385 : if (ll->first_block == nullptr)
266 0 : return ZIP_INTERNALERROR;
267 : }
268 :
269 860 : ldi = ll->last_block;
270 860 : from_copy = reinterpret_cast<const unsigned char *>(buf);
271 :
272 1721 : while (len > 0)
273 : {
274 : uInt copy_this;
275 : uInt i;
276 : unsigned char *to_copy;
277 :
278 861 : if (ldi->avail_in_this_block == 0)
279 : {
280 1 : ldi->next_datablock = allocate_new_datablock();
281 1 : if (ldi->next_datablock == nullptr)
282 0 : return ZIP_INTERNALERROR;
283 1 : ldi = ldi->next_datablock;
284 1 : ll->last_block = ldi;
285 : }
286 :
287 861 : if (ldi->avail_in_this_block < len)
288 1 : copy_this = static_cast<uInt>(ldi->avail_in_this_block);
289 : else
290 860 : copy_this = static_cast<uInt>(len);
291 :
292 861 : to_copy = &(ldi->data[ldi->filled_in_this_block]);
293 :
294 77106 : for (i = 0; i < copy_this; i++)
295 76245 : *(to_copy + i) = *(from_copy + i);
296 :
297 861 : ldi->filled_in_this_block += copy_this;
298 861 : ldi->avail_in_this_block -= copy_this;
299 861 : from_copy += copy_this;
300 861 : len -= copy_this;
301 : }
302 860 : return ZIP_OK;
303 : }
304 :
305 : /****************************************************************************/
306 :
307 : #ifndef NO_ADDFILEINEXISTINGZIP
308 : /* ===========================================================================
309 : Inputs a long in LSB order to the given file
310 : nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T)
311 : */
312 :
313 4954 : static int zip64local_putValue(const zlib_filefunc_def *pzlib_filefunc_def,
314 : voidpf filestream, ZPOS64_T x, int nbByte)
315 : {
316 : unsigned char buf[8];
317 21074 : for (int n = 0; n < nbByte; n++)
318 : {
319 16120 : buf[n] = static_cast<unsigned char>(x & 0xff);
320 16120 : x >>= 8;
321 : }
322 4954 : if (x != 0)
323 : { /* data overflow - hack for ZIP64 (X Roche) */
324 0 : for (int n = 0; n < nbByte; n++)
325 : {
326 0 : buf[n] = 0xff;
327 : }
328 : }
329 :
330 4954 : if (ZWRITE64(*pzlib_filefunc_def, filestream, buf, nbByte) !=
331 4954 : static_cast<uLong>(nbByte))
332 38 : return ZIP_ERRNO;
333 : else
334 4916 : return ZIP_OK;
335 : }
336 :
337 22174 : static void zip64local_putValue_inmemory(void *dest, ZPOS64_T x, int nbByte)
338 : {
339 22174 : unsigned char *buf = reinterpret_cast<unsigned char *>(dest);
340 90998 : for (int n = 0; n < nbByte; n++)
341 : {
342 68824 : buf[n] = static_cast<unsigned char>(x & 0xff);
343 68824 : x >>= 8;
344 : }
345 :
346 22174 : if (x != 0)
347 : { /* data overflow - hack for ZIP64 */
348 0 : for (int n = 0; n < nbByte; n++)
349 : {
350 0 : buf[n] = 0xff;
351 : }
352 : }
353 22174 : }
354 :
355 : /****************************************************************************/
356 :
357 723 : static uLong zip64local_TmzDateToDosDate(const tm_zip *ptm)
358 : {
359 723 : uLong year = static_cast<uLong>(ptm->tm_year);
360 723 : if (year > 1980)
361 0 : year -= 1980;
362 723 : else if (year > 80)
363 723 : year -= 80;
364 : return static_cast<uLong>(
365 723 : ((ptm->tm_mday) + (32 * (ptm->tm_mon + 1)) + (512 * year))
366 723 : << 16) |
367 723 : ((ptm->tm_sec / 2) + (32 * ptm->tm_min) +
368 723 : (2048 * static_cast<uLong>(ptm->tm_hour)));
369 : }
370 :
371 : /****************************************************************************/
372 :
373 4466 : static int zip64local_getByte(const zlib_filefunc_def *pzlib_filefunc_def,
374 : voidpf filestream, int *pi)
375 : {
376 4466 : unsigned char c = 0;
377 : const int err =
378 4466 : static_cast<int>(ZREAD64(*pzlib_filefunc_def, filestream, &c, 1));
379 4466 : if (err == 1)
380 : {
381 4444 : *pi = static_cast<int>(c);
382 4444 : return ZIP_OK;
383 : }
384 : else
385 : {
386 22 : if (ZERROR64(*pzlib_filefunc_def, filestream))
387 0 : return ZIP_ERRNO;
388 : else
389 22 : return ZIP_EOF;
390 : }
391 : }
392 :
393 : /* ===========================================================================
394 : Reads a long in LSB order from the given gz_stream. Sets
395 : */
396 1015 : static int zip64local_getShort(const zlib_filefunc_def *pzlib_filefunc_def,
397 : voidpf filestream, uLong *pX)
398 : {
399 1015 : int i = 0;
400 1015 : int err = zip64local_getByte(pzlib_filefunc_def, filestream, &i);
401 1015 : uLong x = static_cast<uLong>(i);
402 :
403 1015 : if (err == ZIP_OK)
404 1015 : err = zip64local_getByte(pzlib_filefunc_def, filestream, &i);
405 1015 : x += static_cast<uLong>(i) << 8;
406 :
407 1015 : if (err == ZIP_OK)
408 1015 : *pX = x;
409 : else
410 0 : *pX = 0;
411 1015 : return err;
412 : }
413 :
414 609 : static int zip64local_getLong(const zlib_filefunc_def *pzlib_filefunc_def,
415 : voidpf filestream, uLong *pX)
416 : {
417 609 : int i = 0;
418 609 : int err = zip64local_getByte(pzlib_filefunc_def, filestream, &i);
419 609 : uLong x = static_cast<uLong>(i);
420 :
421 609 : if (err == ZIP_OK)
422 609 : err = zip64local_getByte(pzlib_filefunc_def, filestream, &i);
423 609 : x += static_cast<uLong>(i) << 8;
424 :
425 609 : if (err == ZIP_OK)
426 609 : err = zip64local_getByte(pzlib_filefunc_def, filestream, &i);
427 609 : x += static_cast<uLong>(i) << 16;
428 :
429 609 : if (err == ZIP_OK)
430 609 : err = zip64local_getByte(pzlib_filefunc_def, filestream, &i);
431 609 : x += static_cast<uLong>(i) << 24;
432 :
433 609 : if (err == ZIP_OK)
434 609 : *pX = x;
435 : else
436 0 : *pX = 0;
437 609 : return err;
438 : }
439 :
440 0 : static int zip64local_getLong64(const zlib_filefunc_def *pzlib_filefunc_def,
441 : voidpf filestream, ZPOS64_T *pX)
442 : {
443 : ZPOS64_T x;
444 0 : int i = 0;
445 : int err;
446 :
447 0 : err = zip64local_getByte(pzlib_filefunc_def, filestream, &i);
448 0 : x = static_cast<ZPOS64_T>(i);
449 :
450 0 : if (err == ZIP_OK)
451 0 : err = zip64local_getByte(pzlib_filefunc_def, filestream, &i);
452 0 : x += static_cast<ZPOS64_T>(i) << 8;
453 :
454 0 : if (err == ZIP_OK)
455 0 : err = zip64local_getByte(pzlib_filefunc_def, filestream, &i);
456 0 : x += static_cast<ZPOS64_T>(i) << 16;
457 :
458 0 : if (err == ZIP_OK)
459 0 : err = zip64local_getByte(pzlib_filefunc_def, filestream, &i);
460 0 : x += static_cast<ZPOS64_T>(i) << 24;
461 :
462 0 : if (err == ZIP_OK)
463 0 : err = zip64local_getByte(pzlib_filefunc_def, filestream, &i);
464 0 : x += static_cast<ZPOS64_T>(i) << 32;
465 :
466 0 : if (err == ZIP_OK)
467 0 : err = zip64local_getByte(pzlib_filefunc_def, filestream, &i);
468 0 : x += static_cast<ZPOS64_T>(i) << 40;
469 :
470 0 : if (err == ZIP_OK)
471 0 : err = zip64local_getByte(pzlib_filefunc_def, filestream, &i);
472 0 : x += static_cast<ZPOS64_T>(i) << 48;
473 :
474 0 : if (err == ZIP_OK)
475 0 : err = zip64local_getByte(pzlib_filefunc_def, filestream, &i);
476 0 : x += static_cast<ZPOS64_T>(i) << 56;
477 :
478 0 : if (err == ZIP_OK)
479 0 : *pX = x;
480 : else
481 0 : *pX = 0;
482 :
483 0 : return err;
484 : }
485 :
486 : #ifndef BUFREADCOMMENT
487 : #define BUFREADCOMMENT (0x400)
488 : #endif
489 : /*
490 : Locate the Central directory of a zipfile (at the end, just before
491 : the global comment)
492 : */
493 : static ZPOS64_T
494 203 : zip64local_SearchCentralDir(const zlib_filefunc_def *pzlib_filefunc_def,
495 : voidpf filestream)
496 : {
497 203 : ZPOS64_T uMaxBack = 0xffff; /* maximum size of global comment */
498 203 : ZPOS64_T uPosFound = 0;
499 :
500 203 : if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) !=
501 : 0)
502 0 : return 0;
503 :
504 203 : ZPOS64_T uSizeFile = ZTELL64(*pzlib_filefunc_def, filestream);
505 :
506 203 : if (uMaxBack > uSizeFile)
507 203 : uMaxBack = uSizeFile;
508 :
509 : unsigned char *buf =
510 203 : static_cast<unsigned char *>(ALLOC(BUFREADCOMMENT + 4));
511 203 : if (buf == nullptr)
512 0 : return 0;
513 :
514 203 : ZPOS64_T uBackRead = 4;
515 203 : while (uBackRead < uMaxBack)
516 : {
517 202 : if (uBackRead + BUFREADCOMMENT > uMaxBack)
518 123 : uBackRead = uMaxBack;
519 : else
520 79 : uBackRead += BUFREADCOMMENT;
521 202 : ZPOS64_T uReadPos = uSizeFile - uBackRead;
522 :
523 202 : uLong uReadSize = ((BUFREADCOMMENT + 4) < (uSizeFile - uReadPos))
524 : ? (BUFREADCOMMENT + 4)
525 : : static_cast<uLong>(uSizeFile - uReadPos);
526 202 : if (ZSEEK64(*pzlib_filefunc_def, filestream, uReadPos,
527 202 : ZLIB_FILEFUNC_SEEK_SET) != 0)
528 0 : break;
529 :
530 202 : if (ZREAD64(*pzlib_filefunc_def, filestream, buf, uReadSize) !=
531 : uReadSize)
532 0 : break;
533 :
534 3838 : for (int i = static_cast<int>(uReadSize) - 3; (i--) > 0;)
535 3838 : if (((*(buf + i)) == 0x50) && ((*(buf + i + 1)) == 0x4b) &&
536 202 : ((*(buf + i + 2)) == 0x05) && ((*(buf + i + 3)) == 0x06))
537 : {
538 202 : uPosFound = uReadPos + i;
539 202 : break;
540 : }
541 :
542 202 : if (uPosFound != 0)
543 202 : break;
544 : }
545 203 : TRYFREE(buf);
546 203 : return uPosFound;
547 : }
548 :
549 : /*
550 : Locate the End of Zip64 Central directory locator and from there find the CD of
551 : a zipfile (at the end, just before the global comment)
552 : */
553 : static ZPOS64_T
554 203 : zip64local_SearchCentralDir64(const zlib_filefunc_def *pzlib_filefunc_def,
555 : voidpf filestream)
556 : {
557 : unsigned char *buf;
558 : ZPOS64_T uSizeFile;
559 : ZPOS64_T uBackRead;
560 203 : ZPOS64_T uMaxBack = 0xffff; /* maximum size of global comment */
561 203 : ZPOS64_T uPosFound = 0;
562 : uLong uL;
563 : ZPOS64_T relativeOffset;
564 :
565 203 : if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) !=
566 : 0)
567 0 : return 0;
568 :
569 203 : uSizeFile = ZTELL64(*pzlib_filefunc_def, filestream);
570 :
571 203 : if (uMaxBack > uSizeFile)
572 203 : uMaxBack = uSizeFile;
573 :
574 203 : buf = static_cast<unsigned char *>(ALLOC(BUFREADCOMMENT + 4));
575 203 : if (buf == nullptr)
576 0 : return 0;
577 :
578 203 : uBackRead = 4;
579 485 : while (uBackRead < uMaxBack)
580 : {
581 : uLong uReadSize;
582 : ZPOS64_T uReadPos;
583 : int i;
584 282 : if (uBackRead + BUFREADCOMMENT > uMaxBack)
585 202 : uBackRead = uMaxBack;
586 : else
587 80 : uBackRead += BUFREADCOMMENT;
588 282 : uReadPos = uSizeFile - uBackRead;
589 :
590 282 : uReadSize = ((BUFREADCOMMENT + 4) < (uSizeFile - uReadPos))
591 : ? (BUFREADCOMMENT + 4)
592 : : static_cast<uLong>(uSizeFile - uReadPos);
593 282 : if (ZSEEK64(*pzlib_filefunc_def, filestream, uReadPos,
594 282 : ZLIB_FILEFUNC_SEEK_SET) != 0)
595 0 : break;
596 :
597 282 : if (ZREAD64(*pzlib_filefunc_def, filestream, buf, uReadSize) !=
598 : uReadSize)
599 0 : break;
600 :
601 217409 : for (i = static_cast<int>(uReadSize) - 3; (i--) > 0;)
602 : {
603 : // Signature "0x07064b50" Zip64 end of central directory locater
604 217127 : if (((*(buf + i)) == 0x50) && ((*(buf + i + 1)) == 0x4b) &&
605 1763 : ((*(buf + i + 2)) == 0x06) && ((*(buf + i + 3)) == 0x07))
606 : {
607 0 : uPosFound = uReadPos + i;
608 0 : break;
609 : }
610 : }
611 :
612 282 : if (uPosFound != 0)
613 0 : break;
614 : }
615 :
616 203 : TRYFREE(buf);
617 203 : if (uPosFound == 0)
618 203 : return 0;
619 :
620 : /* Zip64 end of central directory locator */
621 0 : if (ZSEEK64(*pzlib_filefunc_def, filestream, uPosFound,
622 0 : ZLIB_FILEFUNC_SEEK_SET) != 0)
623 0 : return 0;
624 :
625 : /* the signature, already checked */
626 0 : if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK)
627 0 : return 0;
628 :
629 : /* number of the disk with the start of the zip64 end of central directory
630 : */
631 0 : if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK)
632 0 : return 0;
633 0 : if (uL != 0)
634 0 : return 0;
635 :
636 : /* relative offset of the zip64 end of central directory record */
637 0 : if (zip64local_getLong64(pzlib_filefunc_def, filestream, &relativeOffset) !=
638 : ZIP_OK)
639 0 : return 0;
640 :
641 : /* total number of disks */
642 0 : if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK)
643 0 : return 0;
644 : /* Some .zip declare 0 disks, such as in
645 : * http://trac.osgeo.org/gdal/ticket/5615 */
646 0 : if (uL != 0 && uL != 1)
647 0 : return 0;
648 :
649 : /* Goto Zip64 end of central directory record */
650 0 : if (ZSEEK64(*pzlib_filefunc_def, filestream, relativeOffset,
651 0 : ZLIB_FILEFUNC_SEEK_SET) != 0)
652 0 : return 0;
653 :
654 : /* the signature */
655 0 : if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK)
656 0 : return 0;
657 :
658 0 : if (uL != 0x06064b50) // signature of 'Zip64 end of central directory'
659 0 : return 0;
660 :
661 0 : return relativeOffset;
662 : }
663 :
664 203 : static int LoadCentralDirectoryRecord(zip64_internal *pziinit)
665 : {
666 203 : int err = ZIP_OK;
667 : ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/
668 :
669 : ZPOS64_T size_central_dir; /* size of the central directory */
670 : ZPOS64_T offset_central_dir; /* offset of start of central directory */
671 : ZPOS64_T central_pos;
672 : uLong uL;
673 :
674 : uLong number_disk; /* number of the current dist, used for
675 : spanning ZIP, unsupported, always 0*/
676 : uLong number_disk_with_CD; /* number the disk with central dir, used
677 : for spanning ZIP, unsupported, always 0*/
678 : ZPOS64_T number_entry;
679 : ZPOS64_T number_entry_CD; /* total number of entries in
680 : the central dir
681 : (same than number_entry on nospan) */
682 : uLong VersionMadeBy;
683 : uLong VersionNeeded;
684 : uLong size_comment;
685 :
686 203 : int hasZIP64Record = 0;
687 :
688 : // check first if we find a ZIP64 record
689 203 : central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,
690 : pziinit->filestream);
691 203 : if (central_pos > 0)
692 : {
693 0 : hasZIP64Record = 1;
694 : }
695 : else /* if (central_pos == 0) */
696 : {
697 203 : central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,
698 : pziinit->filestream);
699 : }
700 :
701 : /* disable to allow appending to empty ZIP archive
702 : if (central_pos==0)
703 : err=ZIP_ERRNO;
704 : */
705 :
706 203 : if (hasZIP64Record)
707 : {
708 : ZPOS64_T sizeEndOfCentralDirectory;
709 0 : if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,
710 0 : ZLIB_FILEFUNC_SEEK_SET) != 0)
711 0 : err = ZIP_ERRNO;
712 :
713 : /* the signature, already checked */
714 0 : if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,
715 0 : &uL) != ZIP_OK)
716 0 : err = ZIP_ERRNO;
717 :
718 : /* size of zip64 end of central directory record */
719 0 : if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,
720 0 : &sizeEndOfCentralDirectory) != ZIP_OK)
721 0 : err = ZIP_ERRNO;
722 :
723 : /* version made by */
724 0 : if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,
725 0 : &VersionMadeBy) != ZIP_OK)
726 0 : err = ZIP_ERRNO;
727 :
728 : /* version needed to extract */
729 0 : if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,
730 0 : &VersionNeeded) != ZIP_OK)
731 0 : err = ZIP_ERRNO;
732 :
733 : /* number of this disk */
734 0 : if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,
735 0 : &number_disk) != ZIP_OK)
736 0 : err = ZIP_ERRNO;
737 :
738 : /* number of the disk with the start of the central directory */
739 0 : if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,
740 0 : &number_disk_with_CD) != ZIP_OK)
741 0 : err = ZIP_ERRNO;
742 :
743 : /* total number of entries in the central directory on this disk */
744 0 : if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,
745 0 : &number_entry) != ZIP_OK)
746 0 : err = ZIP_ERRNO;
747 :
748 : /* total number of entries in the central directory */
749 0 : if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,
750 0 : &number_entry_CD) != ZIP_OK)
751 0 : err = ZIP_ERRNO;
752 :
753 0 : if ((number_entry_CD != number_entry) || (number_disk_with_CD != 0) ||
754 0 : (number_disk != 0))
755 0 : err = ZIP_BADZIPFILE;
756 :
757 : /* size of the central directory */
758 0 : if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,
759 0 : &size_central_dir) != ZIP_OK)
760 0 : err = ZIP_ERRNO;
761 :
762 : /* offset of start of central directory with respect to the
763 : starting disk number */
764 0 : if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,
765 0 : &offset_central_dir) != ZIP_OK)
766 0 : err = ZIP_ERRNO;
767 :
768 : // TODO..
769 : // read the comment from the standard central header.
770 0 : size_comment = 0;
771 : }
772 : else
773 : {
774 : // Read End of central Directory info
775 203 : if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,
776 203 : ZLIB_FILEFUNC_SEEK_SET) != 0)
777 0 : err = ZIP_ERRNO;
778 :
779 : /* the signature, already checked */
780 203 : if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,
781 203 : &uL) != ZIP_OK)
782 0 : err = ZIP_ERRNO;
783 :
784 : /* number of this disk */
785 203 : if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,
786 203 : &number_disk) != ZIP_OK)
787 0 : err = ZIP_ERRNO;
788 :
789 : /* number of the disk with the start of the central directory */
790 203 : if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,
791 203 : &number_disk_with_CD) != ZIP_OK)
792 0 : err = ZIP_ERRNO;
793 :
794 : /* total number of entries in the central dir on this disk */
795 203 : number_entry = 0;
796 203 : if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,
797 203 : &uL) != ZIP_OK)
798 0 : err = ZIP_ERRNO;
799 : else
800 203 : number_entry = uL;
801 :
802 : /* total number of entries in the central dir */
803 203 : number_entry_CD = 0;
804 203 : if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,
805 203 : &uL) != ZIP_OK)
806 0 : err = ZIP_ERRNO;
807 : else
808 203 : number_entry_CD = uL;
809 :
810 203 : if ((number_entry_CD != number_entry) || (number_disk_with_CD != 0) ||
811 203 : (number_disk != 0))
812 0 : err = ZIP_BADZIPFILE;
813 :
814 : /* size of the central directory */
815 203 : size_central_dir = 0;
816 203 : if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,
817 203 : &uL) != ZIP_OK)
818 0 : err = ZIP_ERRNO;
819 : else
820 203 : size_central_dir = uL;
821 :
822 : /* offset of start of central directory with respect to the starting
823 : * disk number */
824 203 : offset_central_dir = 0;
825 203 : if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,
826 203 : &uL) != ZIP_OK)
827 0 : err = ZIP_ERRNO;
828 : else
829 203 : offset_central_dir = uL;
830 :
831 : /* zipfile global comment length */
832 203 : if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,
833 203 : &size_comment) != ZIP_OK)
834 0 : err = ZIP_ERRNO;
835 : }
836 :
837 203 : if ((central_pos < offset_central_dir + size_central_dir) &&
838 : (err == ZIP_OK))
839 0 : err = ZIP_BADZIPFILE;
840 :
841 203 : if (err != ZIP_OK)
842 : {
843 0 : ZCLOSE64(pziinit->z_filefunc, pziinit->filestream);
844 0 : return ZIP_ERRNO;
845 : }
846 :
847 203 : if (size_comment > 0)
848 : {
849 0 : pziinit->globalcomment = static_cast<char *>(ALLOC(size_comment + 1));
850 0 : if (pziinit->globalcomment)
851 : {
852 0 : size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream,
853 : pziinit->globalcomment, size_comment);
854 0 : pziinit->globalcomment[size_comment] = 0;
855 : }
856 : }
857 :
858 203 : byte_before_the_zipfile =
859 203 : central_pos - (offset_central_dir + size_central_dir);
860 203 : pziinit->add_position_when_writing_offset = byte_before_the_zipfile;
861 :
862 : {
863 203 : ZPOS64_T size_central_dir_to_read = size_central_dir;
864 203 : size_t buf_size = SIZEDATA_INDATABLOCK;
865 203 : void *buf_read = ALLOC(buf_size);
866 203 : if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream,
867 : offset_central_dir + byte_before_the_zipfile,
868 203 : ZLIB_FILEFUNC_SEEK_SET) != 0)
869 0 : err = ZIP_ERRNO;
870 :
871 405 : while ((size_central_dir_to_read > 0) && (err == ZIP_OK))
872 : {
873 202 : ZPOS64_T read_this = SIZEDATA_INDATABLOCK;
874 202 : if (read_this > size_central_dir_to_read)
875 202 : read_this = size_central_dir_to_read;
876 :
877 202 : if (ZREAD64(pziinit->z_filefunc, pziinit->filestream, buf_read,
878 202 : static_cast<uLong>(read_this)) != read_this)
879 0 : err = ZIP_ERRNO;
880 :
881 202 : if (err == ZIP_OK)
882 202 : err = add_data_in_datablock(&pziinit->central_dir, buf_read,
883 : static_cast<uLong>(read_this));
884 :
885 202 : size_central_dir_to_read -= read_this;
886 : }
887 203 : TRYFREE(buf_read);
888 : }
889 203 : pziinit->begin_pos = byte_before_the_zipfile;
890 203 : pziinit->number_entry = number_entry_CD;
891 :
892 203 : if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream,
893 : offset_central_dir + byte_before_the_zipfile,
894 203 : ZLIB_FILEFUNC_SEEK_SET) != 0)
895 0 : err = ZIP_ERRNO;
896 :
897 203 : return err;
898 : }
899 :
900 : #endif /* !NO_ADDFILEINEXISTINGZIP*/
901 :
902 : /************************************************************/
903 448 : extern zipFile ZEXPORT cpl_zipOpen2(const char *pathname, int append,
904 : zipcharpc *globalcomment,
905 : zlib_filefunc_def *pzlib_filefunc_def)
906 : {
907 : zip64_internal ziinit;
908 448 : memset(&ziinit, 0, sizeof(ziinit));
909 :
910 448 : if (pzlib_filefunc_def == nullptr)
911 448 : cpl_fill_fopen_filefunc(&ziinit.z_filefunc);
912 : else
913 0 : ziinit.z_filefunc = *pzlib_filefunc_def;
914 :
915 448 : ziinit.filestream = (*(ziinit.z_filefunc.zopen_file))(
916 : ziinit.z_filefunc.opaque, pathname,
917 : (append == APPEND_STATUS_CREATE)
918 : ? (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE |
919 : ZLIB_FILEFUNC_MODE_CREATE)
920 : : (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE |
921 : ZLIB_FILEFUNC_MODE_EXISTING));
922 :
923 448 : if (ziinit.filestream == nullptr)
924 4 : return nullptr;
925 :
926 444 : if (append == APPEND_STATUS_CREATEAFTER)
927 0 : ZSEEK64(ziinit.z_filefunc, ziinit.filestream, 0, SEEK_END);
928 :
929 444 : ziinit.begin_pos = ZTELL64(ziinit.z_filefunc, ziinit.filestream);
930 444 : ziinit.in_opened_file_inzip = 0;
931 444 : ziinit.ci.stream_initialised = 0;
932 444 : ziinit.number_entry = 0;
933 444 : ziinit.add_position_when_writing_offset = 0;
934 444 : ziinit.use_cpl_io = (pzlib_filefunc_def == nullptr) ? 1 : 0;
935 444 : ziinit.vsi_raw_length_before = 0;
936 444 : ziinit.vsi_deflate_handle = nullptr;
937 444 : ziinit.nChunkSize = 0;
938 444 : ziinit.nThreads = 0;
939 444 : ziinit.nOffsetSize = 0;
940 444 : ziinit.sozip_index = nullptr;
941 444 : init_linkedlist(&(ziinit.central_dir));
942 :
943 : zip64_internal *zi =
944 444 : static_cast<zip64_internal *>(ALLOC(sizeof(zip64_internal)));
945 444 : if (zi == nullptr)
946 : {
947 0 : ZCLOSE64(ziinit.z_filefunc, ziinit.filestream);
948 0 : return nullptr;
949 : }
950 :
951 : /* now we add file in a zipfile */
952 : #ifndef NO_ADDFILEINEXISTINGZIP
953 444 : ziinit.globalcomment = nullptr;
954 :
955 444 : int err = ZIP_OK;
956 444 : if (append == APPEND_STATUS_ADDINZIP)
957 : {
958 : // Read and Cache Central Directory Records
959 203 : err = LoadCentralDirectoryRecord(&ziinit);
960 : }
961 :
962 444 : if (globalcomment)
963 : {
964 0 : *globalcomment = ziinit.globalcomment;
965 : }
966 : #endif /* !NO_ADDFILEINEXISTINGZIP*/
967 :
968 444 : if (err != ZIP_OK)
969 : {
970 : #ifndef NO_ADDFILEINEXISTINGZIP
971 0 : TRYFREE(ziinit.globalcomment);
972 : #endif /* !NO_ADDFILEINEXISTINGZIP*/
973 0 : TRYFREE(zi);
974 0 : return nullptr;
975 : }
976 : else
977 : {
978 444 : *zi = ziinit;
979 444 : return static_cast<zipFile>(zi);
980 : }
981 : }
982 :
983 448 : extern zipFile ZEXPORT cpl_zipOpen(const char *pathname, int append)
984 : {
985 448 : return cpl_zipOpen2(pathname, append, nullptr, nullptr);
986 : }
987 :
988 8326 : static void zip64local_putValue_inmemory_update(char **dest, ZPOS64_T x,
989 : int nbByte)
990 : {
991 8326 : zip64local_putValue_inmemory(*dest, x, nbByte);
992 8326 : *dest += nbByte;
993 8326 : }
994 :
995 723 : static int Write_LocalFileHeader(zip64_internal *zi, const char *filename,
996 : uInt size_extrafield_local,
997 : const void *extrafield_local, int zip64)
998 : {
999 : /* write the local header */
1000 723 : int err = ZIP_OK;
1001 723 : uInt size_filename = static_cast<uInt>(strlen(filename));
1002 723 : uInt size_extrafield = size_extrafield_local;
1003 :
1004 723 : if (zip64)
1005 : {
1006 274 : size_extrafield += 20;
1007 : }
1008 :
1009 723 : uInt size_local_header = 30 + size_filename + size_extrafield;
1010 723 : char *local_header = static_cast<char *>(ALLOC(size_local_header));
1011 723 : char *p = local_header;
1012 :
1013 723 : zip64local_putValue_inmemory_update(&p, LOCALHEADERMAGIC, 4);
1014 723 : if (zip64)
1015 274 : zip64local_putValue_inmemory_update(&p, 45,
1016 : 2); /* version needed to extract */
1017 : else
1018 449 : zip64local_putValue_inmemory_update(&p, 20,
1019 : 2); /* version needed to extract */
1020 :
1021 723 : zip64local_putValue_inmemory_update(&p, zi->ci.flag, 2);
1022 :
1023 723 : zip64local_putValue_inmemory_update(&p, zi->ci.method, 2);
1024 :
1025 723 : zip64local_putValue_inmemory_update(&p, zi->ci.dosDate, 4);
1026 :
1027 : // CRC / Compressed size / Uncompressed size will be filled in later and
1028 : // rewritten later
1029 723 : zip64local_putValue_inmemory_update(&p, 0, 4); /* crc 32, unknown */
1030 :
1031 723 : if (zip64)
1032 274 : zip64local_putValue_inmemory_update(&p, 0xFFFFFFFFU,
1033 : 4); /* compressed size, unknown */
1034 : else
1035 449 : zip64local_putValue_inmemory_update(&p, 0,
1036 : 4); /* compressed size, unknown */
1037 :
1038 723 : if (zip64)
1039 274 : zip64local_putValue_inmemory_update(&p, 0xFFFFFFFFU,
1040 : 4); /* uncompressed size, unknown */
1041 : else
1042 449 : zip64local_putValue_inmemory_update(&p, 0,
1043 : 4); /* uncompressed size, unknown */
1044 :
1045 723 : zip64local_putValue_inmemory_update(&p, size_filename, 2);
1046 :
1047 723 : zi->ci.size_local_header_extrafield = size_extrafield;
1048 :
1049 723 : zip64local_putValue_inmemory_update(&p, size_extrafield, 2);
1050 :
1051 723 : if (size_filename > 0)
1052 : {
1053 722 : memcpy(p, filename, size_filename);
1054 722 : p += size_filename;
1055 : }
1056 :
1057 723 : if (size_extrafield_local > 0)
1058 : {
1059 2 : memcpy(p, extrafield_local, size_extrafield_local);
1060 2 : p += size_extrafield_local;
1061 : }
1062 :
1063 723 : if (zip64)
1064 : {
1065 : // write the Zip64 extended info
1066 274 : short HeaderID = 1;
1067 274 : short DataSize = 16;
1068 274 : ZPOS64_T CompressedSize = 0;
1069 274 : ZPOS64_T UncompressedSize = 0;
1070 :
1071 : // Remember position of Zip64 extended info for the local file header.
1072 : // (needed when we update size after done with file)
1073 274 : zi->ci.pos_zip64extrainfo =
1074 274 : ZTELL64(zi->z_filefunc, zi->filestream) + p - local_header;
1075 :
1076 274 : zip64local_putValue_inmemory_update(&p, HeaderID, 2);
1077 274 : zip64local_putValue_inmemory_update(&p, DataSize, 2);
1078 :
1079 274 : zip64local_putValue_inmemory_update(&p, UncompressedSize, 8);
1080 274 : zip64local_putValue_inmemory_update(&p, CompressedSize, 8);
1081 : }
1082 723 : assert(p == local_header + size_local_header);
1083 :
1084 723 : if (ZWRITE64(zi->z_filefunc, zi->filestream, local_header,
1085 723 : size_local_header) != size_local_header)
1086 57 : err = ZIP_ERRNO;
1087 :
1088 723 : zi->ci.local_header = local_header;
1089 723 : zi->ci.size_local_header = size_local_header;
1090 :
1091 723 : return err;
1092 : }
1093 :
1094 723 : extern int ZEXPORT cpl_zipOpenNewFileInZip3(
1095 : zipFile file, const char *filename, const zip_fileinfo *zipfi,
1096 : const void *extrafield_local, uInt size_extrafield_local,
1097 : const void *extrafield_global, uInt size_extrafield_global,
1098 : const char *comment, int method, int level, int raw, int windowBits,
1099 : int memLevel, int strategy, const char *password,
1100 : #ifdef NOCRYPT
1101 : uLong /* crcForCrypting */
1102 : #else
1103 : uLong crcForCrypting
1104 : #endif
1105 : ,
1106 : bool bZip64, bool bIncludeInCentralDirectory)
1107 : {
1108 : zip64_internal *zi;
1109 : uInt size_filename;
1110 : uInt size_comment;
1111 : uInt i;
1112 723 : int err = ZIP_OK;
1113 723 : uLong flagBase = 0;
1114 :
1115 : #ifdef NOCRYPT
1116 723 : if (password != nullptr)
1117 0 : return ZIP_PARAMERROR;
1118 : #endif
1119 :
1120 723 : if (file == nullptr)
1121 0 : return ZIP_PARAMERROR;
1122 723 : if ((method != 0) && (method != Z_DEFLATED))
1123 0 : return ZIP_PARAMERROR;
1124 :
1125 723 : zi = reinterpret_cast<zip64_internal *>(file);
1126 :
1127 723 : if (zi->in_opened_file_inzip == 1)
1128 : {
1129 6 : err = cpl_zipCloseFileInZip(file);
1130 6 : if (err != ZIP_OK)
1131 0 : return err;
1132 : }
1133 :
1134 723 : if (filename == nullptr)
1135 0 : filename = "-";
1136 :
1137 : // The filename and comment length must fit in 16 bits.
1138 723 : if ((filename != nullptr) && (strlen(filename) > 0xffff))
1139 0 : return ZIP_PARAMERROR;
1140 723 : if ((comment != nullptr) && (strlen(comment) > 0xffff))
1141 0 : return ZIP_PARAMERROR;
1142 : // The extra field length must fit in 16 bits. If the member also requires
1143 : // a Zip64 extra block, that will also need to fit within that 16-bit
1144 : // length, but that will be checked for later.
1145 723 : if ((size_extrafield_local > 0xffff) || (size_extrafield_global > 0xffff))
1146 0 : return ZIP_PARAMERROR;
1147 :
1148 723 : if (comment == nullptr)
1149 0 : size_comment = 0;
1150 : else
1151 723 : size_comment = static_cast<uInt>(strlen(comment));
1152 :
1153 723 : size_filename = static_cast<uInt>(strlen(filename));
1154 :
1155 723 : if (zipfi == nullptr)
1156 0 : zi->ci.dosDate = 0;
1157 : else
1158 : {
1159 723 : if (zipfi->dosDate != 0)
1160 0 : zi->ci.dosDate = zipfi->dosDate;
1161 : else
1162 723 : zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date);
1163 : }
1164 :
1165 723 : zi->ci.flag = flagBase;
1166 723 : if ((level == 8) || (level == 9))
1167 0 : zi->ci.flag |= 2;
1168 723 : if (level == 2)
1169 0 : zi->ci.flag |= 4;
1170 723 : if (level == 1)
1171 0 : zi->ci.flag |= 6;
1172 : #ifndef NOCRYPT
1173 : if (password != nullptr)
1174 : zi->ci.flag |= 1;
1175 : #endif
1176 :
1177 723 : zi->ci.crc32 = 0;
1178 723 : zi->ci.method = method;
1179 723 : zi->ci.encrypt = 0;
1180 723 : zi->ci.stream_initialised = 0;
1181 723 : zi->ci.pos_in_buffered_data = 0;
1182 723 : zi->ci.raw = raw;
1183 723 : zi->ci.pos_local_header = ZTELL64(zi->z_filefunc, zi->filestream);
1184 :
1185 723 : if (bIncludeInCentralDirectory)
1186 : {
1187 715 : zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename +
1188 715 : size_extrafield_global + size_comment;
1189 715 : zi->ci.size_centralExtraFree =
1190 : 32; // Extra space we have reserved in case we need to add ZIP64
1191 : // extra info data
1192 :
1193 715 : zi->ci.central_header = static_cast<char *>(ALLOC(static_cast<uInt>(
1194 : zi->ci.size_centralheader + zi->ci.size_centralExtraFree)));
1195 :
1196 715 : zi->ci.size_centralExtra = size_extrafield_global;
1197 715 : zip64local_putValue_inmemory(zi->ci.central_header, CENTRALHEADERMAGIC,
1198 : 4);
1199 : /* version info */
1200 715 : zip64local_putValue_inmemory(zi->ci.central_header + 4, VERSIONMADEBY,
1201 : 2);
1202 715 : zip64local_putValue_inmemory(zi->ci.central_header + 6, 20, 2);
1203 715 : zip64local_putValue_inmemory(zi->ci.central_header + 8,
1204 715 : static_cast<uLong>(zi->ci.flag), 2);
1205 715 : zip64local_putValue_inmemory(zi->ci.central_header + 10,
1206 715 : static_cast<uLong>(zi->ci.method), 2);
1207 715 : zip64local_putValue_inmemory(zi->ci.central_header + 12,
1208 715 : static_cast<uLong>(zi->ci.dosDate), 4);
1209 715 : zip64local_putValue_inmemory(zi->ci.central_header + 16, 0, 4); /*crc*/
1210 715 : zip64local_putValue_inmemory(zi->ci.central_header + 20, 0,
1211 : 4); /*compr size*/
1212 715 : zip64local_putValue_inmemory(zi->ci.central_header + 24, 0,
1213 : 4); /*uncompr size*/
1214 715 : zip64local_putValue_inmemory(zi->ci.central_header + 28,
1215 : static_cast<uLong>(size_filename), 2);
1216 715 : zip64local_putValue_inmemory(zi->ci.central_header + 30,
1217 : static_cast<uLong>(size_extrafield_global),
1218 : 2);
1219 715 : zip64local_putValue_inmemory(zi->ci.central_header + 32,
1220 : static_cast<uLong>(size_comment), 2);
1221 715 : zip64local_putValue_inmemory(zi->ci.central_header + 34, 0,
1222 : 2); /*disk nm start*/
1223 :
1224 715 : if (zipfi == nullptr)
1225 0 : zip64local_putValue_inmemory(zi->ci.central_header + 36, 0, 2);
1226 : else
1227 715 : zip64local_putValue_inmemory(zi->ci.central_header + 36,
1228 715 : static_cast<uLong>(zipfi->internal_fa),
1229 : 2);
1230 :
1231 715 : if (zipfi == nullptr)
1232 0 : zip64local_putValue_inmemory(zi->ci.central_header + 38, 0, 4);
1233 : else
1234 715 : zip64local_putValue_inmemory(zi->ci.central_header + 38,
1235 715 : static_cast<uLong>(zipfi->external_fa),
1236 : 4);
1237 :
1238 715 : if (zi->ci.pos_local_header >= 0xffffffff)
1239 0 : zip64local_putValue_inmemory(zi->ci.central_header + 42,
1240 : static_cast<uLong>(0xffffffff), 4);
1241 : else
1242 715 : zip64local_putValue_inmemory(
1243 715 : zi->ci.central_header + 42,
1244 715 : static_cast<uLong>(zi->ci.pos_local_header) -
1245 715 : zi->add_position_when_writing_offset,
1246 : 4);
1247 :
1248 12380 : for (i = 0; i < size_filename; i++)
1249 11665 : *(zi->ci.central_header + SIZECENTRALHEADER + i) = *(filename + i);
1250 :
1251 780 : for (i = 0; i < size_extrafield_global; i++)
1252 65 : *(zi->ci.central_header + SIZECENTRALHEADER + size_filename + i) =
1253 65 : *((reinterpret_cast<const char *>(extrafield_global)) + i);
1254 :
1255 715 : for (i = 0; i < size_comment; i++)
1256 0 : *(zi->ci.central_header + SIZECENTRALHEADER + size_filename +
1257 0 : size_extrafield_global + i) = *(comment + i);
1258 715 : if (zi->ci.central_header == nullptr)
1259 0 : return ZIP_INTERNALERROR;
1260 : }
1261 : else
1262 : {
1263 8 : zi->ci.central_header = nullptr;
1264 : }
1265 :
1266 723 : zi->ci.totalCompressedData = 0;
1267 723 : zi->ci.totalUncompressedData = 0;
1268 723 : zi->ci.pos_zip64extrainfo = 0;
1269 :
1270 : // For now default is to generate zip64 extra fields
1271 723 : err = Write_LocalFileHeader(zi, filename, size_extrafield_local,
1272 : extrafield_local, bZip64 ? 1 : 0);
1273 :
1274 723 : zi->ci.stream.avail_in = 0;
1275 723 : zi->ci.stream.avail_out = Z_BUFSIZE;
1276 723 : zi->ci.stream.next_out = zi->ci.buffered_data;
1277 723 : zi->ci.stream.total_in = 0;
1278 723 : zi->ci.stream.total_out = 0;
1279 723 : zi->ci.stream.data_type = Z_UNKNOWN;
1280 :
1281 723 : if ((err == ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
1282 : {
1283 619 : zi->ci.stream.zalloc = nullptr;
1284 619 : zi->ci.stream.zfree = nullptr;
1285 619 : zi->ci.stream.opaque = nullptr;
1286 :
1287 619 : if (windowBits > 0)
1288 0 : windowBits = -windowBits;
1289 :
1290 619 : if (zi->use_cpl_io)
1291 : {
1292 619 : auto fpRaw = reinterpret_cast<VSIVirtualHandle *>(zi->filestream);
1293 619 : zi->vsi_raw_length_before = fpRaw->Tell();
1294 619 : zi->vsi_deflate_handle = VSICreateGZipWritable(
1295 : fpRaw, CPL_DEFLATE_TYPE_RAW_DEFLATE, false, zi->nThreads,
1296 : zi->nChunkSize, zi->nOffsetSize, zi->sozip_index);
1297 619 : err = Z_OK;
1298 : }
1299 : else
1300 : {
1301 0 : err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits,
1302 : memLevel, strategy);
1303 : }
1304 :
1305 619 : if (err == Z_OK)
1306 619 : zi->ci.stream_initialised = 1;
1307 : }
1308 : #ifndef NOCRYPT
1309 : zi->ci.crypt_header_size = 0;
1310 : if ((err == Z_OK) && (password != nullptr))
1311 : {
1312 : unsigned char bufHead[RAND_HEAD_LEN];
1313 : unsigned int sizeHead = 0;
1314 : zi->ci.encrypt = 1;
1315 : zi->ci.pcrc_32_tab = get_crc_table();
1316 : /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/
1317 :
1318 : sizeHead = crypthead(password, bufHead, RAND_HEAD_LEN, zi->ci.keys,
1319 : zi->ci.pcrc_32_tab, crcForCrypting);
1320 : zi->ci.crypt_header_size = sizeHead;
1321 :
1322 : if (ZWRITE64(zi->z_filefunc, zi->filestream, bufHead, sizeHead) !=
1323 : sizeHead)
1324 : err = ZIP_ERRNO;
1325 : }
1326 : #endif
1327 :
1328 723 : if (err == Z_OK)
1329 666 : zi->in_opened_file_inzip = 1;
1330 : else
1331 : {
1332 57 : free(zi->ci.central_header);
1333 57 : zi->ci.central_header = nullptr;
1334 57 : free(zi->ci.local_header);
1335 57 : zi->ci.local_header = nullptr;
1336 : }
1337 :
1338 723 : return err;
1339 : }
1340 :
1341 0 : extern int ZEXPORT cpl_zipOpenNewFileInZip2(
1342 : zipFile file, const char *filename, const zip_fileinfo *zipfi,
1343 : const void *extrafield_local, uInt size_extrafield_local,
1344 : const void *extrafield_global, uInt size_extrafield_global,
1345 : const char *comment, int method, int level, int raw)
1346 : {
1347 0 : return cpl_zipOpenNewFileInZip3(
1348 : file, filename, zipfi, extrafield_local, size_extrafield_local,
1349 : extrafield_global, size_extrafield_global, comment, method, level, raw,
1350 0 : -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, nullptr, 0, true, true);
1351 : }
1352 :
1353 0 : extern int ZEXPORT cpl_zipOpenNewFileInZip(
1354 : zipFile file, const char *filename, const zip_fileinfo *zipfi,
1355 : const void *extrafield_local, uInt size_extrafield_local,
1356 : const void *extrafield_global, uInt size_extrafield_global,
1357 : const char *comment, int method, int level)
1358 : {
1359 0 : return cpl_zipOpenNewFileInZip2(
1360 : file, filename, zipfi, extrafield_local, size_extrafield_local,
1361 0 : extrafield_global, size_extrafield_global, comment, method, level, 0);
1362 : }
1363 :
1364 47 : static int zip64FlushWriteBuffer(zip64_internal *zi)
1365 : {
1366 47 : int err = ZIP_OK;
1367 :
1368 47 : if (zi->ci.encrypt != 0)
1369 : {
1370 : #ifndef NOCRYPT
1371 : int t = 0;
1372 : for (uInt i = 0; i < zi->ci.pos_in_buffered_data; i++)
1373 : zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab,
1374 : zi->ci.buffered_data[i], t);
1375 : #endif
1376 : }
1377 47 : if (ZWRITE64(zi->z_filefunc, zi->filestream, zi->ci.buffered_data,
1378 47 : zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data)
1379 0 : err = ZIP_ERRNO;
1380 :
1381 47 : zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data;
1382 47 : zi->ci.totalUncompressedData += zi->ci.stream.total_in;
1383 47 : zi->ci.stream.total_in = 0;
1384 :
1385 47 : zi->ci.pos_in_buffered_data = 0;
1386 47 : return err;
1387 : }
1388 :
1389 211057 : extern int ZEXPORT cpl_zipWriteInFileInZip(zipFile file, const void *buf,
1390 : unsigned len)
1391 : {
1392 211057 : if (file == nullptr)
1393 0 : return ZIP_PARAMERROR;
1394 :
1395 211057 : zip64_internal *zi = reinterpret_cast<zip64_internal *>(file);
1396 :
1397 211057 : if (zi->in_opened_file_inzip == 0)
1398 0 : return ZIP_PARAMERROR;
1399 :
1400 211057 : zi->ci.stream.next_in = reinterpret_cast<Bytef *>(const_cast<void *>(buf));
1401 211057 : zi->ci.stream.avail_in = len;
1402 211057 : zi->ci.crc32 =
1403 211057 : crc32(zi->ci.crc32, reinterpret_cast<const Bytef *>(buf), len);
1404 :
1405 211057 : int err = ZIP_OK;
1406 422114 : while ((err == ZIP_OK) && (zi->ci.stream.avail_in > 0))
1407 : {
1408 211057 : if (zi->ci.stream.avail_out == 0)
1409 : {
1410 0 : if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
1411 0 : err = ZIP_ERRNO;
1412 0 : zi->ci.stream.avail_out = Z_BUFSIZE;
1413 0 : zi->ci.stream.next_out = zi->ci.buffered_data;
1414 : }
1415 :
1416 211057 : if (err != ZIP_OK)
1417 0 : break;
1418 :
1419 211057 : if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
1420 : {
1421 211010 : if (zi->vsi_deflate_handle)
1422 : {
1423 211010 : zi->ci.totalUncompressedData += len;
1424 211010 : if (zi->vsi_deflate_handle->Write(buf, 1, len) < len)
1425 34464 : err = ZIP_INTERNALERROR;
1426 211010 : zi->ci.stream.avail_in = 0;
1427 : }
1428 : else
1429 : {
1430 0 : uLong uTotalOutBefore = zi->ci.stream.total_out;
1431 0 : err = deflate(&zi->ci.stream, Z_NO_FLUSH);
1432 0 : zi->ci.pos_in_buffered_data += static_cast<uInt>(
1433 0 : zi->ci.stream.total_out - uTotalOutBefore);
1434 211010 : }
1435 : }
1436 : else
1437 : {
1438 : uInt copy_this;
1439 47 : if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
1440 47 : copy_this = zi->ci.stream.avail_in;
1441 : else
1442 0 : copy_this = zi->ci.stream.avail_out;
1443 10417 : for (uInt i = 0; i < copy_this; i++)
1444 10370 : *((reinterpret_cast<char *>(zi->ci.stream.next_out)) + i) =
1445 10370 : *((reinterpret_cast<const char *>(zi->ci.stream.next_in)) +
1446 10370 : i);
1447 : {
1448 47 : zi->ci.stream.avail_in -= copy_this;
1449 47 : zi->ci.stream.avail_out -= copy_this;
1450 47 : zi->ci.stream.next_in += copy_this;
1451 47 : zi->ci.stream.next_out += copy_this;
1452 47 : zi->ci.stream.total_in += copy_this;
1453 47 : zi->ci.stream.total_out += copy_this;
1454 47 : zi->ci.pos_in_buffered_data += copy_this;
1455 : }
1456 : }
1457 : }
1458 :
1459 211057 : return err;
1460 : }
1461 :
1462 666 : extern int ZEXPORT cpl_zipCloseFileInZipRaw(zipFile file,
1463 : ZPOS64_T uncompressed_size,
1464 : uLong crc32)
1465 : {
1466 666 : if (file == nullptr)
1467 0 : return ZIP_PARAMERROR;
1468 :
1469 666 : zip64_internal *zi = reinterpret_cast<zip64_internal *>(file);
1470 :
1471 666 : if (zi->in_opened_file_inzip == 0)
1472 0 : return ZIP_PARAMERROR;
1473 666 : zi->ci.stream.avail_in = 0;
1474 :
1475 666 : int err = ZIP_OK;
1476 666 : if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
1477 : {
1478 619 : if (zi->vsi_deflate_handle)
1479 : {
1480 619 : auto fpRaw = reinterpret_cast<VSIVirtualHandle *>(zi->filestream);
1481 619 : delete zi->vsi_deflate_handle;
1482 619 : zi->vsi_deflate_handle = nullptr;
1483 619 : zi->ci.totalCompressedData =
1484 619 : fpRaw->Tell() - zi->vsi_raw_length_before;
1485 :
1486 619 : if (zi->sozip_index)
1487 : {
1488 9 : uint64_t nVal =
1489 9 : static_cast<uint64_t>(zi->ci.totalCompressedData);
1490 9 : CPL_LSBPTR64(&nVal);
1491 9 : memcpy(zi->sozip_index->data() + 24, &nVal, sizeof(uint64_t));
1492 : }
1493 : }
1494 : else
1495 : {
1496 0 : while (err == ZIP_OK)
1497 : {
1498 0 : if (zi->ci.stream.avail_out == 0)
1499 : {
1500 0 : if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
1501 : {
1502 0 : err = ZIP_ERRNO;
1503 0 : break;
1504 : }
1505 0 : zi->ci.stream.avail_out = Z_BUFSIZE;
1506 0 : zi->ci.stream.next_out = zi->ci.buffered_data;
1507 : }
1508 0 : uLong uTotalOutBefore = zi->ci.stream.total_out;
1509 0 : err = deflate(&zi->ci.stream, Z_FINISH);
1510 0 : zi->ci.pos_in_buffered_data += static_cast<uInt>(
1511 0 : zi->ci.stream.total_out - uTotalOutBefore);
1512 : }
1513 : }
1514 : }
1515 :
1516 666 : if (err == Z_STREAM_END)
1517 0 : err = ZIP_OK; /* this is normal */
1518 :
1519 666 : if ((zi->ci.pos_in_buffered_data > 0) && (err == ZIP_OK))
1520 47 : if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
1521 0 : err = ZIP_ERRNO;
1522 :
1523 666 : if (!zi->use_cpl_io && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
1524 : {
1525 0 : err = deflateEnd(&zi->ci.stream);
1526 0 : zi->ci.stream_initialised = 0;
1527 : }
1528 :
1529 666 : if (!zi->ci.raw)
1530 : {
1531 666 : crc32 = static_cast<uLong>(zi->ci.crc32);
1532 666 : uncompressed_size = zi->ci.totalUncompressedData;
1533 : }
1534 666 : ZPOS64_T compressed_size = zi->ci.totalCompressedData;
1535 : #ifndef NOCRYPT
1536 : compressed_size += zi->ci.crypt_header_size;
1537 : #endif
1538 :
1539 : #ifdef disabled
1540 : // Code finally disabled since it causes compatibility issues with
1541 : // libreoffice for .xlsx or .ods files
1542 : if (zi->ci.pos_zip64extrainfo && uncompressed_size < 0xffffffff &&
1543 : compressed_size < 0xffffffff)
1544 : {
1545 : // Update the LocalFileHeader to be a regular one and not a ZIP64 one
1546 : // by removing its trailing 20 bytes, and moving it in the file
1547 : // 20 bytes further of its original position.
1548 :
1549 : ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream);
1550 :
1551 : if (ZSEEK64(zi->z_filefunc, zi->filestream, zi->ci.pos_local_header,
1552 : ZLIB_FILEFUNC_SEEK_SET) != 0)
1553 : err = ZIP_ERRNO;
1554 :
1555 : // Insert leading padding
1556 : constexpr uInt nZIP64ExtraBytes = 20;
1557 : char padding[nZIP64ExtraBytes];
1558 : memset(padding, 0, sizeof(padding));
1559 : if (ZWRITE64(zi->z_filefunc, zi->filestream, padding,
1560 : nZIP64ExtraBytes) != nZIP64ExtraBytes)
1561 : err = ZIP_ERRNO;
1562 :
1563 : // Correct version needed to extract
1564 : zip64local_putValue_inmemory(zi->ci.local_header + 4, 20, 2);
1565 :
1566 : // Correct extra field length
1567 : zi->ci.size_local_header_extrafield -= nZIP64ExtraBytes;
1568 : zip64local_putValue_inmemory(zi->ci.local_header + 28,
1569 : zi->ci.size_local_header_extrafield, 2);
1570 :
1571 : zi->ci.size_local_header -= nZIP64ExtraBytes;
1572 :
1573 : // Rewrite local header
1574 : if (ZWRITE64(zi->z_filefunc, zi->filestream, zi->ci.local_header,
1575 : zi->ci.size_local_header) != zi->ci.size_local_header)
1576 : err = ZIP_ERRNO;
1577 :
1578 : if (ZSEEK64(zi->z_filefunc, zi->filestream, cur_pos_inzip,
1579 : ZLIB_FILEFUNC_SEEK_SET) != 0)
1580 : err = ZIP_ERRNO;
1581 :
1582 : zi->ci.pos_zip64extrainfo = 0;
1583 :
1584 : // Correct central header offset to local header
1585 : zi->ci.pos_local_header += nZIP64ExtraBytes;
1586 : if (zi->ci.central_header)
1587 : {
1588 : if (zi->ci.pos_local_header >= 0xffffffff)
1589 : zip64local_putValue_inmemory(zi->ci.central_header + 42,
1590 : static_cast<uLong>(0xffffffff), 4);
1591 : else
1592 : zip64local_putValue_inmemory(
1593 : zi->ci.central_header + 42,
1594 : static_cast<uLong>(zi->ci.pos_local_header) -
1595 : zi->add_position_when_writing_offset,
1596 : 4);
1597 : }
1598 : }
1599 : #endif
1600 :
1601 666 : const bool bInCentralHeader = zi->ci.central_header != nullptr;
1602 666 : if (zi->ci.central_header)
1603 : {
1604 : // update Current Item crc and sizes,
1605 658 : if (zi->ci.pos_zip64extrainfo || compressed_size >= 0xffffffff ||
1606 441 : uncompressed_size >= 0xffffffff ||
1607 441 : zi->ci.pos_local_header >= 0xffffffff)
1608 : {
1609 : /*version Made by*/
1610 217 : zip64local_putValue_inmemory(zi->ci.central_header + 4, 45, 2);
1611 : /*version needed*/
1612 217 : zip64local_putValue_inmemory(zi->ci.central_header + 6, 45, 2);
1613 : }
1614 :
1615 658 : zip64local_putValue_inmemory(zi->ci.central_header + 16, crc32,
1616 : 4); /*crc*/
1617 :
1618 658 : const uLong invalidValue = 0xffffffff;
1619 658 : if (compressed_size >= 0xffffffff)
1620 0 : zip64local_putValue_inmemory(zi->ci.central_header + 20,
1621 : invalidValue, 4); /*compr size*/
1622 : else
1623 658 : zip64local_putValue_inmemory(zi->ci.central_header + 20,
1624 : compressed_size, 4); /*compr size*/
1625 :
1626 : /// set internal file attributes field
1627 658 : if (zi->ci.stream.data_type == Z_ASCII)
1628 0 : zip64local_putValue_inmemory(zi->ci.central_header + 36, Z_ASCII,
1629 : 2);
1630 :
1631 658 : if (uncompressed_size >= 0xffffffff)
1632 0 : zip64local_putValue_inmemory(zi->ci.central_header + 24,
1633 : invalidValue, 4); /*uncompr size*/
1634 : else
1635 658 : zip64local_putValue_inmemory(zi->ci.central_header + 24,
1636 : uncompressed_size, 4); /*uncompr size*/
1637 :
1638 658 : short datasize = 0;
1639 : // Add ZIP64 extra info field for uncompressed size
1640 658 : if (uncompressed_size >= 0xffffffff)
1641 0 : datasize += 8;
1642 :
1643 : // Add ZIP64 extra info field for compressed size
1644 658 : if (compressed_size >= 0xffffffff)
1645 0 : datasize += 8;
1646 :
1647 : // Add ZIP64 extra info field for relative offset to local file header
1648 : // of current file
1649 658 : if (zi->ci.pos_local_header >= 0xffffffff)
1650 0 : datasize += 8;
1651 :
1652 658 : if (datasize > 0)
1653 : {
1654 0 : char *p = nullptr;
1655 :
1656 0 : if (static_cast<uLong>(datasize + 4) > zi->ci.size_centralExtraFree)
1657 : {
1658 : // we can not write more data to the buffer that we have room
1659 : // for.
1660 0 : return ZIP_BADZIPFILE;
1661 : }
1662 :
1663 0 : p = zi->ci.central_header + zi->ci.size_centralheader;
1664 :
1665 : // Add Extra Information Header for 'ZIP64 information'
1666 0 : zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID
1667 0 : p += 2;
1668 0 : zip64local_putValue_inmemory(p, datasize, 2); // DataSize
1669 0 : p += 2;
1670 :
1671 0 : if (uncompressed_size >= 0xffffffff)
1672 : {
1673 0 : zip64local_putValue_inmemory(p, uncompressed_size, 8);
1674 0 : p += 8;
1675 : }
1676 :
1677 0 : if (compressed_size >= 0xffffffff)
1678 : {
1679 0 : zip64local_putValue_inmemory(p, compressed_size, 8);
1680 0 : p += 8;
1681 : }
1682 :
1683 0 : if (zi->ci.pos_local_header >= 0xffffffff)
1684 : {
1685 0 : zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8);
1686 : // p += 8;
1687 : }
1688 :
1689 : // Update how much extra free space we got in the memory buffer
1690 : // and increase the centralheader size so the new ZIP64 fields are
1691 : // included ( 4 below is the size of HeaderID and DataSize field )
1692 0 : zi->ci.size_centralExtraFree -= datasize + 4;
1693 0 : zi->ci.size_centralheader += datasize + 4;
1694 :
1695 : // Update the extra info size field
1696 0 : zi->ci.size_centralExtra += datasize + 4;
1697 0 : zip64local_putValue_inmemory(
1698 0 : zi->ci.central_header + 30,
1699 0 : static_cast<uLong>(zi->ci.size_centralExtra), 2);
1700 : }
1701 :
1702 658 : if (err == ZIP_OK)
1703 658 : err = add_data_in_datablock(
1704 658 : &zi->central_dir, zi->ci.central_header,
1705 658 : static_cast<uLong>(zi->ci.size_centralheader));
1706 658 : free(zi->ci.central_header);
1707 658 : zi->ci.central_header = nullptr;
1708 : }
1709 :
1710 666 : free(zi->ci.local_header);
1711 666 : zi->ci.local_header = nullptr;
1712 :
1713 666 : if (err == ZIP_OK)
1714 : {
1715 : // Update the LocalFileHeader with the new values.
1716 :
1717 666 : ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream);
1718 :
1719 666 : if (ZSEEK64(zi->z_filefunc, zi->filestream,
1720 666 : zi->ci.pos_local_header + 14, ZLIB_FILEFUNC_SEEK_SET) != 0)
1721 0 : err = ZIP_ERRNO;
1722 :
1723 666 : if (err == ZIP_OK)
1724 666 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream, crc32,
1725 : 4); /* crc 32, unknown */
1726 :
1727 666 : if (uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff)
1728 : {
1729 0 : if (zi->ci.pos_zip64extrainfo > 0)
1730 : {
1731 : // Update the size in the ZIP64 extended field.
1732 0 : if (ZSEEK64(zi->z_filefunc, zi->filestream,
1733 : zi->ci.pos_zip64extrainfo + 4,
1734 0 : ZLIB_FILEFUNC_SEEK_SET) != 0)
1735 0 : err = ZIP_ERRNO;
1736 :
1737 0 : if (err == ZIP_OK) /* compressed size, unknown */
1738 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream,
1739 : uncompressed_size, 8);
1740 :
1741 0 : if (err == ZIP_OK) /* uncompressed size, unknown */
1742 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream,
1743 : compressed_size, 8);
1744 : }
1745 : else
1746 0 : err = ZIP_BADZIPFILE; // Caller passed zip64 = 0, so no room
1747 : // for zip64 info -> fatal
1748 : }
1749 : else
1750 : {
1751 666 : if (err == ZIP_OK) /* compressed size, unknown */
1752 666 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream,
1753 : compressed_size, 4);
1754 :
1755 666 : if (err == ZIP_OK) /* uncompressed size, unknown */
1756 666 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream,
1757 : uncompressed_size, 4);
1758 : }
1759 666 : if (ZSEEK64(zi->z_filefunc, zi->filestream, cur_pos_inzip,
1760 666 : ZLIB_FILEFUNC_SEEK_SET) != 0)
1761 0 : err = ZIP_ERRNO;
1762 : }
1763 :
1764 666 : if (bInCentralHeader)
1765 658 : zi->number_entry++;
1766 666 : zi->in_opened_file_inzip = 0;
1767 :
1768 666 : return err;
1769 : }
1770 :
1771 666 : extern int ZEXPORT cpl_zipCloseFileInZip(zipFile file)
1772 : {
1773 666 : return cpl_zipCloseFileInZipRaw(file, 0, 0);
1774 : }
1775 :
1776 0 : static int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal *zi,
1777 : ZPOS64_T zip64eocd_pos_inzip)
1778 : {
1779 0 : int err = ZIP_OK;
1780 0 : ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writing_offset;
1781 :
1782 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream,
1783 : ZIP64ENDLOCHEADERMAGIC, 4);
1784 :
1785 : /*num disks*/
1786 0 : if (err ==
1787 : ZIP_OK) /* number of the disk with the start of the central directory */
1788 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 0, 4);
1789 :
1790 : /*relative offset*/
1791 0 : if (err == ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */
1792 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream, pos, 8);
1793 :
1794 : /*total disks*/ /* Do not support spawning of disk so always say 1 here*/
1795 0 : if (err ==
1796 : ZIP_OK) /* number of the disk with the start of the central directory */
1797 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 1, 4);
1798 :
1799 0 : return err;
1800 : }
1801 :
1802 0 : static int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal *zi,
1803 : uLong size_centraldir,
1804 : ZPOS64_T centraldir_pos_inzip)
1805 : {
1806 0 : int err = ZIP_OK;
1807 :
1808 0 : uLong Zip64DataSize = 44;
1809 :
1810 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream,
1811 : ZIP64ENDHEADERMAGIC, 4);
1812 :
1813 0 : if (err == ZIP_OK) /* size of this 'zip64 end of central directory' */
1814 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream,
1815 : Zip64DataSize, 8); // why ZPOS64_T of this ?
1816 :
1817 0 : if (err == ZIP_OK) /* version made by */
1818 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 45, 2);
1819 :
1820 0 : if (err == ZIP_OK) /* version needed */
1821 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 45, 2);
1822 :
1823 0 : if (err == ZIP_OK) /* number of this disk */
1824 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 0, 4);
1825 :
1826 0 : if (err ==
1827 : ZIP_OK) /* number of the disk with the start of the central directory */
1828 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 0, 4);
1829 :
1830 0 : if (err ==
1831 : ZIP_OK) /* total number of entries in the central dir on this disk */
1832 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream,
1833 : zi->number_entry, 8);
1834 :
1835 0 : if (err == ZIP_OK) /* total number of entries in the central dir */
1836 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream,
1837 : zi->number_entry, 8);
1838 :
1839 0 : if (err == ZIP_OK) /* size of the central directory */
1840 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream,
1841 : size_centraldir, 8);
1842 :
1843 0 : if (err == ZIP_OK) /* offset of start of central directory with respect to
1844 : the starting disk number */
1845 : {
1846 0 : ZPOS64_T pos =
1847 0 : centraldir_pos_inzip - zi->add_position_when_writing_offset;
1848 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream, pos, 8);
1849 : }
1850 0 : return err;
1851 : }
1852 :
1853 388 : static int Write_EndOfCentralDirectoryRecord(zip64_internal *zi,
1854 : uLong size_centraldir,
1855 : ZPOS64_T centraldir_pos_inzip)
1856 : {
1857 388 : int err = ZIP_OK;
1858 :
1859 : /*signature*/
1860 : err =
1861 388 : zip64local_putValue(&zi->z_filefunc, zi->filestream, ENDHEADERMAGIC, 4);
1862 :
1863 388 : if (err == ZIP_OK) /* number of this disk */
1864 380 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 0, 2);
1865 :
1866 388 : if (err ==
1867 : ZIP_OK) /* number of the disk with the start of the central directory */
1868 376 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 0, 2);
1869 :
1870 388 : if (err ==
1871 : ZIP_OK) /* total number of entries in the central dir on this disk */
1872 : {
1873 : {
1874 372 : if (zi->number_entry >= 0xFFFF)
1875 : err =
1876 0 : zip64local_putValue(&zi->z_filefunc, zi->filestream, 0xffff,
1877 : 2); // use value in ZIP64 record
1878 : else
1879 372 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream,
1880 : zi->number_entry, 2);
1881 : }
1882 : }
1883 :
1884 388 : if (err == ZIP_OK) /* total number of entries in the central dir */
1885 : {
1886 368 : if (zi->number_entry >= 0xFFFF)
1887 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 0xffff,
1888 : 2); // use value in ZIP64 record
1889 : else
1890 368 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream,
1891 : zi->number_entry, 2);
1892 : }
1893 :
1894 388 : if (err == ZIP_OK) /* size of the central directory */
1895 364 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream,
1896 : size_centraldir, 4);
1897 :
1898 388 : if (err == ZIP_OK) /* offset of start of central directory with respect to
1899 : the starting disk number */
1900 : {
1901 356 : ZPOS64_T pos =
1902 356 : centraldir_pos_inzip - zi->add_position_when_writing_offset;
1903 356 : if (pos >= 0xffffffff)
1904 : {
1905 0 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream,
1906 : 0xffffffff, 4);
1907 : }
1908 : else
1909 356 : err = zip64local_putValue(
1910 356 : &zi->z_filefunc, zi->filestream,
1911 356 : (centraldir_pos_inzip - zi->add_position_when_writing_offset),
1912 : 4);
1913 : }
1914 :
1915 388 : return err;
1916 : }
1917 :
1918 352 : static int Write_GlobalComment(zip64_internal *zi, const char *global_comment)
1919 : {
1920 352 : int err = ZIP_OK;
1921 352 : uInt size_global_comment = 0;
1922 :
1923 352 : if (global_comment != nullptr)
1924 0 : size_global_comment = static_cast<uInt>(strlen(global_comment));
1925 :
1926 352 : err = zip64local_putValue(&zi->z_filefunc, zi->filestream,
1927 : size_global_comment, 2);
1928 :
1929 352 : if (err == ZIP_OK && size_global_comment > 0)
1930 : {
1931 0 : if (ZWRITE64(zi->z_filefunc, zi->filestream, global_comment,
1932 0 : size_global_comment) != size_global_comment)
1933 0 : err = ZIP_ERRNO;
1934 : }
1935 352 : return err;
1936 : }
1937 :
1938 444 : extern int ZEXPORT cpl_zipClose(zipFile file, const char *global_comment)
1939 : {
1940 444 : int err = 0;
1941 444 : uLong size_centraldir = 0;
1942 : ZPOS64_T centraldir_pos_inzip;
1943 : ZPOS64_T pos;
1944 :
1945 444 : if (file == nullptr)
1946 0 : return ZIP_PARAMERROR;
1947 :
1948 444 : zip64_internal *zi = reinterpret_cast<zip64_internal *>(file);
1949 :
1950 444 : if (zi->in_opened_file_inzip == 1)
1951 : {
1952 0 : err = cpl_zipCloseFileInZip(file);
1953 : }
1954 :
1955 : #ifndef NO_ADDFILEINEXISTINGZIP
1956 444 : if (global_comment == nullptr)
1957 444 : global_comment = zi->globalcomment;
1958 : #endif
1959 :
1960 444 : centraldir_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream);
1961 444 : if (err == ZIP_OK)
1962 : {
1963 444 : linkedlist_datablock_internal *ldi = zi->central_dir.first_block;
1964 830 : while (ldi != nullptr)
1965 : {
1966 386 : if ((err == ZIP_OK) && (ldi->filled_in_this_block > 0))
1967 386 : if (ZWRITE64(zi->z_filefunc, zi->filestream, ldi->data,
1968 386 : ldi->filled_in_this_block) !=
1969 386 : ldi->filled_in_this_block)
1970 56 : err = ZIP_ERRNO;
1971 :
1972 386 : size_centraldir += ldi->filled_in_this_block;
1973 386 : ldi = ldi->next_datablock;
1974 : }
1975 : }
1976 444 : free_linkedlist(&(zi->central_dir));
1977 :
1978 444 : pos = centraldir_pos_inzip - zi->add_position_when_writing_offset;
1979 444 : if (pos >= 0xffffffff || zi->number_entry > 0xFFFF)
1980 : {
1981 0 : ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc, zi->filestream);
1982 0 : Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir,
1983 : centraldir_pos_inzip);
1984 :
1985 0 : Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos);
1986 : }
1987 :
1988 444 : if (err == ZIP_OK)
1989 388 : err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir,
1990 : centraldir_pos_inzip);
1991 :
1992 444 : if (err == ZIP_OK)
1993 352 : err = Write_GlobalComment(zi, global_comment);
1994 :
1995 444 : if (ZCLOSE64(zi->z_filefunc, zi->filestream) != 0)
1996 0 : if (err == ZIP_OK)
1997 0 : err = ZIP_ERRNO;
1998 :
1999 : #ifndef NO_ADDFILEINEXISTINGZIP
2000 444 : TRYFREE(zi->globalcomment);
2001 : #endif
2002 444 : TRYFREE(zi);
2003 :
2004 444 : return err;
2005 : }
2006 :
2007 : /************************************************************************/
2008 : /* ==================================================================== */
2009 : /* The following is a simplified CPL API for creating ZIP files */
2010 : /* exported from cpl_conv.h. */
2011 : /* ==================================================================== */
2012 : /************************************************************************/
2013 :
2014 : #include "cpl_minizip_unzip.h"
2015 :
2016 : typedef struct
2017 : {
2018 : zipFile hZip;
2019 : char **papszFilenames;
2020 : } CPLZip;
2021 :
2022 : /************************************************************************/
2023 : /* CPLCreateZip() */
2024 : /************************************************************************/
2025 :
2026 : /** Create ZIP file */
2027 448 : void *CPLCreateZip(const char *pszZipFilename, char **papszOptions)
2028 :
2029 : {
2030 : const bool bAppend =
2031 448 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "APPEND", "FALSE"));
2032 448 : char **papszFilenames = nullptr;
2033 :
2034 448 : if (bAppend)
2035 : {
2036 203 : zipFile unzF = cpl_unzOpen(pszZipFilename);
2037 203 : if (unzF != nullptr)
2038 : {
2039 202 : if (cpl_unzGoToFirstFile(unzF) == UNZ_OK)
2040 : {
2041 394 : do
2042 : {
2043 : char fileName[8193];
2044 : unz_file_info file_info;
2045 596 : cpl_unzGetCurrentFileInfo(unzF, &file_info, fileName,
2046 : sizeof(fileName) - 1, nullptr, 0,
2047 : nullptr, 0);
2048 596 : fileName[sizeof(fileName) - 1] = '\0';
2049 596 : papszFilenames = CSLAddString(papszFilenames, fileName);
2050 596 : } while (cpl_unzGoToNextFile(unzF) == UNZ_OK);
2051 : }
2052 202 : cpl_unzClose(unzF);
2053 : }
2054 : }
2055 :
2056 448 : zipFile hZip = cpl_zipOpen(pszZipFilename, bAppend ? APPEND_STATUS_ADDINZIP
2057 : : APPEND_STATUS_CREATE);
2058 448 : if (hZip == nullptr)
2059 : {
2060 4 : CSLDestroy(papszFilenames);
2061 4 : return nullptr;
2062 : }
2063 :
2064 444 : CPLZip *psZip = static_cast<CPLZip *>(CPLMalloc(sizeof(CPLZip)));
2065 444 : psZip->hZip = hZip;
2066 444 : psZip->papszFilenames = papszFilenames;
2067 444 : return psZip;
2068 : }
2069 :
2070 : /************************************************************************/
2071 : /* CPLCreateFileInZip() */
2072 : /************************************************************************/
2073 :
2074 : /** Create a file in a ZIP file */
2075 726 : CPLErr CPLCreateFileInZip(void *hZip, const char *pszFilename,
2076 : char **papszOptions)
2077 :
2078 : {
2079 726 : if (hZip == nullptr)
2080 0 : return CE_Failure;
2081 :
2082 726 : CPLZip *psZip = static_cast<CPLZip *>(hZip);
2083 :
2084 726 : if (CSLFindString(psZip->papszFilenames, pszFilename) >= 0)
2085 : {
2086 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s already exists in ZIP file",
2087 : pszFilename);
2088 3 : return CE_Failure;
2089 : }
2090 :
2091 : const bool bCompressed =
2092 723 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "COMPRESSED", "TRUE"));
2093 :
2094 723 : char *pszCPFilename = nullptr;
2095 1446 : std::vector<GByte> abyExtra;
2096 : // If the filename is not ASCII only, we need an extended field
2097 723 : if (!CPLIsASCII(pszFilename, strlen(pszFilename)))
2098 : {
2099 1 : const char *pszDestEncoding = CPLGetConfigOption("CPL_ZIP_ENCODING",
2100 : #if defined(_WIN32) && !defined(HAVE_ICONV)
2101 : "CP_OEMCP"
2102 : #else
2103 : "CP437"
2104 : #endif
2105 : );
2106 :
2107 1 : pszCPFilename = CPLRecode(pszFilename, CPL_ENC_UTF8, pszDestEncoding);
2108 :
2109 : /* Create a Info-ZIP Unicode Path Extra Field (0x7075) */
2110 1 : const size_t nDataLength =
2111 1 : sizeof(GByte) + sizeof(uint32_t) + strlen(pszFilename);
2112 1 : if (abyExtra.size() + 2 * sizeof(uint16_t) + nDataLength >
2113 1 : std::numeric_limits<uint16_t>::max())
2114 : {
2115 0 : CPLError(CE_Warning, CPLE_AppDefined,
2116 : "Too much content to fit in ZIP ExtraField");
2117 : }
2118 : else
2119 : {
2120 1 : const uint16_t nHeaderIdLE = CPL_LSBWORD16(0x7075);
2121 0 : abyExtra.insert(abyExtra.end(),
2122 : reinterpret_cast<const GByte *>(&nHeaderIdLE),
2123 1 : reinterpret_cast<const GByte *>(&nHeaderIdLE) + 2);
2124 1 : const uint16_t nDataLengthLE =
2125 : CPL_LSBWORD16(static_cast<uint16_t>(nDataLength));
2126 : abyExtra.insert(
2127 0 : abyExtra.end(), reinterpret_cast<const GByte *>(&nDataLengthLE),
2128 1 : reinterpret_cast<const GByte *>(&nDataLengthLE) + 2);
2129 1 : const GByte nVersion = 1;
2130 1 : abyExtra.push_back(nVersion);
2131 : const uint32_t nNameCRC32 = static_cast<uint32_t>(
2132 2 : crc32(0, reinterpret_cast<const Bytef *>(pszCPFilename),
2133 1 : static_cast<uInt>(strlen(pszCPFilename))));
2134 1 : const uint32_t nNameCRC32LE = CPL_LSBWORD32(nNameCRC32);
2135 0 : abyExtra.insert(abyExtra.end(),
2136 : reinterpret_cast<const GByte *>(&nNameCRC32LE),
2137 1 : reinterpret_cast<const GByte *>(&nNameCRC32LE) + 4);
2138 0 : abyExtra.insert(abyExtra.end(),
2139 : reinterpret_cast<const GByte *>(pszFilename),
2140 : reinterpret_cast<const GByte *>(pszFilename) +
2141 1 : strlen(pszFilename));
2142 : }
2143 : }
2144 : else
2145 : {
2146 722 : pszCPFilename = CPLStrdup(pszFilename);
2147 : }
2148 :
2149 : const char *pszContentType =
2150 723 : CSLFetchNameValue(papszOptions, "CONTENT_TYPE");
2151 723 : if (pszContentType)
2152 : {
2153 1 : const size_t nDataLength = strlen("KeyValuePairs") + sizeof(GByte) +
2154 : sizeof(uint16_t) + strlen("Content-Type") +
2155 1 : sizeof(uint16_t) + strlen(pszContentType);
2156 1 : if (abyExtra.size() + 2 * sizeof(uint16_t) + nDataLength >
2157 1 : std::numeric_limits<uint16_t>::max())
2158 : {
2159 0 : CPLError(CE_Warning, CPLE_AppDefined,
2160 : "Too much content to fit in ZIP ExtraField");
2161 : }
2162 : else
2163 : {
2164 1 : abyExtra.push_back(GByte('K'));
2165 1 : abyExtra.push_back(GByte('V'));
2166 1 : const uint16_t nDataLengthLE =
2167 : CPL_LSBWORD16(static_cast<uint16_t>(nDataLength));
2168 : abyExtra.insert(
2169 0 : abyExtra.end(), reinterpret_cast<const GByte *>(&nDataLengthLE),
2170 1 : reinterpret_cast<const GByte *>(&nDataLengthLE) + 2);
2171 0 : abyExtra.insert(abyExtra.end(),
2172 : reinterpret_cast<const GByte *>("KeyValuePairs"),
2173 : reinterpret_cast<const GByte *>("KeyValuePairs") +
2174 1 : strlen("KeyValuePairs"));
2175 1 : abyExtra.push_back(1); // number of key/value pairs
2176 1 : const uint16_t nKeyLen =
2177 : CPL_LSBWORD16(static_cast<uint16_t>(strlen("Content-Type")));
2178 0 : abyExtra.insert(abyExtra.end(),
2179 : reinterpret_cast<const GByte *>(&nKeyLen),
2180 1 : reinterpret_cast<const GByte *>(&nKeyLen) + 2);
2181 0 : abyExtra.insert(abyExtra.end(),
2182 : reinterpret_cast<const GByte *>("Content-Type"),
2183 : reinterpret_cast<const GByte *>("Content-Type") +
2184 1 : strlen("Content-Type"));
2185 1 : const uint16_t nValLen =
2186 1 : CPL_LSBWORD16(static_cast<uint16_t>(strlen(pszContentType)));
2187 0 : abyExtra.insert(abyExtra.end(),
2188 : reinterpret_cast<const GByte *>(&nValLen),
2189 1 : reinterpret_cast<const GByte *>(&nValLen) + 2);
2190 0 : abyExtra.insert(abyExtra.end(),
2191 : reinterpret_cast<const GByte *>(pszContentType),
2192 : reinterpret_cast<const GByte *>(
2193 1 : pszContentType + strlen(pszContentType)));
2194 : }
2195 : }
2196 :
2197 723 : const bool bIncludeInCentralDirectory = CPLTestBool(CSLFetchNameValueDef(
2198 : papszOptions, "INCLUDE_IN_CENTRAL_DIRECTORY", "YES"));
2199 723 : const bool bZip64 = CPLTestBool(CSLFetchNameValueDef(
2200 : papszOptions, "ZIP64", CPLGetConfigOption("CPL_CREATE_ZIP64", "ON")));
2201 :
2202 : // Set datetime to write
2203 : zip_fileinfo fileinfo;
2204 723 : memset(&fileinfo, 0, sizeof(fileinfo));
2205 : const char *pszTimeStamp =
2206 723 : CSLFetchNameValueDef(papszOptions, "TIMESTAMP", "NOW");
2207 : GIntBig unixTime =
2208 723 : EQUAL(pszTimeStamp, "NOW")
2209 723 : ? time(nullptr)
2210 87 : : static_cast<GIntBig>(std::strtoll(pszTimeStamp, nullptr, 10));
2211 : struct tm brokenDown;
2212 723 : CPLUnixTimeToYMDHMS(unixTime, &brokenDown);
2213 723 : fileinfo.tmz_date.tm_year = brokenDown.tm_year;
2214 723 : fileinfo.tmz_date.tm_mon = brokenDown.tm_mon;
2215 723 : fileinfo.tmz_date.tm_mday = brokenDown.tm_mday;
2216 723 : fileinfo.tmz_date.tm_hour = brokenDown.tm_hour;
2217 723 : fileinfo.tmz_date.tm_min = brokenDown.tm_min;
2218 723 : fileinfo.tmz_date.tm_sec = brokenDown.tm_sec;
2219 :
2220 2171 : const int nErr = cpl_zipOpenNewFileInZip3(
2221 : psZip->hZip, pszCPFilename, &fileinfo,
2222 725 : abyExtra.empty() ? nullptr : abyExtra.data(),
2223 723 : static_cast<uInt>(abyExtra.size()),
2224 725 : abyExtra.empty() ? nullptr : abyExtra.data(),
2225 723 : static_cast<uInt>(abyExtra.size()), "", bCompressed ? Z_DEFLATED : 0,
2226 : bCompressed ? Z_DEFAULT_COMPRESSION : 0,
2227 : /* raw = */ 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
2228 : /* password = */ nullptr,
2229 : /* crcForCtypting = */ 0, bZip64, bIncludeInCentralDirectory);
2230 :
2231 723 : CPLFree(pszCPFilename);
2232 :
2233 723 : if (nErr != ZIP_OK)
2234 57 : return CE_Failure;
2235 :
2236 666 : if (bIncludeInCentralDirectory)
2237 658 : psZip->papszFilenames =
2238 658 : CSLAddString(psZip->papszFilenames, pszFilename);
2239 :
2240 666 : return CE_None;
2241 : }
2242 :
2243 : /************************************************************************/
2244 : /* CPLWriteFileInZip() */
2245 : /************************************************************************/
2246 :
2247 : /** Write in current file inside a ZIP file */
2248 211057 : CPLErr CPLWriteFileInZip(void *hZip, const void *pBuffer, int nBufferSize)
2249 :
2250 : {
2251 211057 : if (hZip == nullptr)
2252 0 : return CE_Failure;
2253 :
2254 211057 : CPLZip *psZip = static_cast<CPLZip *>(hZip);
2255 :
2256 211057 : int nErr = cpl_zipWriteInFileInZip(psZip->hZip, pBuffer,
2257 : static_cast<unsigned int>(nBufferSize));
2258 :
2259 211057 : if (nErr != ZIP_OK)
2260 34464 : return CE_Failure;
2261 :
2262 176593 : return CE_None;
2263 : }
2264 :
2265 : /************************************************************************/
2266 : /* CPLCloseFileInZip() */
2267 : /************************************************************************/
2268 :
2269 : /** Close current file inside ZIP file */
2270 660 : CPLErr CPLCloseFileInZip(void *hZip)
2271 :
2272 : {
2273 660 : if (hZip == nullptr)
2274 0 : return CE_Failure;
2275 :
2276 660 : CPLZip *psZip = static_cast<CPLZip *>(hZip);
2277 :
2278 660 : int nErr = cpl_zipCloseFileInZip(psZip->hZip);
2279 :
2280 660 : if (nErr != ZIP_OK)
2281 0 : return CE_Failure;
2282 :
2283 660 : return CE_None;
2284 : }
2285 :
2286 : /************************************************************************/
2287 : /* CPLAddFileInZip() */
2288 : /************************************************************************/
2289 :
2290 : /** Add a file inside a ZIP file opened/created with CPLCreateZip().
2291 : *
2292 : * This combines calls to CPLCreateFileInZip(), CPLWriteFileInZip(),
2293 : * and CPLCloseFileInZip() in a more convenient and powerful way.
2294 : *
2295 : * In particular, this enables to add a compressed file using the seek
2296 : * optimization extension.
2297 : *
2298 : * Supported options are:
2299 : * <ul>
2300 : * <li>SOZIP_ENABLED=AUTO/YES/NO: whether to generate a SOZip index for the
2301 : * file. The default can be changed with the CPL_SOZIP_ENABLED configuration
2302 : * option.</li>
2303 : * <li>SOZIP_CHUNK_SIZE: chunk size to use for SOZip generation. Defaults to
2304 : * 32768.
2305 : * </li>
2306 : * <li>SOZIP_MIN_FILE_SIZE: minimum file size to consider to enable SOZip index
2307 : * generation in SOZIP_ENABLED=AUTO mode. Defaults to 1 MB.
2308 : * </li>
2309 : * <li>NUM_THREADS: number of threads used for SOZip generation. Defaults to
2310 : * ALL_CPUS.</li>
2311 : * <li>TIMESTAMP=AUTO/NOW/timestamp_as_epoch_since_jan_1_1970: in AUTO mode,
2312 : * the timestamp of pszInputFilename will be used (if available), otherwise
2313 : * it will fallback to NOW.</li>
2314 : * <li>CONTENT_TYPE=string: Content-Type value for the file. This is stored as
2315 : * a key-value pair in the extra field extension 'KV' (0x564b) dedicated to
2316 : * storing key-value pair metadata.</li>
2317 : * </ul>
2318 : *
2319 : * @param hZip ZIP file handle
2320 : * @param pszArchiveFilename Filename (in UTF-8) stored in the archive.
2321 : * @param pszInputFilename Filename of the file to add. If NULL, fpInput must
2322 : * not be NULL
2323 : * @param fpInput File handle opened on the file to add. May be NULL if
2324 : * pszInputFilename is provided.
2325 : * @param papszOptions Options.
2326 : * @param pProgressFunc Progress callback, or NULL.
2327 : * @param pProgressData User data of progress callback, or NULL.
2328 : * @return CE_None in case of success.
2329 : *
2330 : * @since GDAL 3.7
2331 : */
2332 82 : CPLErr CPLAddFileInZip(void *hZip, const char *pszArchiveFilename,
2333 : const char *pszInputFilename, VSILFILE *fpInput,
2334 : CSLConstList papszOptions,
2335 : GDALProgressFunc pProgressFunc, void *pProgressData)
2336 : {
2337 82 : if (!hZip || !pszArchiveFilename || (!pszInputFilename && !fpInput))
2338 0 : return CE_Failure;
2339 :
2340 82 : CPLZip *psZip = static_cast<CPLZip *>(hZip);
2341 82 : zip64_internal *zi = reinterpret_cast<zip64_internal *>(psZip->hZip);
2342 :
2343 82 : VSIVirtualHandleUniquePtr poFileHandleAutoClose;
2344 82 : if (!fpInput)
2345 : {
2346 81 : fpInput = VSIFOpenL(pszInputFilename, "rb");
2347 81 : if (!fpInput)
2348 0 : return CE_Failure;
2349 81 : poFileHandleAutoClose.reset(fpInput);
2350 : }
2351 :
2352 82 : VSIFSeekL(fpInput, 0, SEEK_END);
2353 82 : const auto nUncompressedSize = VSIFTellL(fpInput);
2354 82 : VSIFSeekL(fpInput, 0, SEEK_SET);
2355 :
2356 164 : CPLStringList aosNewsOptions(papszOptions);
2357 82 : bool bSeekOptimized = false;
2358 : const char *pszSOZIP =
2359 82 : CSLFetchNameValueDef(papszOptions, "SOZIP_ENABLED",
2360 : CPLGetConfigOption("CPL_SOZIP_ENABLED", "AUTO"));
2361 :
2362 82 : const char *pszChunkSize = CSLFetchNameValueDef(
2363 : papszOptions, "SOZIP_CHUNK_SIZE",
2364 : CPLGetConfigOption("CPL_VSIL_DEFLATE_CHUNK_SIZE", nullptr));
2365 82 : const bool bChunkSizeSpecified = pszChunkSize != nullptr;
2366 82 : if (!pszChunkSize)
2367 77 : pszChunkSize = "1024K";
2368 82 : unsigned nChunkSize = static_cast<unsigned>(atoi(pszChunkSize));
2369 82 : if (strchr(pszChunkSize, 'K'))
2370 77 : nChunkSize *= 1024;
2371 5 : else if (strchr(pszChunkSize, 'M'))
2372 0 : nChunkSize *= 1024 * 1024;
2373 82 : nChunkSize =
2374 164 : std::max(static_cast<unsigned>(1),
2375 82 : std::min(static_cast<unsigned>(UINT_MAX), nChunkSize));
2376 :
2377 82 : const char *pszMinFileSize = CSLFetchNameValueDef(
2378 : papszOptions, "SOZIP_MIN_FILE_SIZE",
2379 : CPLGetConfigOption("CPL_SOZIP_MIN_FILE_SIZE", "1M"));
2380 82 : uint64_t nSOZipMinFileSize = std::strtoull(pszMinFileSize, nullptr, 10);
2381 82 : if (strchr(pszMinFileSize, 'K'))
2382 0 : nSOZipMinFileSize *= 1024;
2383 82 : else if (strchr(pszMinFileSize, 'M'))
2384 81 : nSOZipMinFileSize *= 1024 * 1024;
2385 1 : else if (strchr(pszMinFileSize, 'G'))
2386 0 : nSOZipMinFileSize *= 1024 * 1024 * 1024;
2387 :
2388 164 : std::vector<uint8_t> sozip_index;
2389 82 : uint64_t nExpectedIndexSize = 0;
2390 82 : constexpr unsigned nDefaultSOZipChunkSize = 32 * 1024;
2391 82 : constexpr size_t nOffsetSize = 8;
2392 78 : if (((EQUAL(pszSOZIP, "AUTO") && nUncompressedSize > nSOZipMinFileSize) ||
2393 169 : (!EQUAL(pszSOZIP, "AUTO") && CPLTestBool(pszSOZIP))) &&
2394 5 : ((bChunkSizeSpecified &&
2395 5 : nUncompressedSize > static_cast<unsigned>(nChunkSize)) ||
2396 4 : (!bChunkSizeSpecified && nUncompressedSize > nDefaultSOZipChunkSize)))
2397 : {
2398 9 : if (!bChunkSizeSpecified)
2399 4 : nChunkSize = nDefaultSOZipChunkSize;
2400 :
2401 9 : bSeekOptimized = true;
2402 :
2403 : aosNewsOptions.SetNameValue(
2404 9 : "UNCOMPRESSED_SIZE", CPLSPrintf(CPL_FRMT_GUIB, nUncompressedSize));
2405 :
2406 9 : zi->nOffsetSize = nOffsetSize;
2407 9 : nExpectedIndexSize =
2408 9 : 32 + ((nUncompressedSize - 1) / nChunkSize) * nOffsetSize;
2409 9 : if (nExpectedIndexSize >
2410 9 : static_cast<uint64_t>(std::numeric_limits<int>::max()))
2411 : {
2412 0 : CPLError(CE_Failure, CPLE_AppDefined,
2413 : "Too big file w.r.t CHUNK_SIZE");
2414 0 : return CE_Failure;
2415 : }
2416 : try
2417 : {
2418 9 : sozip_index.reserve(static_cast<size_t>(nExpectedIndexSize));
2419 : }
2420 0 : catch (const std::exception &)
2421 : {
2422 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
2423 : "Cannot allocate memory for SOZip index");
2424 0 : return CE_Failure;
2425 : }
2426 9 : sozip_index.resize(32);
2427 : uint32_t nVal32;
2428 : // Version
2429 9 : nVal32 = CPL_LSBWORD32(1);
2430 9 : memcpy(sozip_index.data(), &nVal32, sizeof(nVal32));
2431 : // Extra reserved space after 32 bytes of header
2432 9 : nVal32 = CPL_LSBWORD32(0);
2433 9 : memcpy(sozip_index.data() + 4, &nVal32, sizeof(nVal32));
2434 : // Chunksize
2435 9 : nVal32 = CPL_LSBWORD32(nChunkSize);
2436 9 : memcpy(sozip_index.data() + 8, &nVal32, sizeof(nVal32));
2437 : // SOZIPIndexEltSize
2438 9 : nVal32 = CPL_LSBWORD32(static_cast<uint32_t>(nOffsetSize));
2439 9 : memcpy(sozip_index.data() + 12, &nVal32, sizeof(nVal32));
2440 : // Uncompressed size
2441 9 : uint64_t nVal64 = nUncompressedSize;
2442 9 : CPL_LSBPTR64(&nVal64);
2443 9 : memcpy(sozip_index.data() + 16, &nVal64, sizeof(nVal64));
2444 9 : zi->sozip_index = &sozip_index;
2445 :
2446 9 : zi->nChunkSize = nChunkSize;
2447 :
2448 9 : const char *pszThreads = CSLFetchNameValue(papszOptions, "NUM_THREADS");
2449 9 : if (pszThreads == nullptr || EQUAL(pszThreads, "ALL_CPUS"))
2450 9 : zi->nThreads = CPLGetNumCPUs();
2451 : else
2452 0 : zi->nThreads = atoi(pszThreads);
2453 9 : zi->nThreads = std::max(1, std::min(128, zi->nThreads));
2454 : }
2455 :
2456 : aosNewsOptions.SetNameValue("ZIP64",
2457 82 : nUncompressedSize > 0xFFFFFFFFU ? "YES" : "NO");
2458 :
2459 163 : if (pszInputFilename != nullptr &&
2460 81 : aosNewsOptions.FetchNameValue("TIMESTAMP") == nullptr)
2461 : {
2462 : VSIStatBufL sStat;
2463 81 : if (VSIStatL(pszInputFilename, &sStat) == 0 && sStat.st_mtime != 0)
2464 : {
2465 : aosNewsOptions.SetNameValue(
2466 : "TIMESTAMP",
2467 81 : CPLSPrintf(CPL_FRMT_GIB, static_cast<GIntBig>(sStat.st_mtime)));
2468 : }
2469 : }
2470 :
2471 82 : if (CPLCreateFileInZip(hZip, pszArchiveFilename, aosNewsOptions.List()) !=
2472 : CE_None)
2473 : {
2474 1 : zi->sozip_index = nullptr;
2475 1 : zi->nChunkSize = 0;
2476 1 : zi->nThreads = 0;
2477 1 : return CE_Failure;
2478 : }
2479 81 : zi->nChunkSize = 0;
2480 81 : zi->nThreads = 0;
2481 :
2482 81 : constexpr int CHUNK_READ_MAX_SIZE = 1024 * 1024;
2483 162 : std::vector<GByte> abyChunk(CHUNK_READ_MAX_SIZE);
2484 81 : vsi_l_offset nOffset = 0;
2485 : while (true)
2486 : {
2487 : const int nRead = static_cast<int>(
2488 91 : VSIFReadL(abyChunk.data(), 1, abyChunk.size(), fpInput));
2489 182 : if (nRead > 0 &&
2490 91 : CPLWriteFileInZip(hZip, abyChunk.data(), nRead) != CE_None)
2491 : {
2492 0 : CPLCloseFileInZip(hZip);
2493 0 : zi->sozip_index = nullptr;
2494 0 : return CE_Failure;
2495 : }
2496 91 : nOffset += nRead;
2497 149 : if (pProgressFunc &&
2498 116 : !pProgressFunc(nUncompressedSize == 0
2499 : ? 1.0
2500 58 : : double(nOffset) / nUncompressedSize,
2501 : nullptr, pProgressData))
2502 : {
2503 1 : CPLCloseFileInZip(hZip);
2504 1 : zi->sozip_index = nullptr;
2505 1 : return CE_Failure;
2506 : }
2507 90 : if (nRead < CHUNK_READ_MAX_SIZE)
2508 80 : break;
2509 10 : }
2510 :
2511 80 : if (CPLCloseFileInZip(hZip) != CE_None)
2512 : {
2513 0 : zi->sozip_index = nullptr;
2514 0 : return CE_Failure;
2515 : }
2516 :
2517 80 : if (bSeekOptimized && sozip_index.size() != nExpectedIndexSize)
2518 : {
2519 : // shouldn't happen
2520 0 : CPLError(CE_Failure, CPLE_AppDefined,
2521 : "sozip_index.size() (=%u) != nExpectedIndexSize (=%u)",
2522 0 : static_cast<unsigned>(sozip_index.size()),
2523 : static_cast<unsigned>(nExpectedIndexSize));
2524 : }
2525 80 : else if (bSeekOptimized)
2526 : {
2527 8 : std::string osIdxName;
2528 8 : const char *pszLastSlash = strchr(pszArchiveFilename, '/');
2529 8 : if (pszLastSlash)
2530 : {
2531 : osIdxName.assign(pszArchiveFilename,
2532 2 : pszLastSlash - pszArchiveFilename + 1);
2533 2 : osIdxName += '.';
2534 2 : osIdxName += pszLastSlash + 1;
2535 : }
2536 : else
2537 : {
2538 6 : osIdxName = '.';
2539 6 : osIdxName += pszArchiveFilename;
2540 : }
2541 8 : osIdxName += ".sozip.idx";
2542 :
2543 8 : CPLStringList aosIndexOptions;
2544 8 : aosIndexOptions.SetNameValue("COMPRESSED", "NO");
2545 8 : aosIndexOptions.SetNameValue("ZIP64", "NO");
2546 8 : aosIndexOptions.SetNameValue("INCLUDE_IN_CENTRAL_DIRECTORY", "NO");
2547 : aosIndexOptions.SetNameValue(
2548 8 : "TIMESTAMP", aosNewsOptions.FetchNameValue("TIMESTAMP"));
2549 8 : if (CPLCreateFileInZip(hZip, osIdxName.c_str(),
2550 8 : aosIndexOptions.List()) != CE_None)
2551 : {
2552 0 : zi->sozip_index = nullptr;
2553 0 : return CE_Failure;
2554 : }
2555 :
2556 8 : if (CPLWriteFileInZip(hZip, sozip_index.data(),
2557 16 : static_cast<int>(sozip_index.size())) != CE_None)
2558 : {
2559 0 : zi->sozip_index = nullptr;
2560 0 : CPLCloseFileInZip(hZip);
2561 0 : return CE_Failure;
2562 : }
2563 :
2564 8 : zi->sozip_index = nullptr;
2565 8 : if (CPLCloseFileInZip(hZip) != CE_None)
2566 : {
2567 0 : return CE_Failure;
2568 : }
2569 : }
2570 :
2571 80 : zi->sozip_index = nullptr;
2572 :
2573 80 : return CE_None;
2574 : }
2575 :
2576 : /************************************************************************/
2577 : /* CPLCloseZip() */
2578 : /************************************************************************/
2579 :
2580 : /** Close ZIP file */
2581 444 : CPLErr CPLCloseZip(void *hZip)
2582 : {
2583 444 : if (hZip == nullptr)
2584 0 : return CE_Failure;
2585 :
2586 444 : CPLZip *psZip = static_cast<CPLZip *>(hZip);
2587 :
2588 444 : int nErr = cpl_zipClose(psZip->hZip, nullptr);
2589 :
2590 444 : psZip->hZip = nullptr;
2591 444 : CSLDestroy(psZip->papszFilenames);
2592 444 : psZip->papszFilenames = nullptr;
2593 444 : CPLFree(psZip);
2594 :
2595 444 : if (nErr != ZIP_OK)
2596 94 : return CE_Failure;
2597 :
2598 350 : return CE_None;
2599 : }
|