LCOV - code coverage report
Current view: directory - port - cpl_vsil_gzip.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 835 635 76.0 %
Date: 2012-04-28 Functions: 100 65 65.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: cpl_vsil_gzip.cpp 23995 2012-02-19 22:39:17Z rouault $
       3                 :  *
       4                 :  * Project:  CPL - Common Portability Library
       5                 :  * Purpose:  Implement VSI large file api for gz/zip files (.gz and .zip).
       6                 :  * Author:   Even Rouault, even.rouault at mines-paris.org
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2007, Even Rouault
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : /* gzio.c -- IO on .gz files
      31                 :   Copyright (C) 1995-2005 Jean-loup Gailly.
      32                 : 
      33                 :   This software is provided 'as-is', without any express or implied
      34                 :   warranty.  In no event will the authors be held liable for any damages
      35                 :   arising from the use of this software.
      36                 : 
      37                 :   Permission is granted to anyone to use this software for any purpose,
      38                 :   including commercial applications, and to alter it and redistribute it
      39                 :   freely, subject to the following restrictions:
      40                 : 
      41                 :   1. The origin of this software must not be misrepresented; you must not
      42                 :      claim that you wrote the original software. If you use this software
      43                 :      in a product, an acknowledgment in the product documentation would be
      44                 :      appreciated but is not required.
      45                 :   2. Altered source versions must be plainly marked as such, and must not be
      46                 :      misrepresented as being the original software.
      47                 :   3. This notice may not be removed or altered from any source distribution.
      48                 : 
      49                 :   Jean-loup Gailly        Mark Adler
      50                 :   jloup@gzip.org          madler@alumni.caltech.edu
      51                 : 
      52                 : 
      53                 :   The data format used by the zlib library is described by RFCs (Request for
      54                 :   Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
      55                 :   (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
      56                 : */
      57                 : 
      58                 : 
      59                 : /* This file contains a refactoring of gzio.c from zlib project.
      60                 : 
      61                 :    It replaces classical calls operating on FILE* by calls to the VSI large file
      62                 :    API. It also adds the capability to seek at the end of the file, which is not
      63                 :    implemented in original gzSeek. It also implements a concept of in-memory "snapshots",
      64                 :    that are a way of improving efficiency while seeking GZip files. Snapshots are
      65                 :    ceated regularly when decompressing  the data a snapshot of the gzip state.
      66                 :    Later we can seek directly in the compressed data to the closest snapshot in order to
      67                 :    reduce the amount of data to uncompress again.
      68                 : 
      69                 :    For .gz files, an effort is done to cache the size of the uncompressed data in
      70                 :    a .gz.properties file, so that we don't need to seek at the end of the file
      71                 :    each time a Stat() is done.
      72                 : 
      73                 :    For .zip and .gz, both reading and writing are supported, but just one mode at a time
      74                 :    (read-only or write-only)
      75                 : */
      76                 : 
      77                 : 
      78                 : #include "cpl_vsi_virtual.h"
      79                 : #include "cpl_string.h"
      80                 : #include "cpl_multiproc.h"
      81                 : #include <map>
      82                 : 
      83                 : #include <zlib.h>
      84                 : #include "cpl_minizip_unzip.h"
      85                 : #include "cpl_time.h"
      86                 : 
      87                 : CPL_CVSID("$Id: cpl_vsil_gzip.cpp 23995 2012-02-19 22:39:17Z rouault $");
      88                 : 
      89                 : #define Z_BUFSIZE 65536  /* original size is 16384 */
      90                 : static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
      91                 : 
      92                 : /* gzip flag byte */
      93                 : #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
      94                 : #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
      95                 : #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
      96                 : #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
      97                 : #define COMMENT      0x10 /* bit 4 set: file comment present */
      98                 : #define RESERVED     0xE0 /* bits 5..7: reserved */
      99                 : 
     100                 : #define ALLOC(size) malloc(size)
     101                 : #define TRYFREE(p) {if (p) free(p);}
     102                 : 
     103                 : #define CPL_VSIL_GZ_RETURN_MINUS_ONE()   \
     104                 :         CPLError(CE_Failure, CPLE_AppDefined, "In file %s, at line %d, return -1", __FILE__, __LINE__)
     105                 : 
     106                 : #define ENABLE_DEBUG 0
     107                 : 
     108                 : /************************************************************************/
     109                 : /* ==================================================================== */
     110                 : /*                       VSIGZipHandle                                  */
     111                 : /* ==================================================================== */
     112                 : /************************************************************************/
     113                 : 
     114                 : typedef struct
     115                 : {
     116                 :     vsi_l_offset  uncompressed_pos;
     117                 :     z_stream      stream;
     118                 :     uLong         crc;
     119                 :     int           transparent;
     120                 :     vsi_l_offset  in;
     121                 :     vsi_l_offset  out;
     122                 : } GZipSnapshot;
     123                 : 
     124                 : class VSIGZipHandle : public VSIVirtualHandle
     125                 : {
     126                 :     VSIVirtualHandle* poBaseHandle;
     127                 :     vsi_l_offset      offset;
     128                 :     vsi_l_offset      compressed_size;
     129                 :     vsi_l_offset      uncompressed_size;
     130                 :     vsi_l_offset      offsetEndCompressedData;
     131                 :     unsigned int      expected_crc;
     132                 :     char             *pszBaseFileName; /* optional */
     133                 : 
     134                 :     /* Fields from gz_stream structure */
     135                 :     z_stream stream;
     136                 :     int      z_err;   /* error code for last stream operation */
     137                 :     int      z_eof;   /* set if end of input file */
     138                 :     Byte     *inbuf;  /* input buffer */
     139                 :     Byte     *outbuf; /* output buffer */
     140                 :     uLong    crc;     /* crc32 of uncompressed data */
     141                 :     int      transparent; /* 1 if input file is not a .gz file */
     142                 :     vsi_l_offset  startOff;   /* startOff of compressed data in file (header skipped) */
     143                 :     vsi_l_offset  in;      /* bytes into deflate or inflate */
     144                 :     vsi_l_offset  out;     /* bytes out of deflate or inflate */
     145                 :     vsi_l_offset  nLastReadOffset;
     146                 :     
     147                 :     GZipSnapshot* snapshots;
     148                 :     vsi_l_offset snapshot_byte_interval; /* number of compressed bytes at which we create a "snapshot" */
     149                 : 
     150                 :     void check_header();
     151                 :     int get_byte();
     152                 :     int gzseek( vsi_l_offset nOffset, int nWhence );
     153                 :     int gzrewind ();
     154                 :     uLong getLong ();
     155                 : 
     156                 :   public:
     157                 : 
     158                 :     VSIGZipHandle(VSIVirtualHandle* poBaseHandle,
     159                 :                   const char* pszBaseFileName,
     160                 :                   vsi_l_offset offset = 0,
     161                 :                   vsi_l_offset compressed_size = 0,
     162                 :                   vsi_l_offset uncompressed_size = 0,
     163                 :                   unsigned int expected_crc = 0,
     164                 :                   int transparent = 0);
     165                 :     ~VSIGZipHandle();
     166                 : 
     167                 :     virtual int       Seek( vsi_l_offset nOffset, int nWhence );
     168                 :     virtual vsi_l_offset Tell();
     169                 :     virtual size_t    Read( void *pBuffer, size_t nSize, size_t nMemb );
     170                 :     virtual size_t    Write( const void *pBuffer, size_t nSize, size_t nMemb );
     171                 :     virtual int       Eof();
     172                 :     virtual int       Flush();
     173                 :     virtual int       Close();
     174                 : 
     175                 :     VSIGZipHandle*    Duplicate();
     176                 :     void              CloseBaseHandle();
     177                 : 
     178             188 :     vsi_l_offset      GetLastReadOffset() { return nLastReadOffset; }
     179             580 :     const char*       GetBaseFileName() { return pszBaseFileName; }
     180                 : 
     181               0 :     void              SetUncompressedSize(vsi_l_offset nUncompressedSize) { uncompressed_size = nUncompressedSize; }
     182              10 :     vsi_l_offset      GetUncompressedSize() { return uncompressed_size; }
     183                 : };
     184                 : 
     185                 : 
     186                 : class VSIGZipFilesystemHandler : public VSIFilesystemHandler 
     187                 : {
     188                 :     void* hMutex;
     189                 :     VSIGZipHandle* poHandleLastGZipFile;
     190                 :     int            bInSaveInfo;
     191                 : 
     192                 : public:
     193                 :     VSIGZipFilesystemHandler();
     194                 :     ~VSIGZipFilesystemHandler();
     195                 : 
     196                 :     virtual VSIVirtualHandle *Open( const char *pszFilename, 
     197                 :                                     const char *pszAccess);
     198                 :     VSIGZipHandle *OpenGZipReadOnly( const char *pszFilename, 
     199                 :                                      const char *pszAccess);
     200                 :     virtual int      Stat( const char *pszFilename, VSIStatBufL *pStatBuf, int nFlags );
     201                 :     virtual int      Unlink( const char *pszFilename );
     202                 :     virtual int      Rename( const char *oldpath, const char *newpath );
     203                 :     virtual int      Mkdir( const char *pszDirname, long nMode );
     204                 :     virtual int      Rmdir( const char *pszDirname );
     205                 :     virtual char   **ReadDir( const char *pszDirname );
     206                 : 
     207                 :     void  SaveInfo( VSIGZipHandle* poHandle );
     208                 : };
     209                 : 
     210                 : 
     211                 : /************************************************************************/
     212                 : /*                            Duplicate()                               */
     213                 : /************************************************************************/
     214                 : 
     215              94 : VSIGZipHandle* VSIGZipHandle::Duplicate()
     216                 : {
     217              94 :     CPLAssert (offset == 0);
     218              94 :     CPLAssert (compressed_size != 0);
     219              94 :     CPLAssert (pszBaseFileName != NULL);
     220                 : 
     221                 :     VSIFilesystemHandler *poFSHandler = 
     222              94 :         VSIFileManager::GetHandler( pszBaseFileName );
     223                 : 
     224                 :     VSIVirtualHandle* poNewBaseHandle =
     225              94 :         poFSHandler->Open( pszBaseFileName, "rb" );
     226                 : 
     227              94 :     if (poNewBaseHandle == NULL)
     228               0 :         return NULL;
     229                 : 
     230                 :     VSIGZipHandle* poHandle = new VSIGZipHandle(poNewBaseHandle,
     231                 :                                                 pszBaseFileName,
     232                 :                                                 0,
     233                 :                                                 compressed_size,
     234              94 :                                                 uncompressed_size);
     235                 : 
     236              94 :     poHandle->nLastReadOffset = nLastReadOffset;
     237                 : 
     238                 :     /* Most important : duplicate the snapshots ! */
     239                 : 
     240                 :     unsigned int i;
     241             100 :     for(i=0;i<compressed_size / snapshot_byte_interval + 1;i++)
     242                 :     {
     243              94 :         if (snapshots[i].uncompressed_pos == 0)
     244              88 :             break;
     245                 : 
     246               6 :         poHandle->snapshots[i].uncompressed_pos = snapshots[i].uncompressed_pos;
     247               6 :         inflateCopy( &poHandle->snapshots[i].stream, &snapshots[i].stream);
     248               6 :         poHandle->snapshots[i].crc = snapshots[i].crc;
     249               6 :         poHandle->snapshots[i].transparent = snapshots[i].transparent;
     250               6 :         poHandle->snapshots[i].in = snapshots[i].in;
     251               6 :         poHandle->snapshots[i].out = snapshots[i].out;
     252                 :     }
     253                 : 
     254              94 :     return poHandle;
     255                 : }
     256                 : 
     257                 : /************************************************************************/
     258                 : /*                     CloseBaseHandle()                                */
     259                 : /************************************************************************/
     260                 : 
     261              22 : void  VSIGZipHandle::CloseBaseHandle()
     262                 : {
     263              22 :     if (poBaseHandle)
     264              22 :         VSIFCloseL((VSILFILE*)poBaseHandle);
     265              22 :     poBaseHandle = NULL;
     266              22 : }
     267                 : 
     268                 : /************************************************************************/
     269                 : /*                       VSIGZipHandle()                                */
     270                 : /************************************************************************/
     271                 : 
     272             514 : VSIGZipHandle::VSIGZipHandle(VSIVirtualHandle* poBaseHandle,
     273                 :                              const char* pszBaseFileName,
     274                 :                              vsi_l_offset offset,
     275                 :                              vsi_l_offset compressed_size,
     276                 :                              vsi_l_offset uncompressed_size,
     277                 :                              unsigned int expected_crc,
     278             514 :                              int transparent)
     279                 : {
     280             514 :     this->poBaseHandle = poBaseHandle;
     281             514 :     this->expected_crc = expected_crc;
     282             514 :     this->pszBaseFileName = (pszBaseFileName) ? CPLStrdup(pszBaseFileName) : NULL;
     283             514 :     this->offset = offset;
     284            1006 :     if (compressed_size || transparent)
     285                 :     {
     286             492 :         this->compressed_size = compressed_size;
     287                 :     }
     288                 :     else
     289                 :     {
     290              22 :         VSIFSeekL((VSILFILE*)poBaseHandle, 0, SEEK_END);
     291              22 :         this->compressed_size = VSIFTellL((VSILFILE*)poBaseHandle) - offset;
     292              22 :         compressed_size = this->compressed_size;
     293                 :     }
     294             514 :     this->uncompressed_size = uncompressed_size;
     295             514 :     offsetEndCompressedData = offset + compressed_size;
     296                 : 
     297             514 :     VSIFSeekL((VSILFILE*)poBaseHandle, offset, SEEK_SET);
     298                 : 
     299             514 :     nLastReadOffset = 0;
     300             514 :     stream.zalloc = (alloc_func)0;
     301             514 :     stream.zfree = (free_func)0;
     302             514 :     stream.opaque = (voidpf)0;
     303             514 :     stream.next_in = inbuf = Z_NULL;
     304             514 :     stream.next_out = outbuf = Z_NULL;
     305             514 :     stream.avail_in = stream.avail_out = 0;
     306             514 :     z_err = Z_OK;
     307             514 :     z_eof = 0;
     308             514 :     in = 0;
     309             514 :     out = 0;
     310             514 :     crc = crc32(0L, Z_NULL, 0);
     311             514 :     this->transparent = transparent;
     312                 : 
     313             514 :     stream.next_in  = inbuf = (Byte*)ALLOC(Z_BUFSIZE);
     314                 : 
     315             514 :     int err = inflateInit2(&(stream), -MAX_WBITS);
     316                 :     /* windowBits is passed < 0 to tell that there is no zlib header.
     317                 :         * Note that in this case inflate *requires* an extra "dummy" byte
     318                 :         * after the compressed stream in order to complete decompression and
     319                 :         * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
     320                 :         * present after the compressed stream.
     321                 :         */
     322             514 :     if (err != Z_OK || inbuf == Z_NULL) {
     323               0 :         CPLError(CE_Failure, CPLE_NotSupported, "inflateInit2 init failed");
     324                 :     }
     325             514 :     stream.avail_out = Z_BUFSIZE;
     326                 : 
     327             514 :     if (offset == 0) check_header(); /* skip the .gz header */
     328             514 :     startOff = VSIFTellL((VSILFILE*)poBaseHandle) - stream.avail_in;
     329                 : 
     330             514 :     if (transparent == 0)
     331                 :     {
     332             506 :         snapshot_byte_interval = MAX(Z_BUFSIZE, compressed_size / 100);
     333             506 :         snapshots = (GZipSnapshot*)CPLCalloc(sizeof(GZipSnapshot), (size_t) (compressed_size / snapshot_byte_interval + 1));
     334                 :     }
     335                 :     else
     336                 :     {
     337               8 :         snapshots = NULL;
     338                 :     }
     339             514 : }
     340                 : 
     341                 : /************************************************************************/
     342                 : /*                      ~VSIGZipHandle()                                */
     343                 : /************************************************************************/
     344                 : 
     345             514 : VSIGZipHandle::~VSIGZipHandle()
     346                 : {
     347                 :     
     348             514 :     if (pszBaseFileName)
     349                 :     {
     350                 :         VSIFilesystemHandler *poFSHandler = 
     351             116 :             VSIFileManager::GetHandler( "/vsigzip/" );
     352             116 :         ((VSIGZipFilesystemHandler*)poFSHandler)->SaveInfo(this);
     353                 :     }
     354                 :     
     355             514 :     if (stream.state != NULL) {
     356             514 :         inflateEnd(&(stream));
     357                 :     }
     358                 : 
     359             514 :     TRYFREE(inbuf);
     360             514 :     TRYFREE(outbuf);
     361                 : 
     362             514 :     if (snapshots != NULL)
     363                 :     {
     364                 :         unsigned int i;
     365            1064 :         for(i=0;i<compressed_size / snapshot_byte_interval + 1;i++)
     366                 :         {
     367             558 :             if (snapshots[i].uncompressed_pos)
     368                 :             {
     369             426 :                 inflateEnd(&(snapshots[i].stream));
     370                 :             }
     371                 :         }
     372             506 :         CPLFree(snapshots);
     373                 :     }
     374             514 :     CPLFree(pszBaseFileName);
     375                 : 
     376             514 :     if (poBaseHandle)
     377             492 :         VSIFCloseL((VSILFILE*)poBaseHandle);
     378             514 : }
     379                 : 
     380                 : /************************************************************************/
     381                 : /*                      check_header()                                  */
     382                 : /************************************************************************/
     383                 : 
     384             154 : void VSIGZipHandle::check_header()
     385                 : {
     386                 :     int method; /* method byte */
     387                 :     int flags;  /* flags byte */
     388                 :     uInt len;
     389                 :     int c;
     390                 : 
     391                 :     /* Assure two bytes in the buffer so we can peek ahead -- handle case
     392                 :     where first byte of header is at the end of the buffer after the last
     393                 :     gzip segment */
     394             154 :     len = stream.avail_in;
     395             154 :     if (len < 2) {
     396             154 :         if (len) inbuf[0] = stream.next_in[0];
     397             154 :         errno = 0;
     398             154 :         len = (uInt)VSIFReadL(inbuf + len, 1, Z_BUFSIZE >> len, (VSILFILE*)poBaseHandle);
     399                 :         if (ENABLE_DEBUG) CPLDebug("GZIP", CPL_FRMT_GUIB " " CPL_FRMT_GUIB,
     400                 :                                     VSIFTellL((VSILFILE*)poBaseHandle), offsetEndCompressedData);
     401             154 :         if (VSIFTellL((VSILFILE*)poBaseHandle) > offsetEndCompressedData)
     402                 :         {
     403               0 :             len = len + (uInt) (offsetEndCompressedData - VSIFTellL((VSILFILE*)poBaseHandle));
     404               0 :             VSIFSeekL((VSILFILE*)poBaseHandle, offsetEndCompressedData, SEEK_SET);
     405                 :         }
     406             154 :         if (len == 0 /* && ferror(file)*/)
     407                 :         {
     408              38 :             if (VSIFTellL((VSILFILE*)poBaseHandle) != offsetEndCompressedData)
     409               0 :                 z_err = Z_ERRNO;
     410                 :         }
     411             154 :         stream.avail_in += len;
     412             154 :         stream.next_in = inbuf;
     413             154 :         if (stream.avail_in < 2) {
     414              38 :             transparent = stream.avail_in;
     415              38 :             return;
     416                 :         }
     417                 :     }
     418                 : 
     419                 :     /* Peek ahead to check the gzip magic header */
     420             348 :     if (stream.next_in[0] != gz_magic[0] ||
     421             232 :         stream.next_in[1] != gz_magic[1]) {
     422               0 :         transparent = 1;
     423               0 :         return;
     424                 :     }
     425             116 :     stream.avail_in -= 2;
     426             116 :     stream.next_in += 2;
     427                 : 
     428                 :     /* Check the rest of the gzip header */
     429             116 :     method = get_byte();
     430             116 :     flags = get_byte();
     431             116 :     if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
     432               0 :         z_err = Z_DATA_ERROR;
     433               0 :         return;
     434                 :     }
     435                 : 
     436                 :     /* Discard time, xflags and OS code: */
     437             116 :     for (len = 0; len < 6; len++) (void)get_byte();
     438                 : 
     439             116 :     if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
     440               0 :         len  =  (uInt)get_byte();
     441               0 :         len += ((uInt)get_byte())<<8;
     442                 :         /* len is garbage if EOF but the loop below will quit anyway */
     443               0 :         while (len-- != 0 && get_byte() != EOF) ;
     444                 :     }
     445             116 :     if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
     446               0 :         while ((c = get_byte()) != 0 && c != EOF) ;
     447                 :     }
     448             116 :     if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
     449               0 :         while ((c = get_byte()) != 0 && c != EOF) ;
     450                 :     }
     451             116 :     if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
     452               0 :         for (len = 0; len < 2; len++) (void)get_byte();
     453                 :     }
     454             116 :     z_err = z_eof ? Z_DATA_ERROR : Z_OK;
     455                 : }
     456                 : 
     457                 : /************************************************************************/
     458                 : /*                            get_byte()                                */
     459                 : /************************************************************************/
     460                 : 
     461            1232 : int VSIGZipHandle::get_byte()
     462                 : {
     463            1232 :     if (z_eof) return EOF;
     464            1232 :     if (stream.avail_in == 0) {
     465               0 :         errno = 0;
     466               0 :         stream.avail_in = (uInt)VSIFReadL(inbuf, 1, Z_BUFSIZE, (VSILFILE*)poBaseHandle);
     467                 :         if (ENABLE_DEBUG) CPLDebug("GZIP", CPL_FRMT_GUIB " " CPL_FRMT_GUIB,
     468                 :                                    VSIFTellL((VSILFILE*)poBaseHandle), offsetEndCompressedData);
     469               0 :         if (VSIFTellL((VSILFILE*)poBaseHandle) > offsetEndCompressedData)
     470                 :         {
     471               0 :             stream.avail_in = stream.avail_in + (uInt) (offsetEndCompressedData - VSIFTellL((VSILFILE*)poBaseHandle));
     472               0 :             VSIFSeekL((VSILFILE*)poBaseHandle, offsetEndCompressedData, SEEK_SET);
     473                 :         }
     474               0 :         if (stream.avail_in == 0) {
     475               0 :             z_eof = 1;
     476               0 :             if (VSIFTellL((VSILFILE*)poBaseHandle) != offsetEndCompressedData)
     477               0 :                 z_err = Z_ERRNO;
     478                 :             /*if (ferror(file)) z_err = Z_ERRNO;*/
     479               0 :             return EOF;
     480                 :         }
     481               0 :         stream.next_in = inbuf;
     482                 :     }
     483            1232 :     stream.avail_in--;
     484            1232 :     return *(stream.next_in)++;
     485                 : }
     486                 : 
     487                 : /************************************************************************/
     488                 : /*                            gzrewind()                                */
     489                 : /************************************************************************/
     490                 : 
     491             180 : int VSIGZipHandle::gzrewind ()
     492                 : {
     493             180 :     z_err = Z_OK;
     494             180 :     z_eof = 0;
     495             180 :     stream.avail_in = 0;
     496             180 :     stream.next_in = inbuf;
     497             180 :     crc = crc32(0L, Z_NULL, 0);
     498             180 :     if (!transparent) (void)inflateReset(&stream);
     499             180 :     in = 0;
     500             180 :     out = 0;
     501             180 :     return VSIFSeekL((VSILFILE*)poBaseHandle, startOff, SEEK_SET);
     502                 : }
     503                 : 
     504                 : /************************************************************************/
     505                 : /*                              Seek()                                  */
     506                 : /************************************************************************/
     507                 : 
     508             984 : int VSIGZipHandle::Seek( vsi_l_offset nOffset, int nWhence )
     509                 : {
     510                 :     /* The semantics of gzseek is different from ::Seek */
     511                 :     /* It returns the current offset, where as ::Seek shoud return 0 */
     512                 :     /* if successfull */
     513             984 :     int ret = gzseek(nOffset, nWhence);
     514             984 :     return (ret >= 0) ? 0 : ret;
     515                 : }
     516                 : 
     517                 : /************************************************************************/
     518                 : /*                            gzseek()                                  */
     519                 : /************************************************************************/
     520                 : 
     521             984 : int VSIGZipHandle::gzseek( vsi_l_offset offset, int whence )
     522                 : {
     523             984 :     vsi_l_offset original_offset = offset;
     524             984 :     int original_nWhence = whence;
     525                 : 
     526                 :     if (ENABLE_DEBUG) CPLDebug("GZIP", "Seek(" CPL_FRMT_GUIB ",%d)", offset, whence);
     527                 : 
     528             984 :     if (transparent)
     529                 :     {
     530               6 :         stream.avail_in = 0;
     531               6 :         stream.next_in = inbuf;
     532               6 :         if (whence == SEEK_CUR)
     533                 :         {
     534               0 :             if (out + offset > compressed_size)
     535                 :             {
     536               0 :                 CPL_VSIL_GZ_RETURN_MINUS_ONE();
     537               0 :                 return -1L;
     538                 :             }
     539                 : 
     540               0 :             offset = startOff + out + offset;
     541                 :         }
     542               6 :         else if (whence == SEEK_SET)
     543                 :         {
     544               4 :             if (offset > compressed_size)
     545                 :             {
     546               0 :                 CPL_VSIL_GZ_RETURN_MINUS_ONE();
     547               0 :                 return -1L;
     548                 :             }
     549                 : 
     550               4 :             offset = startOff + offset;
     551                 :         }
     552               2 :         else if (whence == SEEK_END)
     553                 :         {
     554                 :             /* Commented test : because vsi_l_offset is unsigned (for the moment) */
     555                 :             /* so no way to seek backward. See #1590 */
     556               2 :             if (offset > 0 /*|| -offset > compressed_size*/)
     557                 :             {
     558               0 :                 CPL_VSIL_GZ_RETURN_MINUS_ONE();
     559               0 :                 return -1L;
     560                 :             }
     561                 : 
     562               2 :             offset = startOff + compressed_size - offset;
     563                 :         }
     564                 :         else
     565                 :         {
     566               0 :             CPL_VSIL_GZ_RETURN_MINUS_ONE();
     567               0 :             return -1L;
     568                 :         }
     569               6 :         if (VSIFSeekL((VSILFILE*)poBaseHandle, offset, SEEK_SET) < 0)
     570                 :         {
     571               0 :             CPL_VSIL_GZ_RETURN_MINUS_ONE();
     572               0 :             return -1L;
     573                 :         }
     574                 : 
     575               6 :         in = out = offset - startOff;
     576                 :         if (ENABLE_DEBUG) CPLDebug("GZIP", "return " CPL_FRMT_GUIB, in);
     577               6 :         return (int) in;
     578                 :     }
     579                 : 
     580                 :     /* whence == SEEK_END is unsuppored in original gzseek. */
     581             978 :     if (whence == SEEK_END)
     582                 :     {
     583                 :         /* If we known the uncompressed size, we can fake a jump to */
     584                 :         /* the end of the stream */
     585             108 :         if (offset == 0 && uncompressed_size != 0)
     586                 :         {
     587              96 :             out = uncompressed_size;
     588              96 :             return 1;
     589                 :         }
     590                 : 
     591                 :         /* We don't know the uncompressed size. This is unfortunate. Let's do the slow version... */
     592                 :         static int firstWarning = 1;
     593              12 :         if (compressed_size > 10 * 1024 * 1024 && firstWarning)
     594                 :         {
     595                 :             CPLError(CE_Warning, CPLE_AppDefined,
     596               0 :                         "VSIFSeekL(xxx, SEEK_END) may be really slow on GZip streams.");
     597               0 :             firstWarning = 0;
     598                 :         }
     599                 :         
     600              12 :         whence = SEEK_CUR;
     601              12 :         offset = 1024 * 1024 * 1024;
     602              12 :         offset *= 1024 * 1024;
     603                 :     }
     604                 : 
     605             882 :     if (/*whence == SEEK_END ||*/
     606                 :         z_err == Z_ERRNO || z_err == Z_DATA_ERROR) {
     607               0 :         CPL_VSIL_GZ_RETURN_MINUS_ONE();
     608               0 :         return -1L;
     609                 :     }
     610                 : 
     611                 :     /* Rest of function is for reading only */
     612                 : 
     613                 :     /* compute absolute position */
     614             882 :     if (whence == SEEK_CUR) {
     615              12 :         offset += out;
     616                 :     }
     617                 : 
     618                 :     /* For a negative seek, rewind and use positive seek */
     619             882 :     if (offset >= out) {
     620             702 :         offset -= out;
     621             180 :     } else if (gzrewind() < 0) {
     622               0 :             CPL_VSIL_GZ_RETURN_MINUS_ONE();
     623               0 :             return -1L;
     624                 :     }
     625                 :     
     626                 :     unsigned int i;
     627             890 :     for(i=0;i<compressed_size / snapshot_byte_interval + 1;i++)
     628                 :     {
     629             890 :         if (snapshots[i].uncompressed_pos == 0)
     630             738 :             break;
     631             198 :         if (snapshots[i].out <= out + offset &&
     632              46 :             (i == compressed_size / snapshot_byte_interval || snapshots[i+1].out == 0 || snapshots[i+1].out > out+offset))
     633                 :         {
     634             144 :             if (out >= snapshots[i].out)
     635             144 :                 break;
     636                 : 
     637                 :             if (ENABLE_DEBUG)
     638                 :                 CPLDebug("SNAPSHOT", "using snapshot %d : uncompressed_pos(snapshot)=" CPL_FRMT_GUIB
     639                 :                                                         " in(snapshot)=" CPL_FRMT_GUIB
     640                 :                                                         " out(snapshot)=" CPL_FRMT_GUIB
     641                 :                                                         " out=" CPL_FRMT_GUIB
     642                 :                                                         " offset=" CPL_FRMT_GUIB,
     643                 :                          i, snapshots[i].uncompressed_pos, snapshots[i].in, snapshots[i].out, out, offset);
     644               0 :             offset = out + offset - snapshots[i].out;
     645               0 :             VSIFSeekL((VSILFILE*)poBaseHandle, snapshots[i].uncompressed_pos, SEEK_SET);
     646               0 :             inflateEnd(&stream);
     647               0 :             inflateCopy(&stream, &snapshots[i].stream);
     648               0 :             crc = snapshots[i].crc;
     649               0 :             transparent = snapshots[i].transparent;
     650               0 :             in = snapshots[i].in;
     651               0 :             out = snapshots[i].out;
     652               0 :             break;
     653                 :         }
     654                 :     }
     655                 : 
     656                 :     /* offset is now the number of bytes to skip. */
     657                 : 
     658             882 :     if (offset != 0 && outbuf == Z_NULL) {
     659              82 :         outbuf = (Byte*)ALLOC(Z_BUFSIZE);
     660              82 :         if (outbuf == Z_NULL) {
     661               0 :             CPL_VSIL_GZ_RETURN_MINUS_ONE();
     662               0 :             return -1L;
     663                 :         }
     664                 :     }
     665                 : 
     666             882 :     if (original_nWhence == SEEK_END && z_err == Z_STREAM_END)
     667                 :     {
     668                 :         if (ENABLE_DEBUG) CPLDebug("GZIP", "gzseek return " CPL_FRMT_GUIB, out);
     669               2 :         return (int) out;
     670                 :     }
     671                 : 
     672            2164 :     while (offset > 0)  {
     673             416 :         int size = Z_BUFSIZE;
     674             416 :         if (offset < Z_BUFSIZE) size = (int)offset;
     675                 : 
     676             416 :         int read_size = Read(outbuf, 1, (uInt)size);
     677             416 :         if (read_size == 0) {
     678                 :             //CPL_VSIL_GZ_RETURN_MINUS_ONE();
     679               2 :             return -1L;
     680                 :         }
     681             414 :         if (original_nWhence == SEEK_END)
     682                 :         {
     683              10 :             if (size != read_size)
     684                 :             {
     685              10 :                 z_err = Z_STREAM_END;
     686              10 :                 break;
     687                 :             }
     688                 :         }
     689             404 :         offset -= read_size;
     690                 :     }
     691                 :     if (ENABLE_DEBUG) CPLDebug("GZIP", "gzseek return " CPL_FRMT_GUIB, out);
     692                 : 
     693             878 :     if (original_offset == 0 && original_nWhence == SEEK_END)
     694                 :     {
     695              10 :         uncompressed_size = out;
     696                 : 
     697              10 :         if (pszBaseFileName)
     698                 :         {
     699              10 :             CPLString osCacheFilename (pszBaseFileName);
     700              10 :             osCacheFilename += ".properties";
     701                 : 
     702                 :             /* Write a .properties file to avoid seeking next time */
     703              10 :             VSILFILE* fpCacheLength = VSIFOpenL(osCacheFilename.c_str(), "wb");
     704              10 :             if (fpCacheLength)
     705                 :             {
     706                 :                 char* pszFirstNonSpace;
     707                 :                 char szBuffer[32];
     708              10 :                 szBuffer[31] = 0;
     709                 : 
     710              10 :                 CPLPrintUIntBig(szBuffer, compressed_size, 31);
     711              10 :                 pszFirstNonSpace = szBuffer;
     712              10 :                 while (*pszFirstNonSpace == ' ') pszFirstNonSpace ++;
     713              10 :                 VSIFPrintfL(fpCacheLength, "compressed_size=%s\n", pszFirstNonSpace);
     714                 : 
     715              10 :                 CPLPrintUIntBig(szBuffer, uncompressed_size, 31);
     716              10 :                 pszFirstNonSpace = szBuffer;
     717              10 :                 while (*pszFirstNonSpace == ' ') pszFirstNonSpace ++;
     718              10 :                 VSIFPrintfL(fpCacheLength, "uncompressed_size=%s\n", pszFirstNonSpace);
     719                 : 
     720              10 :                 VSIFCloseL(fpCacheLength);
     721              10 :             }
     722                 :         }
     723                 :     }
     724                 : 
     725             878 :     return (int) out;
     726                 : }
     727                 : 
     728                 : /************************************************************************/
     729                 : /*                              Tell()                                  */
     730                 : /************************************************************************/
     731                 : 
     732             110 : vsi_l_offset VSIGZipHandle::Tell()
     733                 : {
     734                 :     if (ENABLE_DEBUG) CPLDebug("GZIP", "Tell() = " CPL_FRMT_GUIB, out);
     735             110 :     return out;
     736                 : }
     737                 : 
     738                 : /************************************************************************/
     739                 : /*                              Read()                                  */
     740                 : /************************************************************************/
     741                 : 
     742            3902 : size_t VSIGZipHandle::Read( void *buf, size_t nSize, size_t nMemb )
     743                 : {
     744                 :     if (ENABLE_DEBUG) CPLDebug("GZIP", "Read(%p, %d, %d)", buf, (int)nSize, (int)nMemb);
     745                 : 
     746            3902 :     unsigned len = nSize * nMemb;
     747                 : 
     748            3902 :     Bytef *pStart = (Bytef*)buf; /* startOffing point for crc computation */
     749                 :     Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
     750                 : 
     751            3902 :     if  (z_err == Z_DATA_ERROR || z_err == Z_ERRNO)
     752                 :     {
     753               0 :         CPL_VSIL_GZ_RETURN_MINUS_ONE();
     754               0 :         return 0;
     755                 :     }
     756            3902 :     if  (z_err == Z_STREAM_END)
     757                 :     {
     758                 :         if (ENABLE_DEBUG) CPLDebug("GZIP", "Read: Eof");
     759              14 :         return 0;  /* EOF */
     760                 :     }
     761                 : 
     762            3888 :     next_out = (Byte*)buf;
     763            3888 :     stream.next_out = (Bytef*)buf;
     764            3888 :     stream.avail_out = len;
     765                 : 
     766           11282 :     while  (stream.avail_out != 0) {
     767                 : 
     768            3892 :         if  (transparent) {
     769                 :             /* Copy first the lookahead bytes: */
     770               4 :             uInt nRead = 0;
     771               4 :             uInt n = stream.avail_in;
     772               4 :             if (n > stream.avail_out) n = stream.avail_out;
     773               4 :             if (n > 0) {
     774               0 :                 memcpy (stream.next_out, stream.next_in, n);
     775               0 :                 next_out += n;
     776               0 :                 stream.next_out = next_out;
     777               0 :                 stream.next_in   += n;
     778               0 :                 stream.avail_out -= n;
     779               0 :                 stream.avail_in  -= n;
     780               0 :                 nRead += n;
     781                 :             }
     782               4 :             if  (stream.avail_out > 0) {
     783               4 :                 uInt nToRead = (uInt) MIN(compressed_size - (in + nRead), stream.avail_out);
     784                 :                 uInt nReadFromFile =
     785               4 :                     (uInt)VSIFReadL(next_out, 1, nToRead, (VSILFILE*)poBaseHandle);
     786               4 :                 stream.avail_out -= nReadFromFile;
     787               4 :                 nRead += nReadFromFile;
     788                 :             }
     789               4 :             in  += nRead;
     790               4 :             out += nRead;
     791               4 :             if (nRead < len) z_eof = 1;
     792                 :             if (ENABLE_DEBUG) CPLDebug("GZIP", "Read return %d", (int)(nRead / nSize));
     793               4 :             return (int)nRead / nSize;
     794                 :         }
     795            3888 :         if  (stream.avail_in == 0 && !z_eof)
     796                 :         {
     797             498 :             vsi_l_offset uncompressed_pos = VSIFTellL((VSILFILE*)poBaseHandle);
     798             498 :             GZipSnapshot* snapshot = &snapshots[(uncompressed_pos - startOff) / snapshot_byte_interval];
     799             498 :             if (snapshot->uncompressed_pos == 0)
     800                 :             {
     801             420 :                 snapshot->crc = crc32 (crc, pStart, (uInt) (stream.next_out - pStart));
     802                 :                 if (ENABLE_DEBUG)
     803                 :                     CPLDebug("SNAPSHOT",
     804                 :                              "creating snapshot %d : uncompressed_pos=" CPL_FRMT_GUIB
     805                 :                                                    " in=" CPL_FRMT_GUIB
     806                 :                                                    " out=" CPL_FRMT_GUIB
     807                 :                                                    " crc=%X",
     808                 :                           (int)((uncompressed_pos - startOff) / snapshot_byte_interval),
     809                 :                           uncompressed_pos, in, out, (unsigned int)snapshot->crc);
     810             420 :                 snapshot->uncompressed_pos = uncompressed_pos;
     811             420 :                 inflateCopy(&snapshot->stream, &stream);
     812             420 :                 snapshot->transparent = transparent;
     813             420 :                 snapshot->in = in;
     814             420 :                 snapshot->out = out;
     815                 : 
     816             420 :                 if (out > nLastReadOffset)
     817               2 :                     nLastReadOffset = out;
     818                 :             }
     819                 : 
     820             498 :             errno = 0;
     821             498 :             stream.avail_in = (uInt)VSIFReadL(inbuf, 1, Z_BUFSIZE, (VSILFILE*)poBaseHandle);
     822                 :             if (ENABLE_DEBUG)
     823                 :                 CPLDebug("GZIP", CPL_FRMT_GUIB " " CPL_FRMT_GUIB,
     824                 :                                  VSIFTellL((VSILFILE*)poBaseHandle), offsetEndCompressedData);
     825             498 :             if (VSIFTellL((VSILFILE*)poBaseHandle) > offsetEndCompressedData)
     826                 :             {
     827                 :                 if (ENABLE_DEBUG) CPLDebug("GZIP", "avail_in before = %d", stream.avail_in);
     828             438 :                 stream.avail_in = stream.avail_in + (uInt) (offsetEndCompressedData - VSIFTellL((VSILFILE*)poBaseHandle));
     829             438 :                 VSIFSeekL((VSILFILE*)poBaseHandle, offsetEndCompressedData, SEEK_SET);
     830             438 :                 if (ENABLE_DEBUG) CPLDebug("GZIP", "avail_in after = %d", stream.avail_in);
     831                 :             }
     832             498 :             if  (stream.avail_in == 0) {
     833               0 :                 z_eof = 1;
     834               0 :                 if (VSIFTellL((VSILFILE*)poBaseHandle) != offsetEndCompressedData)
     835                 :                 {
     836               0 :                     z_err = Z_ERRNO;
     837               0 :                     break;
     838                 :                 }
     839                 :                 /*if (ferror (file)) {
     840                 :                     z_err = Z_ERRNO;
     841                 :                     break;
     842                 :                 }*/
     843                 :             }
     844             498 :             stream.next_in = inbuf;
     845                 :         }
     846            3888 :         in += stream.avail_in;
     847            3888 :         out += stream.avail_out;
     848            3888 :         z_err = inflate(& (stream), Z_NO_FLUSH);
     849            3888 :         in -= stream.avail_in;
     850            3888 :         out -= stream.avail_out;
     851                 : 
     852            3888 :         if  (z_err == Z_STREAM_END && compressed_size != 2 ) {
     853                 :             /* Check CRC and original size */
     854             382 :             crc = crc32 (crc, pStart, (uInt) (stream.next_out - pStart));
     855             382 :             pStart = stream.next_out;
     856             382 :             if (expected_crc)
     857                 :             {
     858             344 :                 if (ENABLE_DEBUG) CPLDebug("GZIP", "Computed CRC = %X. Expected CRC = %X", (unsigned int)crc, expected_crc);
     859                 :             }
     860             382 :             if (expected_crc != 0 && expected_crc != crc)
     861                 :             {
     862               0 :                 CPLError(CE_Failure, CPLE_FileIO, "CRC error. Got %X instead of %X", (unsigned int)crc, expected_crc);
     863               0 :                 z_err = Z_DATA_ERROR;
     864                 :             }
     865             382 :             else if (expected_crc == 0)
     866                 :             {
     867              38 :                 unsigned int read_crc = getLong();
     868              38 :                 if (read_crc != crc)
     869                 :                 {
     870               0 :                     CPLError(CE_Failure, CPLE_FileIO, "CRC error. Got %X instead of %X", (unsigned int)crc, read_crc);
     871               0 :                     z_err = Z_DATA_ERROR;
     872                 :                 }
     873                 :                 else
     874                 :                 {
     875              38 :                     (void)getLong();
     876                 :                     /* The uncompressed length returned by above getlong() may be
     877                 :                     * different from out in case of concatenated .gz files.
     878                 :                     * Check for such files:
     879                 :                     */
     880              38 :                     check_header();
     881              38 :                     if  (z_err == Z_OK) {
     882               0 :                         inflateReset(& (stream));
     883               0 :                         crc = crc32(0L, Z_NULL, 0);
     884                 :                     }
     885                 :                 }
     886                 :             }
     887                 :         }
     888            3888 :         if  (z_err != Z_OK || z_eof) break;
     889                 :     }
     890            3884 :     crc = crc32 (crc, pStart, (uInt) (stream.next_out - pStart));
     891                 : 
     892            3884 :     if (len == stream.avail_out &&
     893                 :             (z_err == Z_DATA_ERROR || z_err == Z_ERRNO))
     894                 :     {
     895               0 :         CPL_VSIL_GZ_RETURN_MINUS_ONE();
     896               0 :         return 0;
     897                 :     }
     898                 :     if (ENABLE_DEBUG)
     899                 :         CPLDebug("GZIP", "Read return %d (z_err=%d, z_eof=%d)",
     900                 :                 (int)((len - stream.avail_out) / nSize), z_err, z_eof);
     901            3884 :     return (int)(len - stream.avail_out) / nSize;
     902                 : }
     903                 : 
     904                 : /************************************************************************/
     905                 : /*                              getLong()                               */
     906                 : /************************************************************************/
     907                 : 
     908              76 : uLong VSIGZipHandle::getLong ()
     909                 : {
     910              76 :     uLong x = (uLong)get_byte();
     911                 :     int c;
     912                 : 
     913              76 :     x += ((uLong)get_byte())<<8;
     914              76 :     x += ((uLong)get_byte())<<16;
     915              76 :     c = get_byte();
     916              76 :     if (c == EOF) z_err = Z_DATA_ERROR;
     917              76 :     x += ((uLong)c)<<24;
     918              76 :     return x;
     919                 : }
     920                 : 
     921                 : /************************************************************************/
     922                 : /*                              Write()                                 */
     923                 : /************************************************************************/
     924                 : 
     925               0 : size_t VSIGZipHandle::Write( const void *pBuffer, size_t nSize, size_t nMemb )
     926                 : {
     927               0 :     CPLError(CE_Failure, CPLE_NotSupported, "VSIFWriteL is not supported on GZip streams");
     928               0 :     return 0;
     929                 : }
     930                 : 
     931                 : /************************************************************************/
     932                 : /*                               Eof()                                  */
     933                 : /************************************************************************/
     934                 : 
     935                 : 
     936            3486 : int VSIGZipHandle::Eof()
     937                 : {
     938                 :     if (ENABLE_DEBUG) CPLDebug("GZIP", "Eof()");
     939            3486 :     if (z_eof) return 1;
     940            3482 :     return z_err == Z_STREAM_END;
     941                 : }
     942                 : 
     943                 : /************************************************************************/
     944                 : /*                              Flush()                                 */
     945                 : /************************************************************************/
     946                 : 
     947               0 : int VSIGZipHandle::Flush()
     948                 : {
     949               0 :     return 0;
     950                 : }
     951                 : 
     952                 : /************************************************************************/
     953                 : /*                              Close()                                 */
     954                 : /************************************************************************/
     955                 : 
     956             492 : int VSIGZipHandle::Close()
     957                 : {
     958             492 :     return 0;
     959                 : }
     960                 : 
     961                 : 
     962                 : /************************************************************************/
     963                 : /* ==================================================================== */
     964                 : /*                       VSIGZipWriteHandle                             */
     965                 : /* ==================================================================== */
     966                 : /************************************************************************/
     967                 : 
     968                 : class VSIGZipWriteHandle : public VSIVirtualHandle
     969                 : {
     970                 :     VSIVirtualHandle*  poBaseHandle;
     971                 :     z_stream           sStream;
     972                 :     Byte              *pabyInBuf;
     973                 :     Byte              *pabyOutBuf;
     974                 :     bool               bCompressActive;
     975                 :     vsi_l_offset       nCurOffset;
     976                 :     GUInt32            nCRC;
     977                 :     int                bRegularZLib;
     978                 :     int                bAutoCloseBaseHandle;
     979                 : 
     980                 :   public:
     981                 : 
     982                 :     VSIGZipWriteHandle(VSIVirtualHandle* poBaseHandle, int bRegularZLib, int bAutoCloseBaseHandleIn);
     983                 : 
     984                 :     ~VSIGZipWriteHandle();
     985                 : 
     986                 :     virtual int       Seek( vsi_l_offset nOffset, int nWhence );
     987                 :     virtual vsi_l_offset Tell();
     988                 :     virtual size_t    Read( void *pBuffer, size_t nSize, size_t nMemb );
     989                 :     virtual size_t    Write( const void *pBuffer, size_t nSize, size_t nMemb );
     990                 :     virtual int       Eof();
     991                 :     virtual int       Flush();
     992                 :     virtual int       Close();
     993                 : };
     994                 : 
     995                 : /************************************************************************/
     996                 : /*                         VSIGZipWriteHandle()                         */
     997                 : /************************************************************************/
     998                 : 
     999             264 : VSIGZipWriteHandle::VSIGZipWriteHandle( VSIVirtualHandle *poBaseHandle,
    1000                 :                                         int bRegularZLibIn,
    1001             264 :                                         int bAutoCloseBaseHandleIn )
    1002                 : 
    1003                 : {
    1004             264 :     nCurOffset = 0;
    1005                 : 
    1006             264 :     this->poBaseHandle = poBaseHandle;
    1007             264 :     bRegularZLib = bRegularZLibIn;
    1008             264 :     bAutoCloseBaseHandle = bAutoCloseBaseHandleIn;
    1009                 : 
    1010             264 :     nCRC = crc32(0L, Z_NULL, 0);
    1011             264 :     sStream.zalloc = (alloc_func)0;
    1012             264 :     sStream.zfree = (free_func)0;
    1013             264 :     sStream.opaque = (voidpf)0;
    1014             264 :     sStream.next_in = Z_NULL;
    1015             264 :     sStream.next_out = Z_NULL;
    1016             264 :     sStream.avail_in = sStream.avail_out = 0;
    1017                 : 
    1018             264 :     pabyInBuf = (Byte *) CPLMalloc( Z_BUFSIZE );
    1019             264 :     sStream.next_in  = pabyInBuf;
    1020                 : 
    1021             264 :     pabyOutBuf = (Byte *) CPLMalloc( Z_BUFSIZE );
    1022                 : 
    1023             264 :     if( deflateInit2( &sStream, Z_DEFAULT_COMPRESSION,
    1024                 :                       Z_DEFLATED, (bRegularZLib) ? MAX_WBITS : -MAX_WBITS, 8,
    1025                 :                       Z_DEFAULT_STRATEGY ) != Z_OK )
    1026               0 :         bCompressActive = false;
    1027                 :     else
    1028                 :     {
    1029             264 :         if (!bRegularZLib)
    1030                 :         {
    1031                 :             char header[11];
    1032                 : 
    1033                 :             /* Write a very simple .gz header:
    1034                 :             */
    1035              48 :             sprintf( header, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
    1036                 :                     Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/,
    1037              48 :                     0x03 );
    1038              48 :             poBaseHandle->Write( header, 1, 10 );
    1039                 :         }
    1040                 : 
    1041             264 :         bCompressActive = true;
    1042                 :     }
    1043             264 : }
    1044                 : 
    1045                 : /************************************************************************/
    1046                 : /*                       VSICreateGZipWritable()                        */
    1047                 : /************************************************************************/
    1048                 : 
    1049             216 : VSIVirtualHandle* VSICreateGZipWritable( VSIVirtualHandle* poBaseHandle,
    1050                 :                                          int bRegularZLibIn,
    1051                 :                                          int bAutoCloseBaseHandle )
    1052                 : {
    1053             216 :     return new VSIGZipWriteHandle( poBaseHandle, bRegularZLibIn, bAutoCloseBaseHandle );
    1054                 : }
    1055                 : 
    1056                 : /************************************************************************/
    1057                 : /*                        ~VSIGZipWriteHandle()                         */
    1058                 : /************************************************************************/
    1059                 : 
    1060             264 : VSIGZipWriteHandle::~VSIGZipWriteHandle()
    1061                 : 
    1062                 : {
    1063             264 :     if( bCompressActive )
    1064               0 :         Close();
    1065                 : 
    1066             264 :     CPLFree( pabyInBuf );
    1067             264 :     CPLFree( pabyOutBuf );
    1068             264 : }
    1069                 : 
    1070                 : /************************************************************************/
    1071                 : /*                               Close()                                */
    1072                 : /************************************************************************/
    1073                 : 
    1074             264 : int VSIGZipWriteHandle::Close()
    1075                 : 
    1076                 : {
    1077             264 :     if( bCompressActive )
    1078                 :     {
    1079             264 :         sStream.next_out = pabyOutBuf;
    1080             264 :         sStream.avail_out = Z_BUFSIZE;
    1081                 : 
    1082             264 :         deflate( &sStream, Z_FINISH );
    1083                 : 
    1084             264 :         size_t nOutBytes = Z_BUFSIZE - sStream.avail_out;
    1085                 : 
    1086             264 :         if( poBaseHandle->Write( pabyOutBuf, 1, nOutBytes ) < nOutBytes )
    1087               0 :             return EOF;
    1088                 : 
    1089             264 :         deflateEnd( &sStream );
    1090                 : 
    1091             264 :         if( !bRegularZLib )
    1092                 :         {
    1093                 :             GUInt32 anTrailer[2];
    1094                 : 
    1095              48 :             anTrailer[0] = CPL_LSBWORD32( nCRC );
    1096              48 :             anTrailer[1] = CPL_LSBWORD32( (GUInt32) nCurOffset );
    1097                 : 
    1098              48 :             poBaseHandle->Write( anTrailer, 1, 8 );
    1099                 :         }
    1100                 : 
    1101             264 :         if( bAutoCloseBaseHandle )
    1102                 :         {
    1103              48 :             poBaseHandle->Close();
    1104                 : 
    1105              48 :             delete poBaseHandle;
    1106                 :         }
    1107                 : 
    1108             264 :         bCompressActive = false;
    1109                 :     }
    1110                 : 
    1111             264 :     return 0;
    1112                 : }
    1113                 : 
    1114                 : /************************************************************************/
    1115                 : /*                                Read()                                */
    1116                 : /************************************************************************/
    1117                 : 
    1118               0 : size_t VSIGZipWriteHandle::Read( void *pBuffer, size_t nSize, size_t nMemb )
    1119                 : 
    1120                 : {
    1121               0 :     CPLError(CE_Failure, CPLE_NotSupported, "VSIFReadL is not supported on GZip write streams\n");
    1122               0 :     return 0;
    1123                 : }
    1124                 : 
    1125                 : /************************************************************************/
    1126                 : /*                               Write()                                */
    1127                 : /************************************************************************/
    1128                 : 
    1129           15842 : size_t VSIGZipWriteHandle::Write( const void *pBuffer, 
    1130                 :                                   size_t nSize, size_t nMemb )
    1131                 : 
    1132                 : {
    1133                 :     int  nBytesToWrite, nNextByte;
    1134                 : 
    1135           15842 :     nBytesToWrite = (int) (nSize * nMemb);
    1136           15842 :     nNextByte = 0;
    1137                 : 
    1138           15842 :     nCRC = crc32(nCRC, (const Bytef *)pBuffer, nBytesToWrite);
    1139                 : 
    1140           15842 :     if( !bCompressActive )
    1141               0 :         return 0;
    1142                 : 
    1143           47526 :     while( nNextByte < nBytesToWrite )
    1144                 :     {
    1145           15842 :         sStream.next_out = pabyOutBuf;
    1146           15842 :         sStream.avail_out = Z_BUFSIZE;
    1147                 : 
    1148           15842 :         if( sStream.avail_in > 0 )
    1149               0 :             memmove( pabyInBuf, sStream.next_in, sStream.avail_in );
    1150                 : 
    1151           15842 :         int nNewBytesToWrite = MIN((int) (Z_BUFSIZE-sStream.avail_in),
    1152                 :                                    nBytesToWrite - nNextByte);
    1153                 :         memcpy( pabyInBuf + sStream.avail_in, 
    1154                 :                 ((Byte *) pBuffer) + nNextByte, 
    1155           15842 :                 nNewBytesToWrite );
    1156                 :         
    1157           15842 :         sStream.next_in = pabyInBuf;
    1158           15842 :         sStream.avail_in += nNewBytesToWrite;
    1159                 : 
    1160           15842 :         deflate( &sStream, Z_NO_FLUSH );
    1161                 : 
    1162           15842 :         size_t nOutBytes = Z_BUFSIZE - sStream.avail_out;
    1163                 : 
    1164           15842 :         if( nOutBytes > 0 )
    1165                 :         {
    1166             250 :             if( poBaseHandle->Write( pabyOutBuf, 1, nOutBytes ) < nOutBytes )
    1167               0 :                 return 0;
    1168                 :         }
    1169                 : 
    1170           15842 :         nNextByte += nNewBytesToWrite;
    1171           15842 :         nCurOffset += nNewBytesToWrite;
    1172                 :     }
    1173                 : 
    1174           15842 :     return nMemb;
    1175                 : }
    1176                 : 
    1177                 : /************************************************************************/
    1178                 : /*                               Flush()                                */
    1179                 : /************************************************************************/
    1180                 : 
    1181               0 : int VSIGZipWriteHandle::Flush()
    1182                 : 
    1183                 : {
    1184                 :     // we *could* do something for this but for now we choose not to.
    1185                 : 
    1186               0 :     return 0;
    1187                 : }
    1188                 : 
    1189                 : /************************************************************************/
    1190                 : /*                                Eof()                                 */
    1191                 : /************************************************************************/
    1192                 : 
    1193               0 : int VSIGZipWriteHandle::Eof()
    1194                 : 
    1195                 : {
    1196               0 :     return 1;
    1197                 : }
    1198                 : 
    1199                 : /************************************************************************/
    1200                 : /*                                Seek()                                */
    1201                 : /************************************************************************/
    1202                 : 
    1203               0 : int VSIGZipWriteHandle::Seek( vsi_l_offset nOffset, int nWhence )
    1204                 : 
    1205                 : {
    1206               0 :     if( nOffset == 0 && (nWhence == SEEK_END || nWhence == SEEK_CUR) )
    1207               0 :         return 0;
    1208               0 :     else if( nWhence == SEEK_SET && nOffset == nCurOffset )
    1209               0 :         return 0;
    1210                 :     else
    1211                 :     {
    1212                 :         CPLError(CE_Failure, CPLE_NotSupported,
    1213               0 :                  "Seeking on writable compressed data streams not supported." );
    1214                 :                
    1215               0 :         return -1;
    1216                 :     }
    1217                 : }
    1218                 : 
    1219                 : /************************************************************************/
    1220                 : /*                                Tell()                                */
    1221                 : /************************************************************************/
    1222                 : 
    1223               0 : vsi_l_offset VSIGZipWriteHandle::Tell()
    1224                 : 
    1225                 : {
    1226               0 :     return nCurOffset;
    1227                 : }
    1228                 : 
    1229                 : 
    1230                 : /************************************************************************/
    1231                 : /* ==================================================================== */
    1232                 : /*                       VSIGZipFilesystemHandler                       */
    1233                 : /* ==================================================================== */
    1234                 : /************************************************************************/
    1235                 : 
    1236                 : 
    1237                 : /************************************************************************/
    1238                 : /*                   VSIGZipFilesystemHandler()                         */
    1239                 : /************************************************************************/
    1240                 : 
    1241            1341 : VSIGZipFilesystemHandler::VSIGZipFilesystemHandler()
    1242                 : {
    1243            1341 :     hMutex = NULL;
    1244                 : 
    1245            1341 :     poHandleLastGZipFile = NULL;
    1246            1341 :     bInSaveInfo = FALSE;
    1247            1341 : }
    1248                 : 
    1249                 : /************************************************************************/
    1250                 : /*                  ~VSIGZipFilesystemHandler()                         */
    1251                 : /************************************************************************/
    1252                 : 
    1253            1297 : VSIGZipFilesystemHandler::~VSIGZipFilesystemHandler()
    1254                 : {
    1255            1297 :     if (poHandleLastGZipFile)
    1256               2 :         delete poHandleLastGZipFile;
    1257                 : 
    1258            1297 :     if( hMutex != NULL )
    1259               2 :         CPLDestroyMutex( hMutex );
    1260            1297 :     hMutex = NULL;
    1261            1297 : }
    1262                 : 
    1263                 : /************************************************************************/
    1264                 : /*                            SaveInfo()                                */
    1265                 : /************************************************************************/
    1266                 : 
    1267             116 : void VSIGZipFilesystemHandler::SaveInfo(  VSIGZipHandle* poHandle )
    1268                 : {
    1269             116 :     CPLMutexHolder oHolder(&hMutex);
    1270                 : 
    1271             116 :     if (bInSaveInfo)
    1272                 :         return;
    1273             116 :     bInSaveInfo = TRUE;
    1274                 :     
    1275             116 :     CPLAssert(poHandle->GetBaseFileName() != NULL);
    1276                 : 
    1277             116 :     if (poHandleLastGZipFile &&
    1278                 :         strcmp(poHandleLastGZipFile->GetBaseFileName(), poHandle->GetBaseFileName()) == 0)
    1279                 :     {
    1280              94 :         if (poHandle->GetLastReadOffset() > poHandleLastGZipFile->GetLastReadOffset())
    1281                 :         {
    1282               0 :             VSIGZipHandle* poTmp = poHandleLastGZipFile;
    1283               0 :             poHandleLastGZipFile = NULL;
    1284               0 :             delete poTmp;
    1285               0 :             poHandleLastGZipFile = poHandle->Duplicate();
    1286               0 :             poHandleLastGZipFile->CloseBaseHandle();
    1287                 :         }
    1288                 :     }
    1289                 :     else
    1290                 :     {
    1291              22 :         VSIGZipHandle* poTmp = poHandleLastGZipFile;
    1292              22 :         poHandleLastGZipFile = NULL;
    1293              22 :         delete poTmp;
    1294              22 :         poHandleLastGZipFile = poHandle->Duplicate();
    1295              22 :         poHandleLastGZipFile->CloseBaseHandle();
    1296                 :     }
    1297                 : 
    1298             116 :     bInSaveInfo = FALSE;
    1299                 : }
    1300                 : 
    1301                 : /************************************************************************/
    1302                 : /*                                Open()                                */
    1303                 : /************************************************************************/
    1304                 : 
    1305             242 : VSIVirtualHandle* VSIGZipFilesystemHandler::Open( const char *pszFilename, 
    1306                 :                                                   const char *pszAccess)
    1307                 : {
    1308                 :     VSIFilesystemHandler *poFSHandler = 
    1309             242 :         VSIFileManager::GetHandler( pszFilename + strlen("/vsigzip/"));
    1310                 : 
    1311                 : /* -------------------------------------------------------------------- */
    1312                 : /*      Is this an attempt to write a new file without update (w+)      */
    1313                 : /*      access?  If so, create a writable handle for the underlying     */
    1314                 : /*      filename.                                                       */
    1315                 : /* -------------------------------------------------------------------- */
    1316             242 :     if (strchr(pszAccess, 'w') != NULL )
    1317                 :     {
    1318              52 :         if( strchr(pszAccess, '+') != NULL )
    1319                 :         {
    1320                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1321               0 :                      "Write+update (w+) not supported for /vsigzip, only read-only or write-only.");
    1322               0 :             return NULL;
    1323                 :         }
    1324                 : 
    1325                 :         VSIVirtualHandle* poVirtualHandle =
    1326              52 :             poFSHandler->Open( pszFilename + strlen("/vsigzip/"), "wb" );
    1327                 : 
    1328              52 :         if (poVirtualHandle == NULL)
    1329               4 :             return NULL;
    1330                 : 
    1331                 :         else
    1332              48 :             return new VSIGZipWriteHandle( poVirtualHandle, strchr(pszAccess, 'z') != NULL, TRUE );
    1333                 :     }
    1334                 : 
    1335                 : /* -------------------------------------------------------------------- */
    1336                 : /*      Otherwise we are in the read access case.                       */
    1337                 : /* -------------------------------------------------------------------- */
    1338                 : 
    1339             190 :     VSIGZipHandle* poGZIPHandle = OpenGZipReadOnly(pszFilename, pszAccess);
    1340             190 :     if (poGZIPHandle)
    1341                 :         /* Wrap the VSIGZipHandle inside a buffered reader that will */
    1342                 :         /* improve dramatically performance when doing small backward */
    1343                 :         /* seeks */
    1344              94 :         return VSICreateBufferedReaderHandle(poGZIPHandle);
    1345                 :     else
    1346              96 :         return NULL;
    1347                 : }
    1348                 : 
    1349                 : /************************************************************************/
    1350                 : /*                          OpenGZipReadOnly()                          */
    1351                 : /************************************************************************/
    1352                 : 
    1353             190 : VSIGZipHandle* VSIGZipFilesystemHandler::OpenGZipReadOnly( const char *pszFilename, 
    1354                 :                                                       const char *pszAccess)
    1355                 : {
    1356                 :     VSIFilesystemHandler *poFSHandler = 
    1357             190 :         VSIFileManager::GetHandler( pszFilename + strlen("/vsigzip/"));
    1358                 : 
    1359             190 :     CPLMutexHolder oHolder(&hMutex);
    1360                 : 
    1361             190 :     if (poHandleLastGZipFile != NULL &&
    1362                 :         strcmp(pszFilename + strlen("/vsigzip/"), poHandleLastGZipFile->GetBaseFileName()) == 0 &&
    1363                 :         EQUAL(pszAccess, "rb"))
    1364                 :     {
    1365              72 :         VSIGZipHandle* poHandle = poHandleLastGZipFile->Duplicate();
    1366              72 :         if (poHandle)
    1367              72 :             return poHandle;
    1368                 :     }
    1369                 : 
    1370                 :     unsigned char signature[2];
    1371                 : 
    1372                 :     VSIVirtualHandle* poVirtualHandle =
    1373             118 :         poFSHandler->Open( pszFilename + strlen("/vsigzip/"), "rb" );
    1374                 : 
    1375             118 :     if (poVirtualHandle == NULL)
    1376              96 :         return NULL;
    1377                 : 
    1378              22 :     if (VSIFReadL(signature, 1, 2, (VSILFILE*)poVirtualHandle) != 2)
    1379               0 :         return NULL;
    1380                 : 
    1381              22 :     if (signature[0] != gz_magic[0] || signature[1] != gz_magic[1])
    1382               0 :         return NULL;
    1383                 : 
    1384              22 :     if (poHandleLastGZipFile)
    1385              20 :         delete poHandleLastGZipFile;
    1386              22 :     poHandleLastGZipFile = NULL;
    1387                 : 
    1388              22 :     return new VSIGZipHandle(poVirtualHandle, pszFilename + strlen("/vsigzip/"));
    1389                 : }
    1390                 : 
    1391                 : /************************************************************************/
    1392                 : /*                                Stat()                                */
    1393                 : /************************************************************************/
    1394                 : 
    1395              88 : int VSIGZipFilesystemHandler::Stat( const char *pszFilename,
    1396                 :                                     VSIStatBufL *pStatBuf,
    1397                 :                                     int nFlags )
    1398                 : {
    1399              88 :     CPLMutexHolder oHolder(&hMutex);
    1400                 : 
    1401              88 :     memset(pStatBuf, 0, sizeof(VSIStatBufL));
    1402                 : 
    1403              88 :     if (poHandleLastGZipFile != NULL &&
    1404                 :         strcmp(pszFilename+strlen("/vsigzip/"), poHandleLastGZipFile->GetBaseFileName()) == 0)
    1405                 :     {
    1406              10 :         if (poHandleLastGZipFile->GetUncompressedSize() != 0)
    1407                 :         {
    1408               0 :             pStatBuf->st_mode = S_IFREG;
    1409               0 :             pStatBuf->st_size = poHandleLastGZipFile->GetUncompressedSize();
    1410               0 :             return 0;
    1411                 :         }
    1412                 :     }
    1413                 : 
    1414                 :     /* Begin by doing a stat on the real file */
    1415              88 :     int ret = VSIStatExL(pszFilename+strlen("/vsigzip/"), pStatBuf, nFlags);
    1416                 : 
    1417              88 :     if (ret == 0 && (nFlags & VSI_STAT_SIZE_FLAG))
    1418                 :     {
    1419               0 :         CPLString osCacheFilename(pszFilename+strlen("/vsigzip/"));
    1420               0 :         osCacheFilename += ".properties";
    1421                 : 
    1422                 :         /* Can we save a bit of seeking by using a .properties file ? */
    1423               0 :         VSILFILE* fpCacheLength = VSIFOpenL(osCacheFilename.c_str(), "rb");
    1424               0 :         if (fpCacheLength)
    1425                 :         {
    1426                 :             const char* pszLine;
    1427               0 :             GUIntBig nCompressedSize = 0;
    1428               0 :             GUIntBig nUncompressedSize = 0;
    1429               0 :             while ((pszLine = CPLReadLineL(fpCacheLength)) != NULL)
    1430                 :             {
    1431               0 :                 if (EQUALN(pszLine, "compressed_size=", strlen("compressed_size=")))
    1432                 :                 {
    1433               0 :                     const char* pszBuffer = pszLine + strlen("compressed_size=");
    1434                 :                     nCompressedSize = 
    1435               0 :                             CPLScanUIntBig(pszBuffer, strlen(pszBuffer));
    1436                 :                 }
    1437               0 :                 else if (EQUALN(pszLine, "uncompressed_size=", strlen("uncompressed_size=")))
    1438                 :                 {
    1439               0 :                     const char* pszBuffer = pszLine + strlen("uncompressed_size=");
    1440                 :                     nUncompressedSize =
    1441               0 :                              CPLScanUIntBig(pszBuffer, strlen(pszBuffer));
    1442                 :                 }
    1443                 :             }
    1444                 : 
    1445               0 :             VSIFCloseL(fpCacheLength);
    1446                 : 
    1447               0 :             if (nCompressedSize == (GUIntBig) pStatBuf->st_size)
    1448                 :             {
    1449                 :                 /* Patch with the uncompressed size */
    1450               0 :                 pStatBuf->st_size = (long)nUncompressedSize;
    1451                 : 
    1452                 :                 VSIGZipHandle* poHandle =
    1453               0 :                     VSIGZipFilesystemHandler::OpenGZipReadOnly(pszFilename, "rb");
    1454               0 :                 if (poHandle)
    1455                 :                 {
    1456               0 :                     poHandle->SetUncompressedSize(nUncompressedSize);
    1457               0 :                     SaveInfo(poHandle);
    1458               0 :                     delete poHandle;
    1459                 :                 }
    1460                 : 
    1461               0 :                 return ret;
    1462                 :             }
    1463                 :         }
    1464                 : 
    1465                 :         /* No, then seek at the end of the data (slow) */
    1466                 :         VSIGZipHandle* poHandle =
    1467               0 :                 VSIGZipFilesystemHandler::OpenGZipReadOnly(pszFilename, "rb");
    1468               0 :         if (poHandle)
    1469                 :         {
    1470                 :             GUIntBig uncompressed_size;
    1471               0 :             poHandle->Seek(0, SEEK_END);
    1472               0 :             uncompressed_size = (GUIntBig) poHandle->Tell();
    1473               0 :             poHandle->Seek(0, SEEK_SET);
    1474                 : 
    1475                 :             /* Patch with the uncompressed size */
    1476               0 :             pStatBuf->st_size = (long)uncompressed_size;
    1477                 : 
    1478               0 :             delete poHandle;
    1479                 :         }
    1480                 :         else
    1481                 :         {
    1482               0 :             ret = -1;
    1483               0 :         }
    1484                 :     }
    1485                 : 
    1486              88 :     return ret;
    1487                 : }
    1488                 : 
    1489                 : /************************************************************************/
    1490                 : /*                               Unlink()                               */
    1491                 : /************************************************************************/
    1492                 : 
    1493               0 : int VSIGZipFilesystemHandler::Unlink( const char *pszFilename )
    1494                 : {
    1495               0 :     return -1;
    1496                 : }
    1497                 : 
    1498                 : /************************************************************************/
    1499                 : /*                               Rename()                               */
    1500                 : /************************************************************************/
    1501                 : 
    1502               0 : int VSIGZipFilesystemHandler::Rename( const char *oldpath, const char *newpath )
    1503                 : {
    1504               0 :     return -1;
    1505                 : }
    1506                 : 
    1507                 : /************************************************************************/
    1508                 : /*                               Mkdir()                                */
    1509                 : /************************************************************************/
    1510                 : 
    1511               0 : int VSIGZipFilesystemHandler::Mkdir( const char *pszDirname, long nMode )
    1512                 : {
    1513               0 :     return -1;
    1514                 : }
    1515                 : /************************************************************************/
    1516                 : /*                               Rmdir()                                */
    1517                 : /************************************************************************/
    1518                 : 
    1519               0 : int VSIGZipFilesystemHandler::Rmdir( const char *pszDirname )
    1520                 : {
    1521               0 :     return -1;
    1522                 : }
    1523                 : 
    1524                 : /************************************************************************/
    1525                 : /*                             ReadDir()                                */
    1526                 : /************************************************************************/
    1527                 : 
    1528              10 : char** VSIGZipFilesystemHandler::ReadDir( const char *pszDirname )
    1529                 : {
    1530              10 :     return NULL;
    1531                 : }
    1532                 : 
    1533                 : /************************************************************************/
    1534                 : /*                   VSIInstallGZipFileHandler()                        */
    1535                 : /************************************************************************/
    1536                 : 
    1537                 : 
    1538                 : /**
    1539                 :  * \brief Install GZip file system handler. 
    1540                 :  *
    1541                 :  * A special file handler is installed that allows reading on-the-fly and 
    1542                 :  * writing in GZip (.gz) files.
    1543                 :  *
    1544                 :  * All portions of the file system underneath the base
    1545                 :  * path "/vsigzip/" will be handled by this driver.
    1546                 :  *
    1547                 :  * Additional documentation is to be found at http://trac.osgeo.org/gdal/wiki/UserDocs/ReadInZip
    1548                 :  *
    1549                 :  * @since GDAL 1.6.0
    1550                 :  */
    1551                 : 
    1552            1341 : void VSIInstallGZipFileHandler(void)
    1553                 : {
    1554            1341 :     VSIFileManager::InstallHandler( "/vsigzip/", new VSIGZipFilesystemHandler );
    1555            1341 : }
    1556                 : 
    1557                 : 
    1558                 : /************************************************************************/
    1559                 : /* ==================================================================== */
    1560                 : /*                         VSIZipEntryFileOffset                        */
    1561                 : /* ==================================================================== */
    1562                 : /************************************************************************/
    1563                 : 
    1564                 : class VSIZipEntryFileOffset : public VSIArchiveEntryFileOffset
    1565            4758 : {
    1566                 : public:
    1567                 :         unz_file_pos file_pos;
    1568                 : 
    1569            4758 :         VSIZipEntryFileOffset(unz_file_pos file_pos)
    1570            4758 :         {
    1571            4758 :             this->file_pos.pos_in_zip_directory = file_pos.pos_in_zip_directory;
    1572            4758 :             this->file_pos.num_of_file = file_pos.num_of_file;
    1573            4758 :         }
    1574                 : };
    1575                 : 
    1576                 : /************************************************************************/
    1577                 : /* ==================================================================== */
    1578                 : /*                             VSIZipReader                             */
    1579                 : /* ==================================================================== */
    1580                 : /************************************************************************/
    1581                 : 
    1582                 : class VSIZipReader : public VSIArchiveReader
    1583                 : {
    1584                 :     private:
    1585                 :         unzFile unzF;
    1586                 :         unz_file_pos file_pos;
    1587                 :         GUIntBig nNextFileSize;
    1588                 :         CPLString osNextFileName;
    1589                 :         GIntBig nModifiedTime;
    1590                 : 
    1591                 :         void SetInfo();
    1592                 : 
    1593                 :     public:
    1594                 :         VSIZipReader(const char* pszZipFileName);
    1595                 :         virtual ~VSIZipReader();
    1596                 : 
    1597             526 :         int IsValid() { return unzF != NULL; }
    1598                 : 
    1599             398 :         unzFile GetUnzFileHandle() { return unzF; }
    1600                 : 
    1601                 :         virtual int GotoFirstFile();
    1602                 :         virtual int GotoNextFile();
    1603            4758 :         virtual VSIArchiveEntryFileOffset* GetFileOffset() { return new VSIZipEntryFileOffset(file_pos); }
    1604            4764 :         virtual GUIntBig GetFileSize() { return nNextFileSize; }
    1605            4788 :         virtual CPLString GetFileName() { return osNextFileName; }
    1606            5544 :         virtual GIntBig GetModifiedTime() { return nModifiedTime; }
    1607                 :         virtual int GotoFileOffset(VSIArchiveEntryFileOffset* pOffset);
    1608                 : };
    1609                 : 
    1610                 : 
    1611                 : /************************************************************************/
    1612                 : /*                           VSIZipReader()                             */
    1613                 : /************************************************************************/
    1614                 : 
    1615             526 : VSIZipReader::VSIZipReader(const char* pszZipFileName)
    1616                 : {
    1617             526 :     unzF = cpl_unzOpen(pszZipFileName);
    1618             526 :     nNextFileSize = 0;
    1619             526 :     nModifiedTime = 0;
    1620             526 : }
    1621                 : 
    1622                 : /************************************************************************/
    1623                 : /*                          ~VSIZipReader()                             */
    1624                 : /************************************************************************/
    1625                 : 
    1626             526 : VSIZipReader::~VSIZipReader()
    1627                 : {
    1628             526 :     if (unzF)
    1629             514 :         cpl_unzClose(unzF);
    1630             526 : }
    1631                 : 
    1632                 : /************************************************************************/
    1633                 : /*                              SetInfo()                               */
    1634                 : /************************************************************************/
    1635                 : 
    1636            5698 : void VSIZipReader::SetInfo()
    1637                 : {
    1638                 :     char fileName[512];
    1639                 :     unz_file_info file_info;
    1640            5698 :     cpl_unzGetCurrentFileInfo (unzF, &file_info, fileName, 512, NULL, 0, NULL, 0);
    1641            5698 :     osNextFileName = fileName;
    1642            5698 :     nNextFileSize = file_info.uncompressed_size;
    1643                 :     struct tm brokendowntime;
    1644            5698 :     brokendowntime.tm_sec = file_info.tmu_date.tm_sec;
    1645            5698 :     brokendowntime.tm_min = file_info.tmu_date.tm_min;
    1646            5698 :     brokendowntime.tm_hour = file_info.tmu_date.tm_hour;
    1647            5698 :     brokendowntime.tm_mday = file_info.tmu_date.tm_mday;
    1648            5698 :     brokendowntime.tm_mon = file_info.tmu_date.tm_mon;
    1649            5698 :     brokendowntime.tm_year = file_info.tmu_date.tm_year - 1900; /* the minizip conventions differs from the Unix one */
    1650            5698 :     nModifiedTime = CPLYMDHMSToUnixTime(&brokendowntime);
    1651                 : 
    1652            5698 :     cpl_unzGetFilePos(unzF, &this->file_pos);
    1653            5698 : }
    1654                 : 
    1655                 : /************************************************************************/
    1656                 : /*                           GotoNextFile()                             */
    1657                 : /************************************************************************/
    1658                 : 
    1659            4794 : int VSIZipReader::GotoNextFile()
    1660                 : {
    1661            4794 :     if (cpl_unzGoToNextFile(unzF) != UNZ_OK)
    1662              88 :         return FALSE;
    1663                 : 
    1664            4706 :     SetInfo();
    1665                 : 
    1666            4706 :     return TRUE;
    1667                 : }
    1668                 : 
    1669                 : /************************************************************************/
    1670                 : /*                          GotoFirstFile()                             */
    1671                 : /************************************************************************/
    1672                 : 
    1673             610 : int VSIZipReader::GotoFirstFile()
    1674                 : {
    1675             610 :     if (cpl_unzGoToFirstFile(unzF) != UNZ_OK)
    1676               0 :         return FALSE;
    1677                 : 
    1678             610 :     SetInfo();
    1679                 : 
    1680             610 :     return TRUE;
    1681                 : }
    1682                 : 
    1683                 : /************************************************************************/
    1684                 : /*                         GotoFileOffset()                             */
    1685                 : /************************************************************************/
    1686                 : 
    1687             382 : int VSIZipReader::GotoFileOffset(VSIArchiveEntryFileOffset* pOffset)
    1688                 : {
    1689             382 :     VSIZipEntryFileOffset* pZipEntryOffset = (VSIZipEntryFileOffset*)pOffset;
    1690             382 :     cpl_unzGoToFilePos(unzF, &(pZipEntryOffset->file_pos));
    1691                 : 
    1692             382 :     SetInfo();
    1693                 : 
    1694             382 :     return TRUE;
    1695                 : }
    1696                 : 
    1697                 : /************************************************************************/
    1698                 : /* ==================================================================== */
    1699                 : /*                       VSIZipFilesystemHandler                  */
    1700                 : /* ==================================================================== */
    1701                 : /************************************************************************/
    1702                 : 
    1703                 : class VSIZipWriteHandle;
    1704                 : 
    1705                 : class VSIZipFilesystemHandler : public VSIArchiveFilesystemHandler 
    1706            1341 : {
    1707                 :     std::map<CPLString, VSIZipWriteHandle*> oMapZipWriteHandles;
    1708                 : 
    1709                 : public:
    1710                 :     virtual ~VSIZipFilesystemHandler();
    1711                 :     
    1712            9120 :     virtual const char* GetPrefix() { return "/vsizip"; }
    1713                 :     virtual std::vector<CPLString> GetExtensions();
    1714                 :     virtual VSIArchiveReader* CreateReader(const char* pszZipFileName);
    1715                 : 
    1716                 :     virtual VSIVirtualHandle *Open( const char *pszFilename, 
    1717                 :                                     const char *pszAccess);
    1718                 : 
    1719                 :     virtual VSIVirtualHandle *OpenForWrite( const char *pszFilename,
    1720                 :                                             const char *pszAccess );
    1721                 : 
    1722                 :     virtual int      Mkdir( const char *pszDirname, long nMode );
    1723                 :     virtual char   **ReadDir( const char *pszDirname );
    1724                 :     virtual int      Stat( const char *pszFilename, VSIStatBufL *pStatBuf, int nFlags );
    1725                 : 
    1726                 :     void RemoveFromMap(VSIZipWriteHandle* poHandle);
    1727                 : };
    1728                 : 
    1729                 : /************************************************************************/
    1730                 : /* ==================================================================== */
    1731                 : /*                       VSIZipWriteHandle                              */
    1732                 : /* ==================================================================== */
    1733                 : /************************************************************************/
    1734                 : 
    1735                 : class VSIZipWriteHandle : public VSIVirtualHandle
    1736                 : {
    1737                 :    VSIZipFilesystemHandler *poFS;
    1738                 :    void                    *hZIP;
    1739                 :    VSIZipWriteHandle       *poChildInWriting;
    1740                 :    VSIZipWriteHandle       *poParent;
    1741                 :    int                      bAutoDeleteParent;
    1742                 : 
    1743                 :   public:
    1744                 : 
    1745                 :     VSIZipWriteHandle(VSIZipFilesystemHandler* poFS,
    1746                 :                       void *hZIP,
    1747                 :                       VSIZipWriteHandle* poParent);
    1748                 : 
    1749                 :     ~VSIZipWriteHandle();
    1750                 : 
    1751                 :     virtual int       Seek( vsi_l_offset nOffset, int nWhence );
    1752                 :     virtual vsi_l_offset Tell();
    1753                 :     virtual size_t    Read( void *pBuffer, size_t nSize, size_t nMemb );
    1754                 :     virtual size_t    Write( const void *pBuffer, size_t nSize, size_t nMemb );
    1755                 :     virtual int       Eof();
    1756                 :     virtual int       Flush();
    1757                 :     virtual int       Close();
    1758                 : 
    1759                 :     void  StartNewFile(VSIZipWriteHandle* poSubFile);
    1760                 :     void  StopCurrentFile();
    1761             102 :     void* GetHandle() { return hZIP; }
    1762             104 :     VSIZipWriteHandle* GetChildInWriting() { return poChildInWriting; };
    1763              26 :     void SetAutoDeleteParent() { bAutoDeleteParent = TRUE; }
    1764                 : };
    1765                 : 
    1766                 : /************************************************************************/
    1767                 : /*                      ~VSIZipFilesystemHandler()                      */
    1768                 : /************************************************************************/
    1769                 : 
    1770            1297 : VSIZipFilesystemHandler::~VSIZipFilesystemHandler()
    1771                 : {
    1772            1297 :     std::map<CPLString,VSIZipWriteHandle*>::const_iterator iter;
    1773                 : 
    1774            1297 :     for( iter = oMapZipWriteHandles.begin(); iter != oMapZipWriteHandles.end(); ++iter )
    1775                 :     {
    1776                 :         CPLError(CE_Failure, CPLE_AppDefined, "%s has not been closed",
    1777               0 :                  iter->first.c_str());
    1778                 :     }
    1779            1297 : }
    1780                 : 
    1781                 : /************************************************************************/
    1782                 : /*                          GetExtensions()                             */
    1783                 : /************************************************************************/
    1784                 : 
    1785           45198 : std::vector<CPLString> VSIZipFilesystemHandler::GetExtensions()
    1786                 : {
    1787           45198 :     std::vector<CPLString> oList;
    1788           45198 :     oList.push_back(".zip");
    1789           45198 :     oList.push_back(".kmz");
    1790           45198 :     oList.push_back(".dwf");
    1791           45198 :     oList.push_back(".ods");
    1792           45198 :     oList.push_back(".xlsx");
    1793               0 :     return oList;
    1794                 : }
    1795                 : 
    1796                 : /************************************************************************/
    1797                 : /*                           CreateReader()                             */
    1798                 : /************************************************************************/
    1799                 : 
    1800             526 : VSIArchiveReader* VSIZipFilesystemHandler::CreateReader(const char* pszZipFileName)
    1801                 : {
    1802             526 :     VSIZipReader* poReader = new VSIZipReader(pszZipFileName);
    1803                 : 
    1804             526 :     if (!poReader->IsValid())
    1805                 :     {
    1806              12 :         delete poReader;
    1807              12 :         return NULL;
    1808                 :     }
    1809                 : 
    1810             514 :     if (!poReader->GotoFirstFile())
    1811                 :     {
    1812               0 :         delete poReader;
    1813               0 :         return NULL;
    1814                 :     }
    1815                 : 
    1816             514 :     return poReader;
    1817                 : }
    1818                 : 
    1819                 : /************************************************************************/
    1820                 : /*                                 Open()                               */
    1821                 : /************************************************************************/
    1822                 : 
    1823             606 : VSIVirtualHandle* VSIZipFilesystemHandler::Open( const char *pszFilename, 
    1824                 :                                                  const char *pszAccess)
    1825                 : {
    1826                 :     char* zipFilename;
    1827             606 :     CPLString osZipInFileName;
    1828                 : 
    1829             606 :     if (strchr(pszAccess, 'w') != NULL)
    1830                 :     {
    1831             110 :         return OpenForWrite(pszFilename, pszAccess);
    1832                 :     }
    1833                 : 
    1834             496 :     if (strchr(pszAccess, '+') != NULL)
    1835                 :     {
    1836                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1837               0 :                  "Random access not supported for /vsizip");
    1838               0 :         return NULL;
    1839                 :     }
    1840                 : 
    1841             496 :     zipFilename = SplitFilename(pszFilename, osZipInFileName, TRUE);
    1842             496 :     if (zipFilename == NULL)
    1843              48 :         return NULL;
    1844                 : 
    1845                 :     {
    1846             448 :         CPLMutexHolder oHolder(&hMutex);
    1847             448 :         if (oMapZipWriteHandles.find(zipFilename) != oMapZipWriteHandles.end() )
    1848                 :         {
    1849                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1850               2 :                     "Cannot read a zip file being written");
    1851               2 :             CPLFree(zipFilename);
    1852               2 :             return NULL;
    1853               0 :         }
    1854                 :     }
    1855                 : 
    1856             446 :     VSIArchiveReader* poReader = OpenArchiveFile(zipFilename, osZipInFileName);
    1857             446 :     if (poReader == NULL)
    1858                 :     {
    1859              48 :         CPLFree(zipFilename);
    1860              48 :         return NULL;
    1861                 :     }
    1862                 : 
    1863                 :     VSIFilesystemHandler *poFSHandler = 
    1864             398 :         VSIFileManager::GetHandler( zipFilename);
    1865                 : 
    1866                 :     VSIVirtualHandle* poVirtualHandle =
    1867             398 :         poFSHandler->Open( zipFilename, "rb" );
    1868                 : 
    1869             398 :     CPLFree(zipFilename);
    1870             398 :     zipFilename = NULL;
    1871                 : 
    1872             398 :     if (poVirtualHandle == NULL)
    1873                 :     {
    1874               0 :         delete poReader;
    1875               0 :         return NULL;
    1876                 :     }
    1877                 : 
    1878             398 :     unzFile unzF = ((VSIZipReader*)poReader)->GetUnzFileHandle();
    1879                 : 
    1880             398 :     cpl_unzOpenCurrentFile(unzF);
    1881                 : 
    1882             398 :     uLong64 pos = cpl_unzGetCurrentFileZStreamPos(unzF);
    1883                 : 
    1884                 :     unz_file_info file_info;
    1885             398 :     cpl_unzGetCurrentFileInfo (unzF, &file_info, NULL, 0, NULL, 0, NULL, 0);
    1886                 : 
    1887             398 :     cpl_unzCloseCurrentFile(unzF);
    1888                 : 
    1889             398 :     delete poReader;
    1890                 : 
    1891                 :     VSIGZipHandle* poGZIPHandle = new VSIGZipHandle(poVirtualHandle,
    1892                 :                              NULL,
    1893                 :                              pos,
    1894                 :                              file_info.compressed_size,
    1895                 :                              file_info.uncompressed_size,
    1896                 :                              file_info.crc,
    1897             398 :                              file_info.compression_method == 0);
    1898                 :     /* Wrap the VSIGZipHandle inside a buffered reader that will */
    1899                 :     /* improve dramatically performance when doing small backward */
    1900                 :     /* seeks */
    1901             796 :     return VSICreateBufferedReaderHandle(poGZIPHandle);
    1902                 : }
    1903                 : 
    1904                 : /************************************************************************/
    1905                 : /*                                Mkdir()                               */
    1906                 : /************************************************************************/
    1907                 : 
    1908               2 : int VSIZipFilesystemHandler::Mkdir( const char *pszDirname, long nMode )
    1909                 : {
    1910               2 :     CPLString osDirname = pszDirname;
    1911               2 :     if (osDirname.size() != 0 && osDirname[osDirname.size() - 1] != '/')
    1912               2 :         osDirname += "/";
    1913               2 :     VSIVirtualHandle* poZIPHandle = OpenForWrite(osDirname, "wb");
    1914               2 :     if (poZIPHandle == NULL)
    1915               0 :         return -1;
    1916               2 :     delete poZIPHandle;
    1917               2 :     return 0;
    1918                 : }
    1919                 : 
    1920                 : /************************************************************************/
    1921                 : /*                                ReadDir()                             */
    1922                 : /************************************************************************/
    1923                 : 
    1924            1098 : char **VSIZipFilesystemHandler::ReadDir( const char *pszDirname )
    1925                 : {
    1926            1098 :     CPLString osInArchiveSubDir;
    1927            1098 :     char* zipFilename = SplitFilename(pszDirname, osInArchiveSubDir, TRUE);
    1928            1098 :     if (zipFilename == NULL)
    1929               6 :         return NULL;
    1930                 : 
    1931                 :     {
    1932            1092 :         CPLMutexHolder oHolder(&hMutex);
    1933                 : 
    1934            1092 :         if (oMapZipWriteHandles.find(zipFilename) != oMapZipWriteHandles.end() )
    1935                 :         {
    1936                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1937               2 :                     "Cannot read a zip file being written");
    1938               2 :             CPLFree(zipFilename);
    1939               2 :             return NULL;
    1940               0 :         }
    1941                 :     }
    1942            1090 :     CPLFree(zipFilename);
    1943                 : 
    1944            1090 :     return VSIArchiveFilesystemHandler::ReadDir(pszDirname);
    1945                 : }
    1946                 : 
    1947                 : 
    1948                 : /************************************************************************/
    1949                 : /*                                 Stat()                               */
    1950                 : /************************************************************************/
    1951                 : 
    1952             116 : int VSIZipFilesystemHandler::Stat( const char *pszFilename,
    1953                 :                                    VSIStatBufL *pStatBuf, int nFlags )
    1954                 : {
    1955             116 :     CPLString osInArchiveSubDir;
    1956                 : 
    1957             116 :     memset(pStatBuf, 0, sizeof(VSIStatBufL));
    1958                 : 
    1959             116 :     char* zipFilename = SplitFilename(pszFilename, osInArchiveSubDir, TRUE);
    1960             116 :     if (zipFilename == NULL)
    1961              14 :         return -1;
    1962                 : 
    1963                 :     {
    1964             102 :         CPLMutexHolder oHolder(&hMutex);
    1965                 : 
    1966             102 :         if (oMapZipWriteHandles.find(zipFilename) != oMapZipWriteHandles.end() )
    1967                 :         {
    1968                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1969               0 :                     "Cannot read a zip file being written");
    1970               0 :             CPLFree(zipFilename);
    1971               0 :             return -1;
    1972               0 :         }
    1973                 :     }
    1974             102 :     CPLFree(zipFilename);
    1975                 : 
    1976             102 :     return VSIArchiveFilesystemHandler::Stat(pszFilename, pStatBuf, nFlags);
    1977                 : }
    1978                 : 
    1979                 : /************************************************************************/
    1980                 : /*                             RemoveFromMap()                           */
    1981                 : /************************************************************************/
    1982                 : 
    1983              34 : void VSIZipFilesystemHandler::RemoveFromMap(VSIZipWriteHandle* poHandle)
    1984                 : {
    1985              34 :     CPLMutexHolder oHolder( &hMutex );
    1986              34 :     std::map<CPLString,VSIZipWriteHandle*>::iterator iter;
    1987                 : 
    1988              34 :     for( iter = oMapZipWriteHandles.begin();
    1989                 :          iter != oMapZipWriteHandles.end(); ++iter )
    1990                 :     {
    1991              34 :         if (iter->second == poHandle)
    1992                 :         {
    1993              34 :             oMapZipWriteHandles.erase(iter);
    1994              34 :             break;
    1995                 :         }
    1996              34 :     }
    1997              34 : }
    1998                 : 
    1999                 : /************************************************************************/
    2000                 : /*                             OpenForWrite()                           */
    2001                 : /************************************************************************/
    2002                 : 
    2003             138 : VSIVirtualHandle* VSIZipFilesystemHandler::OpenForWrite( const char *pszFilename,
    2004                 :                                                          const char *pszAccess)
    2005                 : {
    2006                 :     char* zipFilename;
    2007             138 :     CPLString osZipInFileName;
    2008                 : 
    2009             138 :     CPLMutexHolder oHolder( &hMutex );
    2010                 : 
    2011             138 :     zipFilename = SplitFilename(pszFilename, osZipInFileName, FALSE);
    2012             138 :     if (zipFilename == NULL)
    2013               0 :         return NULL;
    2014             138 :     CPLString osZipFilename = zipFilename;
    2015             138 :     CPLFree(zipFilename);
    2016             138 :     zipFilename = NULL;
    2017                 : 
    2018                 :     /* Invalidate cached file list */
    2019             138 :     std::map<CPLString,VSIArchiveContent*>::iterator iter = oFileList.find(osZipFilename);
    2020             138 :     if (iter != oFileList.end())
    2021                 :     {
    2022               8 :         VSIArchiveContent* content = iter->second;
    2023                 :         int i;
    2024             106 :         for(i=0;i<content->nEntries;i++)
    2025                 :         {
    2026              98 :             delete content->entries[i].file_pos;
    2027              98 :             CPLFree(content->entries[i].fileName);
    2028                 :         }
    2029               8 :         CPLFree(content->entries);
    2030               8 :         delete content;
    2031                 : 
    2032               8 :         oFileList.erase(iter);
    2033                 :     }
    2034                 : 
    2035                 :     VSIZipWriteHandle* poZIPHandle;
    2036                 : 
    2037             138 :     if (oMapZipWriteHandles.find(osZipFilename) != oMapZipWriteHandles.end() )
    2038                 :     {
    2039             104 :         if (strchr(pszAccess, '+') != NULL)
    2040                 :         {
    2041                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2042               0 :                     "Random access not supported for writable file in /vsizip");
    2043               0 :             return NULL;
    2044                 :         }
    2045                 : 
    2046             104 :         poZIPHandle = oMapZipWriteHandles[osZipFilename];
    2047                 : 
    2048             104 :         if (poZIPHandle->GetChildInWriting() != NULL)
    2049                 :         {
    2050                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2051                 :                      "Cannot create %s while another file is being written in the .zip",
    2052               2 :                      osZipInFileName.c_str());
    2053               2 :             return NULL;
    2054                 :         }
    2055                 : 
    2056             102 :         poZIPHandle->StopCurrentFile();
    2057                 : 
    2058                 :         /* Re-add path separator when creating directories */
    2059             102 :         char chLastChar = pszFilename[strlen(pszFilename) - 1];
    2060             102 :         if (chLastChar == '/' || chLastChar == '\\')
    2061               4 :             osZipInFileName += chLastChar;
    2062                 : 
    2063             102 :         if (CPLCreateFileInZip(poZIPHandle->GetHandle(),
    2064                 :                                osZipInFileName, NULL) != CE_None)
    2065               0 :             return NULL;
    2066                 : 
    2067                 :         VSIZipWriteHandle* poChildHandle =
    2068             102 :             new VSIZipWriteHandle(this, NULL, poZIPHandle);
    2069                 : 
    2070             102 :         poZIPHandle->StartNewFile(poChildHandle);
    2071                 : 
    2072             102 :         return poChildHandle;
    2073                 :     }
    2074                 :     else
    2075                 :     {
    2076              34 :         char** papszOptions = NULL;
    2077              34 :         if ((strchr(pszAccess, '+') && osZipInFileName.size() == 0) ||
    2078                 :              osZipInFileName.size() != 0)
    2079                 :         {
    2080                 :             VSIStatBufL sBuf;
    2081              26 :             if (VSIStatExL(osZipFilename, &sBuf, VSI_STAT_EXISTS_FLAG) == 0)
    2082              24 :                 papszOptions = CSLAddNameValue(papszOptions, "APPEND", "TRUE");
    2083                 :         }
    2084                 : 
    2085              34 :         void* hZIP = CPLCreateZip(osZipFilename, papszOptions);
    2086              34 :         CSLDestroy(papszOptions);
    2087                 : 
    2088              34 :         if (hZIP == NULL)
    2089               0 :             return NULL;
    2090                 : 
    2091                 :         oMapZipWriteHandles[osZipFilename] =
    2092              34 :             new VSIZipWriteHandle(this, hZIP, NULL);
    2093                 : 
    2094              34 :         if (osZipInFileName.size() != 0)
    2095                 :         {
    2096                 :             VSIZipWriteHandle* poRes =
    2097              26 :                 (VSIZipWriteHandle*)OpenForWrite(pszFilename, pszAccess);
    2098              26 :             if (poRes == NULL)
    2099                 :             {
    2100               0 :                 delete oMapZipWriteHandles[osZipFilename];
    2101               0 :                 return NULL;
    2102                 :             }
    2103                 : 
    2104              26 :             poRes->SetAutoDeleteParent();
    2105                 : 
    2106              26 :             return poRes;
    2107                 :         }
    2108                 : 
    2109               8 :         return oMapZipWriteHandles[osZipFilename];
    2110               0 :     }
    2111                 : }
    2112                 : 
    2113                 : 
    2114                 : /************************************************************************/
    2115                 : /*                          VSIZipWriteHandle()                         */
    2116                 : /************************************************************************/
    2117                 : 
    2118             136 : VSIZipWriteHandle::VSIZipWriteHandle(VSIZipFilesystemHandler* poFS,
    2119                 :                                      void* hZIP,
    2120             136 :                                      VSIZipWriteHandle* poParent)
    2121                 : {
    2122             136 :     this->poFS = poFS;
    2123             136 :     this->hZIP = hZIP;
    2124             136 :     this->poParent = poParent;
    2125             136 :     poChildInWriting = NULL;
    2126             136 :     bAutoDeleteParent = FALSE;
    2127             136 : }
    2128                 : 
    2129                 : /************************************************************************/
    2130                 : /*                         ~VSIZipWriteHandle()                         */
    2131                 : /************************************************************************/
    2132                 : 
    2133             136 : VSIZipWriteHandle::~VSIZipWriteHandle()
    2134                 : {
    2135             136 :     Close();
    2136             136 : }
    2137                 : 
    2138                 : /************************************************************************/
    2139                 : /*                               Seek()                                 */
    2140                 : /************************************************************************/
    2141                 : 
    2142               0 : int VSIZipWriteHandle::Seek( vsi_l_offset nOffset, int nWhence )
    2143                 : {
    2144                 :     CPLError(CE_Failure, CPLE_NotSupported,
    2145               0 :              "VSIFSeekL() is not supported on writable Zip files");
    2146               0 :     return -1;
    2147                 : }
    2148                 : 
    2149                 : /************************************************************************/
    2150                 : /*                               Tell()                                 */
    2151                 : /************************************************************************/
    2152                 : 
    2153               0 : vsi_l_offset VSIZipWriteHandle::Tell()
    2154                 : {
    2155                 :     CPLError(CE_Failure, CPLE_NotSupported,
    2156               0 :              "VSIFTellL() is not supported on writable Zip files");
    2157               0 :     return 0;
    2158                 : }
    2159                 : 
    2160                 : /************************************************************************/
    2161                 : /*                               Read()                                 */
    2162                 : /************************************************************************/
    2163                 : 
    2164               0 : size_t    VSIZipWriteHandle::Read( void *pBuffer, size_t nSize, size_t nMemb )
    2165                 : {
    2166                 :     CPLError(CE_Failure, CPLE_NotSupported,
    2167               0 :              "VSIFReadL() is not supported on writable Zip files");
    2168               0 :     return 0;
    2169                 : }
    2170                 : 
    2171                 : /************************************************************************/
    2172                 : /*                               Write()                                 */
    2173                 : /************************************************************************/
    2174                 : 
    2175            4092 : size_t    VSIZipWriteHandle::Write( const void *pBuffer, size_t nSize, size_t nMemb )
    2176                 : {
    2177            4092 :     if (poParent == NULL)
    2178                 :     {
    2179                 :         CPLError(CE_Failure, CPLE_NotSupported,
    2180               0 :                  "VSIFWriteL() is not supported on main Zip file or closed subfiles");
    2181               0 :         return 0;
    2182                 :     }
    2183                 : 
    2184            4092 :     if (CPLWriteFileInZip( poParent->hZIP, pBuffer, (int)(nSize * nMemb) ) != CE_None)
    2185               0 :         return 0;
    2186                 : 
    2187            4092 :     return nMemb;
    2188                 : }
    2189                 : 
    2190                 : /************************************************************************/
    2191                 : /*                                Eof()                                 */
    2192                 : /************************************************************************/
    2193                 : 
    2194               0 : int VSIZipWriteHandle::Eof()
    2195                 : {
    2196                 :     CPLError(CE_Failure, CPLE_NotSupported,
    2197               0 :              "VSIFEofL() is not supported on writable Zip files");
    2198               0 :     return FALSE;
    2199                 : }
    2200                 : 
    2201                 : /************************************************************************/
    2202                 : /*                               Flush()                                */
    2203                 : /************************************************************************/
    2204                 : 
    2205               0 : int VSIZipWriteHandle::Flush()
    2206                 : {
    2207                 :     CPLError(CE_Failure, CPLE_NotSupported,
    2208               0 :              "VSIFFlushL() is not supported on writable Zip files");
    2209               0 :     return 0;
    2210                 : }
    2211                 : 
    2212                 : /************************************************************************/
    2213                 : /*                               Close()                                */
    2214                 : /************************************************************************/
    2215                 : 
    2216             244 : int VSIZipWriteHandle::Close()
    2217                 : {
    2218             244 :     if (poParent)
    2219                 :     {
    2220             102 :         CPLCloseFileInZip(poParent->hZIP);
    2221             102 :         poParent->poChildInWriting = NULL;
    2222             102 :         if (bAutoDeleteParent)
    2223              26 :             delete poParent;
    2224             102 :         poParent = NULL;
    2225                 :     }
    2226             244 :     if (poChildInWriting)
    2227                 :     {
    2228               0 :         poChildInWriting->Close();
    2229               0 :         poChildInWriting = NULL;
    2230                 :     }
    2231             244 :     if (hZIP)
    2232                 :     {
    2233              34 :         CPLCloseZip(hZIP);
    2234              34 :         hZIP = NULL;
    2235                 : 
    2236              34 :         poFS->RemoveFromMap(this);
    2237                 :     }
    2238                 : 
    2239             244 :     return 0;
    2240                 : }
    2241                 : 
    2242                 : /************************************************************************/
    2243                 : /*                           StopCurrentFile()                          */
    2244                 : /************************************************************************/
    2245                 : 
    2246             102 : void  VSIZipWriteHandle::StopCurrentFile()
    2247                 : {
    2248             102 :     if (poChildInWriting)
    2249               0 :         poChildInWriting->Close();
    2250             102 :     poChildInWriting = NULL;
    2251             102 : }
    2252                 : 
    2253                 : /************************************************************************/
    2254                 : /*                           StartNewFile()                             */
    2255                 : /************************************************************************/
    2256                 : 
    2257             102 : void  VSIZipWriteHandle::StartNewFile(VSIZipWriteHandle* poSubFile)
    2258                 : {
    2259             102 :     poChildInWriting = poSubFile;
    2260             102 : }
    2261                 : 
    2262                 : /************************************************************************/
    2263                 : /*                    VSIInstallZipFileHandler()                        */
    2264                 : /************************************************************************/
    2265                 : 
    2266                 : 
    2267                 : /**
    2268                 :  * \brief Install ZIP file system handler. 
    2269                 :  *
    2270                 :  * A special file handler is installed that allows reading on-the-fly in ZIP
    2271                 :  * (.zip) archives.
    2272                 :  *
    2273                 :  * All portions of the file system underneath the base path "/vsizip/" will be
    2274                 :  * handled by this driver.
    2275                 :  *
    2276                 :  * The syntax to open a file inside a zip file is /vsizip/path/to/the/file.zip/path/inside/the/zip/file
    2277                 :  * were path/to/the/file.zip is relative or absolute and path/inside/the/zip/file
    2278                 :  * is the relative path to the file inside the archive.
    2279                 :  * 
    2280                 :  * If the path is absolute, it should begin with a / on a Unix-like OS (or C:\ on Windows),
    2281                 :  * so the line looks like /vsizip//home/gdal/...
    2282                 :  * For example gdalinfo /vsizip/myarchive.zip/subdir1/file1.tif
    2283                 :  *
    2284                 :  * Syntaxic sugar : if the .zip file contains only one file located at its root,
    2285                 :  * just mentionning "/vsizip/path/to/the/file.zip" will work
    2286                 :  *
    2287                 :  * VSIStatL() will return the uncompressed size in st_size member and file
    2288                 :  * nature- file or directory - in st_mode member.
    2289                 :  *
    2290                 :  * Directory listing is available through VSIReadDir().
    2291                 :  *
    2292                 :  * Since GDAL 1.8.0, write capabilities are available. They allow creating
    2293                 :  * a new zip file and adding new files to an already existing (or just created)
    2294                 :  * zip file. Read and write operations cannot be interleaved : the new zip must
    2295                 :  * be closed before being re-opened for read.
    2296                 :  *
    2297                 :  * Additional documentation is to be found at http://trac.osgeo.org/gdal/wiki/UserDocs/ReadInZip
    2298                 :  *
    2299                 :  * @since GDAL 1.6.0
    2300                 :  */
    2301                 : 
    2302            1341 : void VSIInstallZipFileHandler(void)
    2303                 : {
    2304            1341 :     VSIFileManager::InstallHandler( "/vsizip/", new VSIZipFilesystemHandler() );
    2305            1341 : }
    2306                 : 

Generated by: LCOV version 1.7