LCOV - code coverage report
Current view: top level - port - cpl_minizip_zip.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 834 1161 71.8 %
Date: 2025-09-10 17:48:50 Functions: 32 37 86.5 %

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

Generated by: LCOV version 1.14