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

Generated by: LCOV version 1.14