LCOV - code coverage report
Current view: directory - port - cpl_vsil_gzip.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 927 702 75.7 %
Date: 2013-03-30 Functions: 102 67 65.7 %

       1                 : /******************************************************************************
       2                 :  * $Id: cpl_vsil_gzip.cpp 25393 2012-12-29 21:36:44Z 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 25393 2012-12-29 21:36:44Z 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             104 :     vsi_l_offset      GetLastReadOffset() { return nLastReadOffset; }
     179             310 :     const char*       GetBaseFileName() { return pszBaseFileName; }
     180                 : 
     181               0 :     void              SetUncompressedSize(vsi_l_offset nUncompressedSize) { uncompressed_size = nUncompressedSize; }
     182               5 :     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              52 : VSIGZipHandle* VSIGZipHandle::Duplicate()
     216                 : {
     217              52 :     CPLAssert (offset == 0);
     218              52 :     CPLAssert (compressed_size != 0);
     219              52 :     CPLAssert (pszBaseFileName != NULL);
     220                 : 
     221                 :     VSIFilesystemHandler *poFSHandler = 
     222              52 :         VSIFileManager::GetHandler( pszBaseFileName );
     223                 : 
     224                 :     VSIVirtualHandle* poNewBaseHandle =
     225              52 :         poFSHandler->Open( pszBaseFileName, "rb" );
     226                 : 
     227              52 :     if (poNewBaseHandle == NULL)
     228               0 :         return NULL;
     229                 : 
     230                 :     VSIGZipHandle* poHandle = new VSIGZipHandle(poNewBaseHandle,
     231                 :                                                 pszBaseFileName,
     232                 :                                                 0,
     233                 :                                                 compressed_size,
     234              52 :                                                 uncompressed_size);
     235                 : 
     236              52 :     poHandle->nLastReadOffset = nLastReadOffset;
     237                 : 
     238                 :     /* Most important : duplicate the snapshots ! */
     239                 : 
     240                 :     unsigned int i;
     241              55 :     for(i=0;i<compressed_size / snapshot_byte_interval + 1;i++)
     242                 :     {
     243              52 :         if (snapshots[i].uncompressed_pos == 0)
     244              49 :             break;
     245                 : 
     246               3 :         poHandle->snapshots[i].uncompressed_pos = snapshots[i].uncompressed_pos;
     247               3 :         inflateCopy( &poHandle->snapshots[i].stream, &snapshots[i].stream);
     248               3 :         poHandle->snapshots[i].crc = snapshots[i].crc;
     249               3 :         poHandle->snapshots[i].transparent = snapshots[i].transparent;
     250               3 :         poHandle->snapshots[i].in = snapshots[i].in;
     251               3 :         poHandle->snapshots[i].out = snapshots[i].out;
     252                 :     }
     253                 : 
     254              52 :     return poHandle;
     255                 : }
     256                 : 
     257                 : /************************************************************************/
     258                 : /*                     CloseBaseHandle()                                */
     259                 : /************************************************************************/
     260                 : 
     261              11 : void  VSIGZipHandle::CloseBaseHandle()
     262                 : {
     263              11 :     if (poBaseHandle)
     264              11 :         VSIFCloseL((VSILFILE*)poBaseHandle);
     265              11 :     poBaseHandle = NULL;
     266              11 : }
     267                 : 
     268                 : /************************************************************************/
     269                 : /*                       VSIGZipHandle()                                */
     270                 : /************************************************************************/
     271                 : 
     272             326 : 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             326 :                              int transparent)
     279                 : {
     280             326 :     this->poBaseHandle = poBaseHandle;
     281             326 :     this->expected_crc = expected_crc;
     282             326 :     this->pszBaseFileName = (pszBaseFileName) ? CPLStrdup(pszBaseFileName) : NULL;
     283             326 :     this->offset = offset;
     284             641 :     if (compressed_size || transparent)
     285                 :     {
     286             315 :         this->compressed_size = compressed_size;
     287                 :     }
     288                 :     else
     289                 :     {
     290              11 :         VSIFSeekL((VSILFILE*)poBaseHandle, 0, SEEK_END);
     291              11 :         this->compressed_size = VSIFTellL((VSILFILE*)poBaseHandle) - offset;
     292              11 :         compressed_size = this->compressed_size;
     293                 :     }
     294             326 :     this->uncompressed_size = uncompressed_size;
     295             326 :     offsetEndCompressedData = offset + compressed_size;
     296                 : 
     297             326 :     VSIFSeekL((VSILFILE*)poBaseHandle, offset, SEEK_SET);
     298                 : 
     299             326 :     nLastReadOffset = 0;
     300             326 :     stream.zalloc = (alloc_func)0;
     301             326 :     stream.zfree = (free_func)0;
     302             326 :     stream.opaque = (voidpf)0;
     303             326 :     stream.next_in = inbuf = Z_NULL;
     304             326 :     stream.next_out = outbuf = Z_NULL;
     305             326 :     stream.avail_in = stream.avail_out = 0;
     306             326 :     z_err = Z_OK;
     307             326 :     z_eof = 0;
     308             326 :     in = 0;
     309             326 :     out = 0;
     310             326 :     crc = crc32(0L, Z_NULL, 0);
     311             326 :     this->transparent = transparent;
     312                 : 
     313             326 :     stream.next_in  = inbuf = (Byte*)ALLOC(Z_BUFSIZE);
     314                 : 
     315             326 :     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             326 :     if (err != Z_OK || inbuf == Z_NULL) {
     323               0 :         CPLError(CE_Failure, CPLE_NotSupported, "inflateInit2 init failed");
     324                 :     }
     325             326 :     stream.avail_out = Z_BUFSIZE;
     326                 : 
     327             326 :     if (offset == 0) check_header(); /* skip the .gz header */
     328             326 :     startOff = VSIFTellL((VSILFILE*)poBaseHandle) - stream.avail_in;
     329                 : 
     330             326 :     if (transparent == 0)
     331                 :     {
     332             322 :         snapshot_byte_interval = MAX(Z_BUFSIZE, compressed_size / 100);
     333             322 :         snapshots = (GZipSnapshot*)CPLCalloc(sizeof(GZipSnapshot), (size_t) (compressed_size / snapshot_byte_interval + 1));
     334                 :     }
     335                 :     else
     336                 :     {
     337               4 :         snapshots = NULL;
     338                 :     }
     339             326 : }
     340                 : 
     341                 : /************************************************************************/
     342                 : /*                      ~VSIGZipHandle()                                */
     343                 : /************************************************************************/
     344                 : 
     345             326 : VSIGZipHandle::~VSIGZipHandle()
     346                 : {
     347                 :     
     348             326 :     if (pszBaseFileName)
     349                 :     {
     350                 :         VSIFilesystemHandler *poFSHandler = 
     351              63 :             VSIFileManager::GetHandler( "/vsigzip/" );
     352              63 :         ((VSIGZipFilesystemHandler*)poFSHandler)->SaveInfo(this);
     353                 :     }
     354                 :     
     355             326 :     if (stream.state != NULL) {
     356             326 :         inflateEnd(&(stream));
     357                 :     }
     358                 : 
     359             326 :     TRYFREE(inbuf);
     360             326 :     TRYFREE(outbuf);
     361                 : 
     362             326 :     if (snapshots != NULL)
     363                 :     {
     364                 :         unsigned int i;
     365             671 :         for(i=0;i<compressed_size / snapshot_byte_interval + 1;i++)
     366                 :         {
     367             349 :             if (snapshots[i].uncompressed_pos)
     368                 :             {
     369             279 :                 inflateEnd(&(snapshots[i].stream));
     370                 :             }
     371                 :         }
     372             322 :         CPLFree(snapshots);
     373                 :     }
     374             326 :     CPLFree(pszBaseFileName);
     375                 : 
     376             326 :     if (poBaseHandle)
     377             315 :         VSIFCloseL((VSILFILE*)poBaseHandle);
     378             326 : }
     379                 : 
     380                 : /************************************************************************/
     381                 : /*                      check_header()                                  */
     382                 : /************************************************************************/
     383                 : 
     384              84 : 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              84 :     len = stream.avail_in;
     395              84 :     if (len < 2) {
     396              84 :         if (len) inbuf[0] = stream.next_in[0];
     397              84 :         errno = 0;
     398              84 :         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              84 :         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              84 :         if (len == 0 /* && ferror(file)*/)
     407                 :         {
     408              21 :             if (VSIFTellL((VSILFILE*)poBaseHandle) != offsetEndCompressedData)
     409               0 :                 z_err = Z_ERRNO;
     410                 :         }
     411              84 :         stream.avail_in += len;
     412              84 :         stream.next_in = inbuf;
     413              84 :         if (stream.avail_in < 2) {
     414              21 :             transparent = stream.avail_in;
     415              21 :             return;
     416                 :         }
     417                 :     }
     418                 : 
     419                 :     /* Peek ahead to check the gzip magic header */
     420             189 :     if (stream.next_in[0] != gz_magic[0] ||
     421             126 :         stream.next_in[1] != gz_magic[1]) {
     422               0 :         transparent = 1;
     423               0 :         return;
     424                 :     }
     425              63 :     stream.avail_in -= 2;
     426              63 :     stream.next_in += 2;
     427                 : 
     428                 :     /* Check the rest of the gzip header */
     429              63 :     method = get_byte();
     430              63 :     flags = get_byte();
     431              63 :     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              63 :     for (len = 0; len < 6; len++) (void)get_byte();
     438                 : 
     439              63 :     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              63 :     if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
     446               0 :         while ((c = get_byte()) != 0 && c != EOF) ;
     447                 :     }
     448              63 :     if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
     449               0 :         while ((c = get_byte()) != 0 && c != EOF) ;
     450                 :     }
     451              63 :     if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
     452               0 :         for (len = 0; len < 2; len++) (void)get_byte();
     453                 :     }
     454              63 :     z_err = z_eof ? Z_DATA_ERROR : Z_OK;
     455                 : }
     456                 : 
     457                 : /************************************************************************/
     458                 : /*                            get_byte()                                */
     459                 : /************************************************************************/
     460                 : 
     461             672 : int VSIGZipHandle::get_byte()
     462                 : {
     463             672 :     if (z_eof) return EOF;
     464             672 :     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             672 :     stream.avail_in--;
     484             672 :     return *(stream.next_in)++;
     485                 : }
     486                 : 
     487                 : /************************************************************************/
     488                 : /*                            gzrewind()                                */
     489                 : /************************************************************************/
     490                 : 
     491              90 : int VSIGZipHandle::gzrewind ()
     492                 : {
     493              90 :     z_err = Z_OK;
     494              90 :     z_eof = 0;
     495              90 :     stream.avail_in = 0;
     496              90 :     stream.next_in = inbuf;
     497              90 :     crc = crc32(0L, Z_NULL, 0);
     498              90 :     if (!transparent) (void)inflateReset(&stream);
     499              90 :     in = 0;
     500              90 :     out = 0;
     501              90 :     return VSIFSeekL((VSILFILE*)poBaseHandle, startOff, SEEK_SET);
     502                 : }
     503                 : 
     504                 : /************************************************************************/
     505                 : /*                              Seek()                                  */
     506                 : /************************************************************************/
     507                 : 
     508             566 : 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             566 :     int ret = gzseek(nOffset, nWhence);
     514             566 :     return (ret >= 0) ? 0 : ret;
     515                 : }
     516                 : 
     517                 : /************************************************************************/
     518                 : /*                            gzseek()                                  */
     519                 : /************************************************************************/
     520                 : 
     521             566 : int VSIGZipHandle::gzseek( vsi_l_offset offset, int whence )
     522                 : {
     523             566 :     vsi_l_offset original_offset = offset;
     524             566 :     int original_nWhence = whence;
     525                 : 
     526                 :     if (ENABLE_DEBUG) CPLDebug("GZIP", "Seek(" CPL_FRMT_GUIB ",%d)", offset, whence);
     527                 : 
     528             566 :     if (transparent)
     529                 :     {
     530               3 :         stream.avail_in = 0;
     531               3 :         stream.next_in = inbuf;
     532               3 :         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               3 :         else if (whence == SEEK_SET)
     543                 :         {
     544               2 :             if (offset > compressed_size)
     545                 :             {
     546               0 :                 CPL_VSIL_GZ_RETURN_MINUS_ONE();
     547               0 :                 return -1L;
     548                 :             }
     549                 : 
     550               2 :             offset = startOff + offset;
     551                 :         }
     552               1 :         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               1 :             if (offset > 0 /*|| -offset > compressed_size*/)
     557                 :             {
     558               0 :                 CPL_VSIL_GZ_RETURN_MINUS_ONE();
     559               0 :                 return -1L;
     560                 :             }
     561                 : 
     562               1 :             offset = startOff + compressed_size - offset;
     563                 :         }
     564                 :         else
     565                 :         {
     566               0 :             CPL_VSIL_GZ_RETURN_MINUS_ONE();
     567               0 :             return -1L;
     568                 :         }
     569               3 :         if (VSIFSeekL((VSILFILE*)poBaseHandle, offset, SEEK_SET) < 0)
     570                 :         {
     571               0 :             CPL_VSIL_GZ_RETURN_MINUS_ONE();
     572               0 :             return -1L;
     573                 :         }
     574                 : 
     575               3 :         in = out = offset - startOff;
     576                 :         if (ENABLE_DEBUG) CPLDebug("GZIP", "return " CPL_FRMT_GUIB, in);
     577               3 :         return (int) in;
     578                 :     }
     579                 : 
     580                 :     /* whence == SEEK_END is unsuppored in original gzseek. */
     581             563 :     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              63 :         if (offset == 0 && uncompressed_size != 0)
     586                 :         {
     587              55 :             out = uncompressed_size;
     588              55 :             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               8 :         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               8 :         whence = SEEK_CUR;
     601               8 :         offset = 1024 * 1024 * 1024;
     602               8 :         offset *= 1024 * 1024;
     603                 :     }
     604                 : 
     605             508 :     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             508 :     if (whence == SEEK_CUR) {
     615               8 :         offset += out;
     616                 :     }
     617                 : 
     618                 :     /* For a negative seek, rewind and use positive seek */
     619             508 :     if (offset >= out) {
     620             418 :         offset -= out;
     621              90 :     } else if (gzrewind() < 0) {
     622               0 :             CPL_VSIL_GZ_RETURN_MINUS_ONE();
     623               0 :             return -1L;
     624                 :     }
     625                 :     
     626                 :     unsigned int i;
     627             508 :     for(i=0;i<compressed_size / snapshot_byte_interval + 1;i++)
     628                 :     {
     629             508 :         if (snapshots[i].uncompressed_pos == 0)
     630             442 :             break;
     631              69 :         if (snapshots[i].out <= out + offset &&
     632               3 :             (i == compressed_size / snapshot_byte_interval || snapshots[i+1].out == 0 || snapshots[i+1].out > out+offset))
     633                 :         {
     634              66 :             if (out >= snapshots[i].out)
     635              66 :                 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             508 :     if (offset != 0 && outbuf == Z_NULL) {
     659              50 :         outbuf = (Byte*)ALLOC(Z_BUFSIZE);
     660              50 :         if (outbuf == Z_NULL) {
     661               0 :             CPL_VSIL_GZ_RETURN_MINUS_ONE();
     662               0 :             return -1L;
     663                 :         }
     664                 :     }
     665                 : 
     666             508 :     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            1213 :     while (offset > 0)  {
     673             208 :         int size = Z_BUFSIZE;
     674             208 :         if (offset < Z_BUFSIZE) size = (int)offset;
     675                 : 
     676             208 :         int read_size = Read(outbuf, 1, (uInt)size);
     677             208 :         if (read_size == 0) {
     678                 :             //CPL_VSIL_GZ_RETURN_MINUS_ONE();
     679               1 :             return -1L;
     680                 :         }
     681             207 :         if (original_nWhence == SEEK_END)
     682                 :         {
     683               6 :             if (size != read_size)
     684                 :             {
     685               6 :                 z_err = Z_STREAM_END;
     686               6 :                 break;
     687                 :             }
     688                 :         }
     689             201 :         offset -= read_size;
     690                 :     }
     691                 :     if (ENABLE_DEBUG) CPLDebug("GZIP", "gzseek return " CPL_FRMT_GUIB, out);
     692                 : 
     693             505 :     if (original_offset == 0 && original_nWhence == SEEK_END)
     694                 :     {
     695               6 :         uncompressed_size = out;
     696                 : 
     697               6 :         if (pszBaseFileName)
     698                 :         {
     699               6 :             CPLString osCacheFilename (pszBaseFileName);
     700               6 :             osCacheFilename += ".properties";
     701                 : 
     702                 :             /* Write a .properties file to avoid seeking next time */
     703               6 :             VSILFILE* fpCacheLength = VSIFOpenL(osCacheFilename.c_str(), "wb");
     704               6 :             if (fpCacheLength)
     705                 :             {
     706                 :                 char* pszFirstNonSpace;
     707                 :                 char szBuffer[32];
     708               6 :                 szBuffer[31] = 0;
     709                 : 
     710               6 :                 CPLPrintUIntBig(szBuffer, compressed_size, 31);
     711               6 :                 pszFirstNonSpace = szBuffer;
     712               6 :                 while (*pszFirstNonSpace == ' ') pszFirstNonSpace ++;
     713               6 :                 VSIFPrintfL(fpCacheLength, "compressed_size=%s\n", pszFirstNonSpace);
     714                 : 
     715               6 :                 CPLPrintUIntBig(szBuffer, uncompressed_size, 31);
     716               6 :                 pszFirstNonSpace = szBuffer;
     717               6 :                 while (*pszFirstNonSpace == ' ') pszFirstNonSpace ++;
     718               6 :                 VSIFPrintfL(fpCacheLength, "uncompressed_size=%s\n", pszFirstNonSpace);
     719                 : 
     720               6 :                 VSIFCloseL(fpCacheLength);
     721               6 :             }
     722                 :         }
     723                 :     }
     724                 : 
     725             505 :     return (int) out;
     726                 : }
     727                 : 
     728                 : /************************************************************************/
     729                 : /*                              Tell()                                  */
     730                 : /************************************************************************/
     731                 : 
     732              64 : vsi_l_offset VSIGZipHandle::Tell()
     733                 : {
     734                 :     if (ENABLE_DEBUG) CPLDebug("GZIP", "Tell() = " CPL_FRMT_GUIB, out);
     735              64 :     return out;
     736                 : }
     737                 : 
     738                 : /************************************************************************/
     739                 : /*                              Read()                                  */
     740                 : /************************************************************************/
     741                 : 
     742            2130 : 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            2130 :     unsigned len = nSize * nMemb;
     747                 : 
     748            2130 :     Bytef *pStart = (Bytef*)buf; /* startOffing point for crc computation */
     749                 :     Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
     750                 : 
     751            2130 :     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            2130 :     if  (z_eof || z_err == Z_STREAM_END)
     757                 :     {
     758             119 :         z_eof = 1;
     759                 :         if (ENABLE_DEBUG) CPLDebug("GZIP", "Read: Eof");
     760             119 :         return 0;  /* EOF */
     761                 :     }
     762                 : 
     763            2011 :     next_out = (Byte*)buf;
     764            2011 :     stream.next_out = (Bytef*)buf;
     765            2011 :     stream.avail_out = len;
     766                 : 
     767            5777 :     while  (stream.avail_out != 0) {
     768                 : 
     769            2014 :         if  (transparent) {
     770                 :             /* Copy first the lookahead bytes: */
     771               2 :             uInt nRead = 0;
     772               2 :             uInt n = stream.avail_in;
     773               2 :             if (n > stream.avail_out) n = stream.avail_out;
     774               2 :             if (n > 0) {
     775               0 :                 memcpy (stream.next_out, stream.next_in, n);
     776               0 :                 next_out += n;
     777               0 :                 stream.next_out = next_out;
     778               0 :                 stream.next_in   += n;
     779               0 :                 stream.avail_out -= n;
     780               0 :                 stream.avail_in  -= n;
     781               0 :                 nRead += n;
     782                 :             }
     783               2 :             if  (stream.avail_out > 0) {
     784               2 :                 uInt nToRead = (uInt) MIN(compressed_size - (in + nRead), stream.avail_out);
     785                 :                 uInt nReadFromFile =
     786               2 :                     (uInt)VSIFReadL(next_out, 1, nToRead, (VSILFILE*)poBaseHandle);
     787               2 :                 stream.avail_out -= nReadFromFile;
     788               2 :                 nRead += nReadFromFile;
     789                 :             }
     790               2 :             in  += nRead;
     791               2 :             out += nRead;
     792               2 :             if (nRead < len) z_eof = 1;
     793                 :             if (ENABLE_DEBUG) CPLDebug("GZIP", "Read return %d", (int)(nRead / nSize));
     794               2 :             return (int)nRead / nSize;
     795                 :         }
     796            2012 :         if  (stream.avail_in == 0 && !z_eof)
     797                 :         {
     798             314 :             vsi_l_offset uncompressed_pos = VSIFTellL((VSILFILE*)poBaseHandle);
     799             314 :             GZipSnapshot* snapshot = &snapshots[(uncompressed_pos - startOff) / snapshot_byte_interval];
     800             314 :             if (snapshot->uncompressed_pos == 0)
     801                 :             {
     802             276 :                 snapshot->crc = crc32 (crc, pStart, (uInt) (stream.next_out - pStart));
     803                 :                 if (ENABLE_DEBUG)
     804                 :                     CPLDebug("SNAPSHOT",
     805                 :                              "creating snapshot %d : uncompressed_pos=" CPL_FRMT_GUIB
     806                 :                                                    " in=" CPL_FRMT_GUIB
     807                 :                                                    " out=" CPL_FRMT_GUIB
     808                 :                                                    " crc=%X",
     809                 :                           (int)((uncompressed_pos - startOff) / snapshot_byte_interval),
     810                 :                           uncompressed_pos, in, out, (unsigned int)snapshot->crc);
     811             276 :                 snapshot->uncompressed_pos = uncompressed_pos;
     812             276 :                 inflateCopy(&snapshot->stream, &stream);
     813             276 :                 snapshot->transparent = transparent;
     814             276 :                 snapshot->in = in;
     815             276 :                 snapshot->out = out;
     816                 : 
     817             276 :                 if (out > nLastReadOffset)
     818               3 :                     nLastReadOffset = out;
     819                 :             }
     820                 : 
     821             314 :             errno = 0;
     822             314 :             stream.avail_in = (uInt)VSIFReadL(inbuf, 1, Z_BUFSIZE, (VSILFILE*)poBaseHandle);
     823                 :             if (ENABLE_DEBUG)
     824                 :                 CPLDebug("GZIP", CPL_FRMT_GUIB " " CPL_FRMT_GUIB,
     825                 :                                  VSIFTellL((VSILFILE*)poBaseHandle), offsetEndCompressedData);
     826             314 :             if (VSIFTellL((VSILFILE*)poBaseHandle) > offsetEndCompressedData)
     827                 :             {
     828                 :                 if (ENABLE_DEBUG) CPLDebug("GZIP", "avail_in before = %d", stream.avail_in);
     829             283 :                 stream.avail_in = stream.avail_in + (uInt) (offsetEndCompressedData - VSIFTellL((VSILFILE*)poBaseHandle));
     830             283 :                 VSIFSeekL((VSILFILE*)poBaseHandle, offsetEndCompressedData, SEEK_SET);
     831             283 :                 if (ENABLE_DEBUG) CPLDebug("GZIP", "avail_in after = %d", stream.avail_in);
     832                 :             }
     833             314 :             if  (stream.avail_in == 0) {
     834               0 :                 z_eof = 1;
     835               0 :                 if (VSIFTellL((VSILFILE*)poBaseHandle) != offsetEndCompressedData)
     836                 :                 {
     837               0 :                     z_err = Z_ERRNO;
     838               0 :                     break;
     839                 :                 }
     840                 :                 /*if (ferror (file)) {
     841                 :                     z_err = Z_ERRNO;
     842                 :                     break;
     843                 :                 }*/
     844                 :             }
     845             314 :             stream.next_in = inbuf;
     846                 :         }
     847            2012 :         in += stream.avail_in;
     848            2012 :         out += stream.avail_out;
     849            2012 :         z_err = inflate(& (stream), Z_NO_FLUSH);
     850            2012 :         in -= stream.avail_in;
     851            2012 :         out -= stream.avail_out;
     852                 : 
     853            2012 :         if  (z_err == Z_STREAM_END && compressed_size != 2 ) {
     854                 :             /* Check CRC and original size */
     855             257 :             crc = crc32 (crc, pStart, (uInt) (stream.next_out - pStart));
     856             257 :             pStart = stream.next_out;
     857             257 :             if (expected_crc)
     858                 :             {
     859             236 :                 if (ENABLE_DEBUG) CPLDebug("GZIP", "Computed CRC = %X. Expected CRC = %X", (unsigned int)crc, expected_crc);
     860                 :             }
     861             257 :             if (expected_crc != 0 && expected_crc != crc)
     862                 :             {
     863               0 :                 CPLError(CE_Failure, CPLE_FileIO, "CRC error. Got %X instead of %X", (unsigned int)crc, expected_crc);
     864               0 :                 z_err = Z_DATA_ERROR;
     865                 :             }
     866             257 :             else if (expected_crc == 0)
     867                 :             {
     868              21 :                 unsigned int read_crc = getLong();
     869              21 :                 if (read_crc != crc)
     870                 :                 {
     871               0 :                     CPLError(CE_Failure, CPLE_FileIO, "CRC error. Got %X instead of %X", (unsigned int)crc, read_crc);
     872               0 :                     z_err = Z_DATA_ERROR;
     873                 :                 }
     874                 :                 else
     875                 :                 {
     876              21 :                     (void)getLong();
     877                 :                     /* The uncompressed length returned by above getlong() may be
     878                 :                     * different from out in case of concatenated .gz files.
     879                 :                     * Check for such files:
     880                 :                     */
     881              21 :                     check_header();
     882              21 :                     if  (z_err == Z_OK) {
     883               0 :                         inflateReset(& (stream));
     884               0 :                         crc = crc32(0L, Z_NULL, 0);
     885                 :                     }
     886                 :                 }
     887                 :             }
     888                 :         }
     889            2012 :         if  (z_err != Z_OK || z_eof) break;
     890                 :     }
     891            2009 :     crc = crc32 (crc, pStart, (uInt) (stream.next_out - pStart));
     892                 : 
     893            2009 :     if (len == stream.avail_out &&
     894                 :             (z_err == Z_DATA_ERROR || z_err == Z_ERRNO))
     895                 :     {
     896               0 :         CPL_VSIL_GZ_RETURN_MINUS_ONE();
     897               0 :         return 0;
     898                 :     }
     899                 :     if (ENABLE_DEBUG)
     900                 :         CPLDebug("GZIP", "Read return %d (z_err=%d, z_eof=%d)",
     901                 :                 (int)((len - stream.avail_out) / nSize), z_err, z_eof);
     902            2009 :     return (int)(len - stream.avail_out) / nSize;
     903                 : }
     904                 : 
     905                 : /************************************************************************/
     906                 : /*                              getLong()                               */
     907                 : /************************************************************************/
     908                 : 
     909              42 : uLong VSIGZipHandle::getLong ()
     910                 : {
     911              42 :     uLong x = (uLong)get_byte();
     912                 :     int c;
     913                 : 
     914              42 :     x += ((uLong)get_byte())<<8;
     915              42 :     x += ((uLong)get_byte())<<16;
     916              42 :     c = get_byte();
     917              42 :     if (c == EOF) z_err = Z_DATA_ERROR;
     918              42 :     x += ((uLong)c)<<24;
     919              42 :     return x;
     920                 : }
     921                 : 
     922                 : /************************************************************************/
     923                 : /*                              Write()                                 */
     924                 : /************************************************************************/
     925                 : 
     926               0 : size_t VSIGZipHandle::Write( const void *pBuffer, size_t nSize, size_t nMemb )
     927                 : {
     928               0 :     CPLError(CE_Failure, CPLE_NotSupported, "VSIFWriteL is not supported on GZip streams");
     929               0 :     return 0;
     930                 : }
     931                 : 
     932                 : /************************************************************************/
     933                 : /*                               Eof()                                  */
     934                 : /************************************************************************/
     935                 : 
     936                 : 
     937            1922 : int VSIGZipHandle::Eof()
     938                 : {
     939                 :     if (ENABLE_DEBUG) CPLDebug("GZIP", "Eof()");
     940            1922 :     return z_eof;
     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             315 : int VSIGZipHandle::Close()
     957                 : {
     958             315 :     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             301 : VSIGZipWriteHandle::VSIGZipWriteHandle( VSIVirtualHandle *poBaseHandle,
    1000                 :                                         int bRegularZLibIn,
    1001             301 :                                         int bAutoCloseBaseHandleIn )
    1002                 : 
    1003                 : {
    1004             301 :     nCurOffset = 0;
    1005                 : 
    1006             301 :     this->poBaseHandle = poBaseHandle;
    1007             301 :     bRegularZLib = bRegularZLibIn;
    1008             301 :     bAutoCloseBaseHandle = bAutoCloseBaseHandleIn;
    1009                 : 
    1010             301 :     nCRC = crc32(0L, Z_NULL, 0);
    1011             301 :     sStream.zalloc = (alloc_func)0;
    1012             301 :     sStream.zfree = (free_func)0;
    1013             301 :     sStream.opaque = (voidpf)0;
    1014             301 :     sStream.next_in = Z_NULL;
    1015             301 :     sStream.next_out = Z_NULL;
    1016             301 :     sStream.avail_in = sStream.avail_out = 0;
    1017                 : 
    1018             301 :     pabyInBuf = (Byte *) CPLMalloc( Z_BUFSIZE );
    1019             301 :     sStream.next_in  = pabyInBuf;
    1020                 : 
    1021             301 :     pabyOutBuf = (Byte *) CPLMalloc( Z_BUFSIZE );
    1022                 : 
    1023             301 :     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             301 :         if (!bRegularZLib)
    1030                 :         {
    1031                 :             char header[11];
    1032                 : 
    1033                 :             /* Write a very simple .gz header:
    1034                 :             */
    1035              24 :             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              24 :                     0x03 );
    1038              24 :             poBaseHandle->Write( header, 1, 10 );
    1039                 :         }
    1040                 : 
    1041             301 :         bCompressActive = true;
    1042                 :     }
    1043             301 : }
    1044                 : 
    1045                 : /************************************************************************/
    1046                 : /*                       VSICreateGZipWritable()                        */
    1047                 : /************************************************************************/
    1048                 : 
    1049             277 : VSIVirtualHandle* VSICreateGZipWritable( VSIVirtualHandle* poBaseHandle,
    1050                 :                                          int bRegularZLibIn,
    1051                 :                                          int bAutoCloseBaseHandle )
    1052                 : {
    1053             277 :     return new VSIGZipWriteHandle( poBaseHandle, bRegularZLibIn, bAutoCloseBaseHandle );
    1054                 : }
    1055                 : 
    1056                 : /************************************************************************/
    1057                 : /*                        ~VSIGZipWriteHandle()                         */
    1058                 : /************************************************************************/
    1059                 : 
    1060             301 : VSIGZipWriteHandle::~VSIGZipWriteHandle()
    1061                 : 
    1062                 : {
    1063             301 :     if( bCompressActive )
    1064               0 :         Close();
    1065                 : 
    1066             301 :     CPLFree( pabyInBuf );
    1067             301 :     CPLFree( pabyOutBuf );
    1068             301 : }
    1069                 : 
    1070                 : /************************************************************************/
    1071                 : /*                               Close()                                */
    1072                 : /************************************************************************/
    1073                 : 
    1074             301 : int VSIGZipWriteHandle::Close()
    1075                 : 
    1076                 : {
    1077             301 :     if( bCompressActive )
    1078                 :     {
    1079             301 :         sStream.next_out = pabyOutBuf;
    1080             301 :         sStream.avail_out = Z_BUFSIZE;
    1081                 : 
    1082             301 :         deflate( &sStream, Z_FINISH );
    1083                 : 
    1084             301 :         size_t nOutBytes = Z_BUFSIZE - sStream.avail_out;
    1085                 : 
    1086             301 :         if( poBaseHandle->Write( pabyOutBuf, 1, nOutBytes ) < nOutBytes )
    1087               0 :             return EOF;
    1088                 : 
    1089             301 :         deflateEnd( &sStream );
    1090                 : 
    1091             301 :         if( !bRegularZLib )
    1092                 :         {
    1093                 :             GUInt32 anTrailer[2];
    1094                 : 
    1095              24 :             anTrailer[0] = CPL_LSBWORD32( nCRC );
    1096              24 :             anTrailer[1] = CPL_LSBWORD32( (GUInt32) nCurOffset );
    1097                 : 
    1098              24 :             poBaseHandle->Write( anTrailer, 1, 8 );
    1099                 :         }
    1100                 : 
    1101             301 :         if( bAutoCloseBaseHandle )
    1102                 :         {
    1103              24 :             poBaseHandle->Close();
    1104                 : 
    1105              24 :             delete poBaseHandle;
    1106                 :         }
    1107                 : 
    1108             301 :         bCompressActive = false;
    1109                 :     }
    1110                 : 
    1111             301 :     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           10714 : size_t VSIGZipWriteHandle::Write( const void *pBuffer, 
    1130                 :                                   size_t nSize, size_t nMemb )
    1131                 : 
    1132                 : {
    1133                 :     int  nBytesToWrite, nNextByte;
    1134                 : 
    1135           10714 :     nBytesToWrite = (int) (nSize * nMemb);
    1136           10714 :     nNextByte = 0;
    1137                 : 
    1138           10714 :     nCRC = crc32(nCRC, (const Bytef *)pBuffer, nBytesToWrite);
    1139                 : 
    1140           10714 :     if( !bCompressActive )
    1141               0 :         return 0;
    1142                 : 
    1143           32142 :     while( nNextByte < nBytesToWrite )
    1144                 :     {
    1145           10714 :         sStream.next_out = pabyOutBuf;
    1146           10714 :         sStream.avail_out = Z_BUFSIZE;
    1147                 : 
    1148           10714 :         if( sStream.avail_in > 0 )
    1149               0 :             memmove( pabyInBuf, sStream.next_in, sStream.avail_in );
    1150                 : 
    1151           10714 :         int nNewBytesToWrite = MIN((int) (Z_BUFSIZE-sStream.avail_in),
    1152                 :                                    nBytesToWrite - nNextByte);
    1153                 :         memcpy( pabyInBuf + sStream.avail_in, 
    1154                 :                 ((Byte *) pBuffer) + nNextByte, 
    1155           10714 :                 nNewBytesToWrite );
    1156                 :         
    1157           10714 :         sStream.next_in = pabyInBuf;
    1158           10714 :         sStream.avail_in += nNewBytesToWrite;
    1159                 : 
    1160           10714 :         deflate( &sStream, Z_NO_FLUSH );
    1161                 : 
    1162           10714 :         size_t nOutBytes = Z_BUFSIZE - sStream.avail_out;
    1163                 : 
    1164           10714 :         if( nOutBytes > 0 )
    1165                 :         {
    1166             294 :             if( poBaseHandle->Write( pabyOutBuf, 1, nOutBytes ) < nOutBytes )
    1167               0 :                 return 0;
    1168                 :         }
    1169                 : 
    1170           10714 :         nNextByte += nNewBytesToWrite;
    1171           10714 :         nCurOffset += nNewBytesToWrite;
    1172                 :     }
    1173                 : 
    1174           10714 :     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             757 : VSIGZipFilesystemHandler::VSIGZipFilesystemHandler()
    1242                 : {
    1243             757 :     hMutex = NULL;
    1244                 : 
    1245             757 :     poHandleLastGZipFile = NULL;
    1246             757 :     bInSaveInfo = FALSE;
    1247             757 : }
    1248                 : 
    1249                 : /************************************************************************/
    1250                 : /*                  ~VSIGZipFilesystemHandler()                         */
    1251                 : /************************************************************************/
    1252                 : 
    1253             704 : VSIGZipFilesystemHandler::~VSIGZipFilesystemHandler()
    1254                 : {
    1255             704 :     if (poHandleLastGZipFile)
    1256               1 :         delete poHandleLastGZipFile;
    1257                 : 
    1258             704 :     if( hMutex != NULL )
    1259               1 :         CPLDestroyMutex( hMutex );
    1260             704 :     hMutex = NULL;
    1261             704 : }
    1262                 : 
    1263                 : /************************************************************************/
    1264                 : /*                            SaveInfo()                                */
    1265                 : /************************************************************************/
    1266                 : 
    1267              63 : void VSIGZipFilesystemHandler::SaveInfo(  VSIGZipHandle* poHandle )
    1268                 : {
    1269              63 :     CPLMutexHolder oHolder(&hMutex);
    1270                 : 
    1271              63 :     if (bInSaveInfo)
    1272                 :         return;
    1273              63 :     bInSaveInfo = TRUE;
    1274                 :     
    1275              63 :     CPLAssert(poHandle->GetBaseFileName() != NULL);
    1276                 : 
    1277              63 :     if (poHandleLastGZipFile &&
    1278                 :         strcmp(poHandleLastGZipFile->GetBaseFileName(), poHandle->GetBaseFileName()) == 0)
    1279                 :     {
    1280              52 :         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              11 :         VSIGZipHandle* poTmp = poHandleLastGZipFile;
    1292              11 :         poHandleLastGZipFile = NULL;
    1293              11 :         delete poTmp;
    1294              11 :         poHandleLastGZipFile = poHandle->Duplicate();
    1295              11 :         poHandleLastGZipFile->CloseBaseHandle();
    1296                 :     }
    1297                 : 
    1298              63 :     bInSaveInfo = FALSE;
    1299                 : }
    1300                 : 
    1301                 : /************************************************************************/
    1302                 : /*                                Open()                                */
    1303                 : /************************************************************************/
    1304                 : 
    1305             126 : VSIVirtualHandle* VSIGZipFilesystemHandler::Open( const char *pszFilename, 
    1306                 :                                                   const char *pszAccess)
    1307                 : {
    1308                 :     VSIFilesystemHandler *poFSHandler = 
    1309             126 :         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             126 :     if (strchr(pszAccess, 'w') != NULL )
    1317                 :     {
    1318              26 :         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              26 :             poFSHandler->Open( pszFilename + strlen("/vsigzip/"), "wb" );
    1327                 : 
    1328              26 :         if (poVirtualHandle == NULL)
    1329               2 :             return NULL;
    1330                 : 
    1331                 :         else
    1332              24 :             return new VSIGZipWriteHandle( poVirtualHandle, strchr(pszAccess, 'z') != NULL, TRUE );
    1333                 :     }
    1334                 : 
    1335                 : /* -------------------------------------------------------------------- */
    1336                 : /*      Otherwise we are in the read access case.                       */
    1337                 : /* -------------------------------------------------------------------- */
    1338                 : 
    1339             100 :     VSIGZipHandle* poGZIPHandle = OpenGZipReadOnly(pszFilename, pszAccess);
    1340             100 :     if (poGZIPHandle)
    1341                 :         /* Wrap the VSIGZipHandle inside a buffered reader that will */
    1342                 :         /* improve dramatically performance when doing small backward */
    1343                 :         /* seeks */
    1344              52 :         return VSICreateBufferedReaderHandle(poGZIPHandle);
    1345                 :     else
    1346              48 :         return NULL;
    1347                 : }
    1348                 : 
    1349                 : /************************************************************************/
    1350                 : /*                          OpenGZipReadOnly()                          */
    1351                 : /************************************************************************/
    1352                 : 
    1353             100 : VSIGZipHandle* VSIGZipFilesystemHandler::OpenGZipReadOnly( const char *pszFilename, 
    1354                 :                                                       const char *pszAccess)
    1355                 : {
    1356                 :     VSIFilesystemHandler *poFSHandler = 
    1357             100 :         VSIFileManager::GetHandler( pszFilename + strlen("/vsigzip/"));
    1358                 : 
    1359             100 :     CPLMutexHolder oHolder(&hMutex);
    1360                 : 
    1361             100 :     if (poHandleLastGZipFile != NULL &&
    1362                 :         strcmp(pszFilename + strlen("/vsigzip/"), poHandleLastGZipFile->GetBaseFileName()) == 0 &&
    1363                 :         EQUAL(pszAccess, "rb"))
    1364                 :     {
    1365              41 :         VSIGZipHandle* poHandle = poHandleLastGZipFile->Duplicate();
    1366              41 :         if (poHandle)
    1367              41 :             return poHandle;
    1368                 :     }
    1369                 : 
    1370                 :     unsigned char signature[2];
    1371                 : 
    1372                 :     VSIVirtualHandle* poVirtualHandle =
    1373              59 :         poFSHandler->Open( pszFilename + strlen("/vsigzip/"), "rb" );
    1374                 : 
    1375              59 :     if (poVirtualHandle == NULL)
    1376              48 :         return NULL;
    1377                 : 
    1378              55 :     if (VSIFReadL(signature, 1, 2, (VSILFILE*)poVirtualHandle) != 2 ||
    1379              44 :         signature[0] != gz_magic[0] || signature[1] != gz_magic[1])
    1380                 :     {
    1381               0 :         delete poVirtualHandle;
    1382               0 :         return NULL;
    1383                 :     }
    1384                 : 
    1385              11 :     if (poHandleLastGZipFile)
    1386              10 :         delete poHandleLastGZipFile;
    1387              11 :     poHandleLastGZipFile = NULL;
    1388                 : 
    1389              11 :     return new VSIGZipHandle(poVirtualHandle, pszFilename + strlen("/vsigzip/"));
    1390                 : }
    1391                 : 
    1392                 : /************************************************************************/
    1393                 : /*                                Stat()                                */
    1394                 : /************************************************************************/
    1395                 : 
    1396              44 : int VSIGZipFilesystemHandler::Stat( const char *pszFilename,
    1397                 :                                     VSIStatBufL *pStatBuf,
    1398                 :                                     int nFlags )
    1399                 : {
    1400              44 :     CPLMutexHolder oHolder(&hMutex);
    1401                 : 
    1402              44 :     memset(pStatBuf, 0, sizeof(VSIStatBufL));
    1403                 : 
    1404              44 :     if (poHandleLastGZipFile != NULL &&
    1405                 :         strcmp(pszFilename+strlen("/vsigzip/"), poHandleLastGZipFile->GetBaseFileName()) == 0)
    1406                 :     {
    1407               5 :         if (poHandleLastGZipFile->GetUncompressedSize() != 0)
    1408                 :         {
    1409               0 :             pStatBuf->st_mode = S_IFREG;
    1410               0 :             pStatBuf->st_size = poHandleLastGZipFile->GetUncompressedSize();
    1411               0 :             return 0;
    1412                 :         }
    1413                 :     }
    1414                 : 
    1415                 :     /* Begin by doing a stat on the real file */
    1416              44 :     int ret = VSIStatExL(pszFilename+strlen("/vsigzip/"), pStatBuf, nFlags);
    1417                 : 
    1418              44 :     if (ret == 0 && (nFlags & VSI_STAT_SIZE_FLAG))
    1419                 :     {
    1420               0 :         CPLString osCacheFilename(pszFilename+strlen("/vsigzip/"));
    1421               0 :         osCacheFilename += ".properties";
    1422                 : 
    1423                 :         /* Can we save a bit of seeking by using a .properties file ? */
    1424               0 :         VSILFILE* fpCacheLength = VSIFOpenL(osCacheFilename.c_str(), "rb");
    1425               0 :         if (fpCacheLength)
    1426                 :         {
    1427                 :             const char* pszLine;
    1428               0 :             GUIntBig nCompressedSize = 0;
    1429               0 :             GUIntBig nUncompressedSize = 0;
    1430               0 :             while ((pszLine = CPLReadLineL(fpCacheLength)) != NULL)
    1431                 :             {
    1432               0 :                 if (EQUALN(pszLine, "compressed_size=", strlen("compressed_size=")))
    1433                 :                 {
    1434               0 :                     const char* pszBuffer = pszLine + strlen("compressed_size=");
    1435                 :                     nCompressedSize = 
    1436               0 :                             CPLScanUIntBig(pszBuffer, strlen(pszBuffer));
    1437                 :                 }
    1438               0 :                 else if (EQUALN(pszLine, "uncompressed_size=", strlen("uncompressed_size=")))
    1439                 :                 {
    1440               0 :                     const char* pszBuffer = pszLine + strlen("uncompressed_size=");
    1441                 :                     nUncompressedSize =
    1442               0 :                              CPLScanUIntBig(pszBuffer, strlen(pszBuffer));
    1443                 :                 }
    1444                 :             }
    1445                 : 
    1446               0 :             VSIFCloseL(fpCacheLength);
    1447                 : 
    1448               0 :             if (nCompressedSize == (GUIntBig) pStatBuf->st_size)
    1449                 :             {
    1450                 :                 /* Patch with the uncompressed size */
    1451               0 :                 pStatBuf->st_size = (long)nUncompressedSize;
    1452                 : 
    1453                 :                 VSIGZipHandle* poHandle =
    1454               0 :                     VSIGZipFilesystemHandler::OpenGZipReadOnly(pszFilename, "rb");
    1455               0 :                 if (poHandle)
    1456                 :                 {
    1457               0 :                     poHandle->SetUncompressedSize(nUncompressedSize);
    1458               0 :                     SaveInfo(poHandle);
    1459               0 :                     delete poHandle;
    1460                 :                 }
    1461                 : 
    1462               0 :                 return ret;
    1463                 :             }
    1464                 :         }
    1465                 : 
    1466                 :         /* No, then seek at the end of the data (slow) */
    1467                 :         VSIGZipHandle* poHandle =
    1468               0 :                 VSIGZipFilesystemHandler::OpenGZipReadOnly(pszFilename, "rb");
    1469               0 :         if (poHandle)
    1470                 :         {
    1471                 :             GUIntBig uncompressed_size;
    1472               0 :             poHandle->Seek(0, SEEK_END);
    1473               0 :             uncompressed_size = (GUIntBig) poHandle->Tell();
    1474               0 :             poHandle->Seek(0, SEEK_SET);
    1475                 : 
    1476                 :             /* Patch with the uncompressed size */
    1477               0 :             pStatBuf->st_size = (long)uncompressed_size;
    1478                 : 
    1479               0 :             delete poHandle;
    1480                 :         }
    1481                 :         else
    1482                 :         {
    1483               0 :             ret = -1;
    1484               0 :         }
    1485                 :     }
    1486                 : 
    1487              44 :     return ret;
    1488                 : }
    1489                 : 
    1490                 : /************************************************************************/
    1491                 : /*                               Unlink()                               */
    1492                 : /************************************************************************/
    1493                 : 
    1494               0 : int VSIGZipFilesystemHandler::Unlink( const char *pszFilename )
    1495                 : {
    1496               0 :     return -1;
    1497                 : }
    1498                 : 
    1499                 : /************************************************************************/
    1500                 : /*                               Rename()                               */
    1501                 : /************************************************************************/
    1502                 : 
    1503               0 : int VSIGZipFilesystemHandler::Rename( const char *oldpath, const char *newpath )
    1504                 : {
    1505               0 :     return -1;
    1506                 : }
    1507                 : 
    1508                 : /************************************************************************/
    1509                 : /*                               Mkdir()                                */
    1510                 : /************************************************************************/
    1511                 : 
    1512               0 : int VSIGZipFilesystemHandler::Mkdir( const char *pszDirname, long nMode )
    1513                 : {
    1514               0 :     return -1;
    1515                 : }
    1516                 : /************************************************************************/
    1517                 : /*                               Rmdir()                                */
    1518                 : /************************************************************************/
    1519                 : 
    1520               0 : int VSIGZipFilesystemHandler::Rmdir( const char *pszDirname )
    1521                 : {
    1522               0 :     return -1;
    1523                 : }
    1524                 : 
    1525                 : /************************************************************************/
    1526                 : /*                             ReadDir()                                */
    1527                 : /************************************************************************/
    1528                 : 
    1529               5 : char** VSIGZipFilesystemHandler::ReadDir( const char *pszDirname )
    1530                 : {
    1531               5 :     return NULL;
    1532                 : }
    1533                 : 
    1534                 : /************************************************************************/
    1535                 : /*                   VSIInstallGZipFileHandler()                        */
    1536                 : /************************************************************************/
    1537                 : 
    1538                 : 
    1539                 : /**
    1540                 :  * \brief Install GZip file system handler. 
    1541                 :  *
    1542                 :  * A special file handler is installed that allows reading on-the-fly and 
    1543                 :  * writing in GZip (.gz) files.
    1544                 :  *
    1545                 :  * All portions of the file system underneath the base
    1546                 :  * path "/vsigzip/" will be handled by this driver.
    1547                 :  *
    1548                 :  * Additional documentation is to be found at http://trac.osgeo.org/gdal/wiki/UserDocs/ReadInZip
    1549                 :  *
    1550                 :  * @since GDAL 1.6.0
    1551                 :  */
    1552                 : 
    1553             757 : void VSIInstallGZipFileHandler(void)
    1554                 : {
    1555             757 :     VSIFileManager::InstallHandler( "/vsigzip/", new VSIGZipFilesystemHandler );
    1556             757 : }
    1557                 : 
    1558                 : 
    1559                 : /************************************************************************/
    1560                 : /* ==================================================================== */
    1561                 : /*                         VSIZipEntryFileOffset                        */
    1562                 : /* ==================================================================== */
    1563                 : /************************************************************************/
    1564                 : 
    1565                 : class VSIZipEntryFileOffset : public VSIArchiveEntryFileOffset
    1566            2443 : {
    1567                 : public:
    1568                 :         unz_file_pos file_pos;
    1569                 : 
    1570            2443 :         VSIZipEntryFileOffset(unz_file_pos file_pos)
    1571            2443 :         {
    1572            2443 :             this->file_pos.pos_in_zip_directory = file_pos.pos_in_zip_directory;
    1573            2443 :             this->file_pos.num_of_file = file_pos.num_of_file;
    1574            2443 :         }
    1575                 : };
    1576                 : 
    1577                 : /************************************************************************/
    1578                 : /* ==================================================================== */
    1579                 : /*                             VSIZipReader                             */
    1580                 : /* ==================================================================== */
    1581                 : /************************************************************************/
    1582                 : 
    1583                 : class VSIZipReader : public VSIArchiveReader
    1584                 : {
    1585                 :     private:
    1586                 :         unzFile unzF;
    1587                 :         unz_file_pos file_pos;
    1588                 :         GUIntBig nNextFileSize;
    1589                 :         CPLString osNextFileName;
    1590                 :         GIntBig nModifiedTime;
    1591                 : 
    1592                 :         void SetInfo();
    1593                 : 
    1594                 :     public:
    1595                 :         VSIZipReader(const char* pszZipFileName);
    1596                 :         virtual ~VSIZipReader();
    1597                 : 
    1598             351 :         int IsValid() { return unzF != NULL; }
    1599                 : 
    1600             263 :         unzFile GetUnzFileHandle() { return unzF; }
    1601                 : 
    1602                 :         virtual int GotoFirstFile();
    1603                 :         virtual int GotoNextFile();
    1604            2443 :         virtual VSIArchiveEntryFileOffset* GetFileOffset() { return new VSIZipEntryFileOffset(file_pos); }
    1605            2446 :         virtual GUIntBig GetFileSize() { return nNextFileSize; }
    1606            2461 :         virtual CPLString GetFileName() { return osNextFileName; }
    1607            3867 :         virtual GIntBig GetModifiedTime() { return nModifiedTime; }
    1608                 :         virtual int GotoFileOffset(VSIArchiveEntryFileOffset* pOffset);
    1609                 : };
    1610                 : 
    1611                 : 
    1612                 : /************************************************************************/
    1613                 : /*                           VSIZipReader()                             */
    1614                 : /************************************************************************/
    1615                 : 
    1616             351 : VSIZipReader::VSIZipReader(const char* pszZipFileName)
    1617                 : {
    1618             351 :     unzF = cpl_unzOpen(pszZipFileName);
    1619             351 :     nNextFileSize = 0;
    1620             351 :     nModifiedTime = 0;
    1621             351 : }
    1622                 : 
    1623                 : /************************************************************************/
    1624                 : /*                          ~VSIZipReader()                             */
    1625                 : /************************************************************************/
    1626                 : 
    1627             351 : VSIZipReader::~VSIZipReader()
    1628                 : {
    1629             351 :     if (unzF)
    1630             345 :         cpl_unzClose(unzF);
    1631             351 : }
    1632                 : 
    1633                 : /************************************************************************/
    1634                 : /*                              SetInfo()                               */
    1635                 : /************************************************************************/
    1636                 : 
    1637            3068 : void VSIZipReader::SetInfo()
    1638                 : {
    1639                 :     char fileName[8193];
    1640                 :     unz_file_info file_info;
    1641            3068 :     cpl_unzGetCurrentFileInfo (unzF, &file_info, fileName, sizeof(fileName) - 1, NULL, 0, NULL, 0);
    1642            3068 :     fileName[sizeof(fileName) - 1] = '\0';
    1643            3068 :     osNextFileName = fileName;
    1644            3068 :     nNextFileSize = file_info.uncompressed_size;
    1645                 :     struct tm brokendowntime;
    1646            3068 :     brokendowntime.tm_sec = file_info.tmu_date.tm_sec;
    1647            3068 :     brokendowntime.tm_min = file_info.tmu_date.tm_min;
    1648            3068 :     brokendowntime.tm_hour = file_info.tmu_date.tm_hour;
    1649            3068 :     brokendowntime.tm_mday = file_info.tmu_date.tm_mday;
    1650            3068 :     brokendowntime.tm_mon = file_info.tmu_date.tm_mon;
    1651            3068 :     brokendowntime.tm_year = file_info.tmu_date.tm_year - 1900; /* the minizip conventions differs from the Unix one */
    1652            3068 :     nModifiedTime = CPLYMDHMSToUnixTime(&brokendowntime);
    1653                 : 
    1654            3068 :     cpl_unzGetFilePos(unzF, &this->file_pos);
    1655            3068 : }
    1656                 : 
    1657                 : /************************************************************************/
    1658                 : /*                           GotoNextFile()                             */
    1659                 : /************************************************************************/
    1660                 : 
    1661            2465 : int VSIZipReader::GotoNextFile()
    1662                 : {
    1663            2465 :     if (cpl_unzGoToNextFile(unzF) != UNZ_OK)
    1664              63 :         return FALSE;
    1665                 : 
    1666            2402 :     SetInfo();
    1667                 : 
    1668            2402 :     return TRUE;
    1669                 : }
    1670                 : 
    1671                 : /************************************************************************/
    1672                 : /*                          GotoFirstFile()                             */
    1673                 : /************************************************************************/
    1674                 : 
    1675             413 : int VSIZipReader::GotoFirstFile()
    1676                 : {
    1677             413 :     if (cpl_unzGoToFirstFile(unzF) != UNZ_OK)
    1678               0 :         return FALSE;
    1679                 : 
    1680             413 :     SetInfo();
    1681                 : 
    1682             413 :     return TRUE;
    1683                 : }
    1684                 : 
    1685                 : /************************************************************************/
    1686                 : /*                         GotoFileOffset()                             */
    1687                 : /************************************************************************/
    1688                 : 
    1689             253 : int VSIZipReader::GotoFileOffset(VSIArchiveEntryFileOffset* pOffset)
    1690                 : {
    1691             253 :     VSIZipEntryFileOffset* pZipEntryOffset = (VSIZipEntryFileOffset*)pOffset;
    1692             253 :     cpl_unzGoToFilePos(unzF, &(pZipEntryOffset->file_pos));
    1693                 : 
    1694             253 :     SetInfo();
    1695                 : 
    1696             253 :     return TRUE;
    1697                 : }
    1698                 : 
    1699                 : /************************************************************************/
    1700                 : /* ==================================================================== */
    1701                 : /*                       VSIZipFilesystemHandler                  */
    1702                 : /* ==================================================================== */
    1703                 : /************************************************************************/
    1704                 : 
    1705                 : class VSIZipWriteHandle;
    1706                 : 
    1707                 : class VSIZipFilesystemHandler : public VSIArchiveFilesystemHandler 
    1708             757 : {
    1709                 :     std::map<CPLString, VSIZipWriteHandle*> oMapZipWriteHandles;
    1710                 : 
    1711                 : public:
    1712                 :     virtual ~VSIZipFilesystemHandler();
    1713                 :     
    1714           16977 :     virtual const char* GetPrefix() { return "/vsizip"; }
    1715                 :     virtual std::vector<CPLString> GetExtensions();
    1716                 :     virtual VSIArchiveReader* CreateReader(const char* pszZipFileName);
    1717                 : 
    1718                 :     virtual VSIVirtualHandle *Open( const char *pszFilename, 
    1719                 :                                     const char *pszAccess);
    1720                 : 
    1721                 :     virtual VSIVirtualHandle *OpenForWrite( const char *pszFilename,
    1722                 :                                             const char *pszAccess );
    1723                 : 
    1724                 :     virtual int      Mkdir( const char *pszDirname, long nMode );
    1725                 :     virtual char   **ReadDir( const char *pszDirname );
    1726                 :     virtual int      Stat( const char *pszFilename, VSIStatBufL *pStatBuf, int nFlags );
    1727                 : 
    1728                 :     void RemoveFromMap(VSIZipWriteHandle* poHandle);
    1729                 : };
    1730                 : 
    1731                 : /************************************************************************/
    1732                 : /* ==================================================================== */
    1733                 : /*                       VSIZipWriteHandle                              */
    1734                 : /* ==================================================================== */
    1735                 : /************************************************************************/
    1736                 : 
    1737                 : class VSIZipWriteHandle : public VSIVirtualHandle
    1738                 : {
    1739                 :    VSIZipFilesystemHandler *poFS;
    1740                 :    void                    *hZIP;
    1741                 :    VSIZipWriteHandle       *poChildInWriting;
    1742                 :    VSIZipWriteHandle       *poParent;
    1743                 :    int                      bAutoDeleteParent;
    1744                 : 
    1745                 :   public:
    1746                 : 
    1747                 :     VSIZipWriteHandle(VSIZipFilesystemHandler* poFS,
    1748                 :                       void *hZIP,
    1749                 :                       VSIZipWriteHandle* poParent);
    1750                 : 
    1751                 :     ~VSIZipWriteHandle();
    1752                 : 
    1753                 :     virtual int       Seek( vsi_l_offset nOffset, int nWhence );
    1754                 :     virtual vsi_l_offset Tell();
    1755                 :     virtual size_t    Read( void *pBuffer, size_t nSize, size_t nMemb );
    1756                 :     virtual size_t    Write( const void *pBuffer, size_t nSize, size_t nMemb );
    1757                 :     virtual int       Eof();
    1758                 :     virtual int       Flush();
    1759                 :     virtual int       Close();
    1760                 : 
    1761                 :     void  StartNewFile(VSIZipWriteHandle* poSubFile);
    1762                 :     void  StopCurrentFile();
    1763              56 :     void* GetHandle() { return hZIP; }
    1764              57 :     VSIZipWriteHandle* GetChildInWriting() { return poChildInWriting; };
    1765              14 :     void SetAutoDeleteParent() { bAutoDeleteParent = TRUE; }
    1766                 : };
    1767                 : 
    1768                 : /************************************************************************/
    1769                 : /*                      ~VSIZipFilesystemHandler()                      */
    1770                 : /************************************************************************/
    1771                 : 
    1772             704 : VSIZipFilesystemHandler::~VSIZipFilesystemHandler()
    1773                 : {
    1774             704 :     std::map<CPLString,VSIZipWriteHandle*>::const_iterator iter;
    1775                 : 
    1776             704 :     for( iter = oMapZipWriteHandles.begin(); iter != oMapZipWriteHandles.end(); ++iter )
    1777                 :     {
    1778                 :         CPLError(CE_Failure, CPLE_AppDefined, "%s has not been closed",
    1779               0 :                  iter->first.c_str());
    1780                 :     }
    1781             704 : }
    1782                 : 
    1783                 : /************************************************************************/
    1784                 : /*                          GetExtensions()                             */
    1785                 : /************************************************************************/
    1786                 : 
    1787          106732 : std::vector<CPLString> VSIZipFilesystemHandler::GetExtensions()
    1788                 : {
    1789          106732 :     std::vector<CPLString> oList;
    1790          106732 :     oList.push_back(".zip");
    1791          106732 :     oList.push_back(".kmz");
    1792          106732 :     oList.push_back(".dwf");
    1793          106732 :     oList.push_back(".ods");
    1794          106732 :     oList.push_back(".xlsx");
    1795               0 :     return oList;
    1796                 : }
    1797                 : 
    1798                 : /************************************************************************/
    1799                 : /*                           CreateReader()                             */
    1800                 : /************************************************************************/
    1801                 : 
    1802             351 : VSIArchiveReader* VSIZipFilesystemHandler::CreateReader(const char* pszZipFileName)
    1803                 : {
    1804             351 :     VSIZipReader* poReader = new VSIZipReader(pszZipFileName);
    1805                 : 
    1806             351 :     if (!poReader->IsValid())
    1807                 :     {
    1808               6 :         delete poReader;
    1809               6 :         return NULL;
    1810                 :     }
    1811                 : 
    1812             345 :     if (!poReader->GotoFirstFile())
    1813                 :     {
    1814               0 :         delete poReader;
    1815               0 :         return NULL;
    1816                 :     }
    1817                 : 
    1818             345 :     return poReader;
    1819                 : }
    1820                 : 
    1821                 : /************************************************************************/
    1822                 : /*                                 Open()                               */
    1823                 : /************************************************************************/
    1824                 : 
    1825             380 : VSIVirtualHandle* VSIZipFilesystemHandler::Open( const char *pszFilename, 
    1826                 :                                                  const char *pszAccess)
    1827                 : {
    1828                 :     char* zipFilename;
    1829             380 :     CPLString osZipInFileName;
    1830                 : 
    1831             380 :     if (strchr(pszAccess, 'w') != NULL)
    1832                 :     {
    1833              62 :         return OpenForWrite(pszFilename, pszAccess);
    1834                 :     }
    1835                 : 
    1836             318 :     if (strchr(pszAccess, '+') != NULL)
    1837                 :     {
    1838                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1839               0 :                  "Random access not supported for /vsizip");
    1840               0 :         return NULL;
    1841                 :     }
    1842                 : 
    1843             318 :     zipFilename = SplitFilename(pszFilename, osZipInFileName, TRUE);
    1844             318 :     if (zipFilename == NULL)
    1845              24 :         return NULL;
    1846                 : 
    1847                 :     {
    1848             294 :         CPLMutexHolder oHolder(&hMutex);
    1849             294 :         if (oMapZipWriteHandles.find(zipFilename) != oMapZipWriteHandles.end() )
    1850                 :         {
    1851                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1852               1 :                     "Cannot read a zip file being written");
    1853               1 :             CPLFree(zipFilename);
    1854               1 :             return NULL;
    1855               0 :         }
    1856                 :     }
    1857                 : 
    1858             293 :     VSIArchiveReader* poReader = OpenArchiveFile(zipFilename, osZipInFileName);
    1859             293 :     if (poReader == NULL)
    1860                 :     {
    1861              30 :         CPLFree(zipFilename);
    1862              30 :         return NULL;
    1863                 :     }
    1864                 : 
    1865                 :     VSIFilesystemHandler *poFSHandler = 
    1866             263 :         VSIFileManager::GetHandler( zipFilename);
    1867                 : 
    1868                 :     VSIVirtualHandle* poVirtualHandle =
    1869             263 :         poFSHandler->Open( zipFilename, "rb" );
    1870                 : 
    1871             263 :     CPLFree(zipFilename);
    1872             263 :     zipFilename = NULL;
    1873                 : 
    1874             263 :     if (poVirtualHandle == NULL)
    1875                 :     {
    1876               0 :         delete poReader;
    1877               0 :         return NULL;
    1878                 :     }
    1879                 : 
    1880             263 :     unzFile unzF = ((VSIZipReader*)poReader)->GetUnzFileHandle();
    1881                 : 
    1882             263 :     cpl_unzOpenCurrentFile(unzF);
    1883                 : 
    1884             263 :     uLong64 pos = cpl_unzGetCurrentFileZStreamPos(unzF);
    1885                 : 
    1886                 :     unz_file_info file_info;
    1887             263 :     cpl_unzGetCurrentFileInfo (unzF, &file_info, NULL, 0, NULL, 0, NULL, 0);
    1888                 : 
    1889             263 :     cpl_unzCloseCurrentFile(unzF);
    1890                 : 
    1891             263 :     delete poReader;
    1892                 : 
    1893                 :     VSIGZipHandle* poGZIPHandle = new VSIGZipHandle(poVirtualHandle,
    1894                 :                              NULL,
    1895                 :                              pos,
    1896                 :                              file_info.compressed_size,
    1897                 :                              file_info.uncompressed_size,
    1898                 :                              file_info.crc,
    1899             263 :                              file_info.compression_method == 0);
    1900                 :     /* Wrap the VSIGZipHandle inside a buffered reader that will */
    1901                 :     /* improve dramatically performance when doing small backward */
    1902                 :     /* seeks */
    1903             526 :     return VSICreateBufferedReaderHandle(poGZIPHandle);
    1904                 : }
    1905                 : 
    1906                 : /************************************************************************/
    1907                 : /*                                Mkdir()                               */
    1908                 : /************************************************************************/
    1909                 : 
    1910               1 : int VSIZipFilesystemHandler::Mkdir( const char *pszDirname, long nMode )
    1911                 : {
    1912               1 :     CPLString osDirname = pszDirname;
    1913               1 :     if (osDirname.size() != 0 && osDirname[osDirname.size() - 1] != '/')
    1914               1 :         osDirname += "/";
    1915               1 :     VSIVirtualHandle* poZIPHandle = OpenForWrite(osDirname, "wb");
    1916               1 :     if (poZIPHandle == NULL)
    1917               0 :         return -1;
    1918               1 :     delete poZIPHandle;
    1919               1 :     return 0;
    1920                 : }
    1921                 : 
    1922                 : /************************************************************************/
    1923                 : /*                                ReadDir()                             */
    1924                 : /************************************************************************/
    1925                 : 
    1926            1569 : char **VSIZipFilesystemHandler::ReadDir( const char *pszDirname )
    1927                 : {
    1928            1569 :     CPLString osInArchiveSubDir;
    1929            1569 :     char* zipFilename = SplitFilename(pszDirname, osInArchiveSubDir, TRUE);
    1930            1569 :     if (zipFilename == NULL)
    1931               3 :         return NULL;
    1932                 : 
    1933                 :     {
    1934            1566 :         CPLMutexHolder oHolder(&hMutex);
    1935                 : 
    1936            1566 :         if (oMapZipWriteHandles.find(zipFilename) != oMapZipWriteHandles.end() )
    1937                 :         {
    1938                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1939               1 :                     "Cannot read a zip file being written");
    1940               1 :             CPLFree(zipFilename);
    1941               1 :             return NULL;
    1942               0 :         }
    1943                 :     }
    1944            1565 :     CPLFree(zipFilename);
    1945                 : 
    1946            1565 :     return VSIArchiveFilesystemHandler::ReadDir(pszDirname);
    1947                 : }
    1948                 : 
    1949                 : 
    1950                 : /************************************************************************/
    1951                 : /*                                 Stat()                               */
    1952                 : /************************************************************************/
    1953                 : 
    1954            1068 : int VSIZipFilesystemHandler::Stat( const char *pszFilename,
    1955                 :                                    VSIStatBufL *pStatBuf, int nFlags )
    1956                 : {
    1957            1068 :     CPLString osInArchiveSubDir;
    1958                 : 
    1959            1068 :     memset(pStatBuf, 0, sizeof(VSIStatBufL));
    1960                 : 
    1961            1068 :     char* zipFilename = SplitFilename(pszFilename, osInArchiveSubDir, TRUE);
    1962            1068 :     if (zipFilename == NULL)
    1963               7 :         return -1;
    1964                 : 
    1965                 :     {
    1966            1061 :         CPLMutexHolder oHolder(&hMutex);
    1967                 : 
    1968            1061 :         if (oMapZipWriteHandles.find(zipFilename) != oMapZipWriteHandles.end() )
    1969                 :         {
    1970                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1971               0 :                     "Cannot read a zip file being written");
    1972               0 :             CPLFree(zipFilename);
    1973               0 :             return -1;
    1974               0 :         }
    1975                 :     }
    1976            1061 :     CPLFree(zipFilename);
    1977                 : 
    1978            1061 :     return VSIArchiveFilesystemHandler::Stat(pszFilename, pStatBuf, nFlags);
    1979                 : }
    1980                 : 
    1981                 : /************************************************************************/
    1982                 : /*                             RemoveFromMap()                           */
    1983                 : /************************************************************************/
    1984                 : 
    1985              21 : void VSIZipFilesystemHandler::RemoveFromMap(VSIZipWriteHandle* poHandle)
    1986                 : {
    1987              21 :     CPLMutexHolder oHolder( &hMutex );
    1988              21 :     std::map<CPLString,VSIZipWriteHandle*>::iterator iter;
    1989                 : 
    1990              21 :     for( iter = oMapZipWriteHandles.begin();
    1991                 :          iter != oMapZipWriteHandles.end(); ++iter )
    1992                 :     {
    1993              21 :         if (iter->second == poHandle)
    1994                 :         {
    1995              21 :             oMapZipWriteHandles.erase(iter);
    1996              21 :             break;
    1997                 :         }
    1998              21 :     }
    1999              21 : }
    2000                 : 
    2001                 : /************************************************************************/
    2002                 : /*                             OpenForWrite()                           */
    2003                 : /************************************************************************/
    2004                 : 
    2005              78 : VSIVirtualHandle* VSIZipFilesystemHandler::OpenForWrite( const char *pszFilename,
    2006                 :                                                          const char *pszAccess)
    2007                 : {
    2008                 :     char* zipFilename;
    2009              78 :     CPLString osZipInFileName;
    2010                 : 
    2011              78 :     CPLMutexHolder oHolder( &hMutex );
    2012                 : 
    2013              78 :     zipFilename = SplitFilename(pszFilename, osZipInFileName, FALSE);
    2014              78 :     if (zipFilename == NULL)
    2015               0 :         return NULL;
    2016              78 :     CPLString osZipFilename = zipFilename;
    2017              78 :     CPLFree(zipFilename);
    2018              78 :     zipFilename = NULL;
    2019                 : 
    2020                 :     /* Invalidate cached file list */
    2021              78 :     std::map<CPLString,VSIArchiveContent*>::iterator iter = oFileList.find(osZipFilename);
    2022              78 :     if (iter != oFileList.end())
    2023                 :     {
    2024               4 :         VSIArchiveContent* content = iter->second;
    2025                 :         int i;
    2026              53 :         for(i=0;i<content->nEntries;i++)
    2027                 :         {
    2028              49 :             delete content->entries[i].file_pos;
    2029              49 :             CPLFree(content->entries[i].fileName);
    2030                 :         }
    2031               4 :         CPLFree(content->entries);
    2032               4 :         delete content;
    2033                 : 
    2034               4 :         oFileList.erase(iter);
    2035                 :     }
    2036                 : 
    2037                 :     VSIZipWriteHandle* poZIPHandle;
    2038                 : 
    2039              78 :     if (oMapZipWriteHandles.find(osZipFilename) != oMapZipWriteHandles.end() )
    2040                 :     {
    2041              57 :         if (strchr(pszAccess, '+') != NULL)
    2042                 :         {
    2043                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2044               0 :                     "Random access not supported for writable file in /vsizip");
    2045               0 :             return NULL;
    2046                 :         }
    2047                 : 
    2048              57 :         poZIPHandle = oMapZipWriteHandles[osZipFilename];
    2049                 : 
    2050              57 :         if (poZIPHandle->GetChildInWriting() != NULL)
    2051                 :         {
    2052                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2053                 :                      "Cannot create %s while another file is being written in the .zip",
    2054               1 :                      osZipInFileName.c_str());
    2055               1 :             return NULL;
    2056                 :         }
    2057                 : 
    2058              56 :         poZIPHandle->StopCurrentFile();
    2059                 : 
    2060                 :         /* Re-add path separator when creating directories */
    2061              56 :         char chLastChar = pszFilename[strlen(pszFilename) - 1];
    2062              56 :         if (chLastChar == '/' || chLastChar == '\\')
    2063               2 :             osZipInFileName += chLastChar;
    2064                 : 
    2065              56 :         if (CPLCreateFileInZip(poZIPHandle->GetHandle(),
    2066                 :                                osZipInFileName, NULL) != CE_None)
    2067               2 :             return NULL;
    2068                 : 
    2069                 :         VSIZipWriteHandle* poChildHandle =
    2070              54 :             new VSIZipWriteHandle(this, NULL, poZIPHandle);
    2071                 : 
    2072              54 :         poZIPHandle->StartNewFile(poChildHandle);
    2073                 : 
    2074              54 :         return poChildHandle;
    2075                 :     }
    2076                 :     else
    2077                 :     {
    2078              21 :         char** papszOptions = NULL;
    2079              21 :         if ((strchr(pszAccess, '+') && osZipInFileName.size() == 0) ||
    2080                 :              osZipInFileName.size() != 0)
    2081                 :         {
    2082                 :             VSIStatBufL sBuf;
    2083              15 :             if (VSIStatExL(osZipFilename, &sBuf, VSI_STAT_EXISTS_FLAG) == 0)
    2084              13 :                 papszOptions = CSLAddNameValue(papszOptions, "APPEND", "TRUE");
    2085                 :         }
    2086                 : 
    2087              21 :         void* hZIP = CPLCreateZip(osZipFilename, papszOptions);
    2088              21 :         CSLDestroy(papszOptions);
    2089                 : 
    2090              21 :         if (hZIP == NULL)
    2091               0 :             return NULL;
    2092                 : 
    2093                 :         oMapZipWriteHandles[osZipFilename] =
    2094              21 :             new VSIZipWriteHandle(this, hZIP, NULL);
    2095                 : 
    2096              21 :         if (osZipInFileName.size() != 0)
    2097                 :         {
    2098                 :             VSIZipWriteHandle* poRes =
    2099              15 :                 (VSIZipWriteHandle*)OpenForWrite(pszFilename, pszAccess);
    2100              15 :             if (poRes == NULL)
    2101                 :             {
    2102               1 :                 delete oMapZipWriteHandles[osZipFilename];
    2103               1 :                 return NULL;
    2104                 :             }
    2105                 : 
    2106              14 :             poRes->SetAutoDeleteParent();
    2107                 : 
    2108              14 :             return poRes;
    2109                 :         }
    2110                 : 
    2111               6 :         return oMapZipWriteHandles[osZipFilename];
    2112               0 :     }
    2113                 : }
    2114                 : 
    2115                 : 
    2116                 : /************************************************************************/
    2117                 : /*                          VSIZipWriteHandle()                         */
    2118                 : /************************************************************************/
    2119                 : 
    2120              75 : VSIZipWriteHandle::VSIZipWriteHandle(VSIZipFilesystemHandler* poFS,
    2121                 :                                      void* hZIP,
    2122              75 :                                      VSIZipWriteHandle* poParent)
    2123                 : {
    2124              75 :     this->poFS = poFS;
    2125              75 :     this->hZIP = hZIP;
    2126              75 :     this->poParent = poParent;
    2127              75 :     poChildInWriting = NULL;
    2128              75 :     bAutoDeleteParent = FALSE;
    2129              75 : }
    2130                 : 
    2131                 : /************************************************************************/
    2132                 : /*                         ~VSIZipWriteHandle()                         */
    2133                 : /************************************************************************/
    2134                 : 
    2135              75 : VSIZipWriteHandle::~VSIZipWriteHandle()
    2136                 : {
    2137              75 :     Close();
    2138              75 : }
    2139                 : 
    2140                 : /************************************************************************/
    2141                 : /*                               Seek()                                 */
    2142                 : /************************************************************************/
    2143                 : 
    2144               0 : int VSIZipWriteHandle::Seek( vsi_l_offset nOffset, int nWhence )
    2145                 : {
    2146                 :     CPLError(CE_Failure, CPLE_NotSupported,
    2147               0 :              "VSIFSeekL() is not supported on writable Zip files");
    2148               0 :     return -1;
    2149                 : }
    2150                 : 
    2151                 : /************************************************************************/
    2152                 : /*                               Tell()                                 */
    2153                 : /************************************************************************/
    2154                 : 
    2155               0 : vsi_l_offset VSIZipWriteHandle::Tell()
    2156                 : {
    2157                 :     CPLError(CE_Failure, CPLE_NotSupported,
    2158               0 :              "VSIFTellL() is not supported on writable Zip files");
    2159               0 :     return 0;
    2160                 : }
    2161                 : 
    2162                 : /************************************************************************/
    2163                 : /*                               Read()                                 */
    2164                 : /************************************************************************/
    2165                 : 
    2166               0 : size_t    VSIZipWriteHandle::Read( void *pBuffer, size_t nSize, size_t nMemb )
    2167                 : {
    2168                 :     CPLError(CE_Failure, CPLE_NotSupported,
    2169               0 :              "VSIFReadL() is not supported on writable Zip files");
    2170               0 :     return 0;
    2171                 : }
    2172                 : 
    2173                 : /************************************************************************/
    2174                 : /*                               Write()                                 */
    2175                 : /************************************************************************/
    2176                 : 
    2177            2048 : size_t    VSIZipWriteHandle::Write( const void *pBuffer, size_t nSize, size_t nMemb )
    2178                 : {
    2179            2048 :     if (poParent == NULL)
    2180                 :     {
    2181                 :         CPLError(CE_Failure, CPLE_NotSupported,
    2182               0 :                  "VSIFWriteL() is not supported on main Zip file or closed subfiles");
    2183               0 :         return 0;
    2184                 :     }
    2185                 : 
    2186            2048 :     if (CPLWriteFileInZip( poParent->hZIP, pBuffer, (int)(nSize * nMemb) ) != CE_None)
    2187               0 :         return 0;
    2188                 : 
    2189            2048 :     return nMemb;
    2190                 : }
    2191                 : 
    2192                 : /************************************************************************/
    2193                 : /*                                Eof()                                 */
    2194                 : /************************************************************************/
    2195                 : 
    2196               0 : int VSIZipWriteHandle::Eof()
    2197                 : {
    2198                 :     CPLError(CE_Failure, CPLE_NotSupported,
    2199               0 :              "VSIFEofL() is not supported on writable Zip files");
    2200               0 :     return FALSE;
    2201                 : }
    2202                 : 
    2203                 : /************************************************************************/
    2204                 : /*                               Flush()                                */
    2205                 : /************************************************************************/
    2206                 : 
    2207               0 : int VSIZipWriteHandle::Flush()
    2208                 : {
    2209                 :     CPLError(CE_Failure, CPLE_NotSupported,
    2210               0 :              "VSIFFlushL() is not supported on writable Zip files");
    2211               0 :     return 0;
    2212                 : }
    2213                 : 
    2214                 : /************************************************************************/
    2215                 : /*                               Close()                                */
    2216                 : /************************************************************************/
    2217                 : 
    2218             134 : int VSIZipWriteHandle::Close()
    2219                 : {
    2220             134 :     if (poParent)
    2221                 :     {
    2222              54 :         CPLCloseFileInZip(poParent->hZIP);
    2223              54 :         poParent->poChildInWriting = NULL;
    2224              54 :         if (bAutoDeleteParent)
    2225              14 :             delete poParent;
    2226              54 :         poParent = NULL;
    2227                 :     }
    2228             134 :     if (poChildInWriting)
    2229                 :     {
    2230               0 :         poChildInWriting->Close();
    2231               0 :         poChildInWriting = NULL;
    2232                 :     }
    2233             134 :     if (hZIP)
    2234                 :     {
    2235              21 :         CPLCloseZip(hZIP);
    2236              21 :         hZIP = NULL;
    2237                 : 
    2238              21 :         poFS->RemoveFromMap(this);
    2239                 :     }
    2240                 : 
    2241             134 :     return 0;
    2242                 : }
    2243                 : 
    2244                 : /************************************************************************/
    2245                 : /*                           StopCurrentFile()                          */
    2246                 : /************************************************************************/
    2247                 : 
    2248              56 : void  VSIZipWriteHandle::StopCurrentFile()
    2249                 : {
    2250              56 :     if (poChildInWriting)
    2251               0 :         poChildInWriting->Close();
    2252              56 :     poChildInWriting = NULL;
    2253              56 : }
    2254                 : 
    2255                 : /************************************************************************/
    2256                 : /*                           StartNewFile()                             */
    2257                 : /************************************************************************/
    2258                 : 
    2259              54 : void  VSIZipWriteHandle::StartNewFile(VSIZipWriteHandle* poSubFile)
    2260                 : {
    2261              54 :     poChildInWriting = poSubFile;
    2262              54 : }
    2263                 : 
    2264                 : /************************************************************************/
    2265                 : /*                    VSIInstallZipFileHandler()                        */
    2266                 : /************************************************************************/
    2267                 : 
    2268                 : 
    2269                 : /**
    2270                 :  * \brief Install ZIP file system handler. 
    2271                 :  *
    2272                 :  * A special file handler is installed that allows reading on-the-fly in ZIP
    2273                 :  * (.zip) archives.
    2274                 :  *
    2275                 :  * All portions of the file system underneath the base path "/vsizip/" will be
    2276                 :  * handled by this driver.
    2277                 :  *
    2278                 :  * The syntax to open a file inside a zip file is /vsizip/path/to/the/file.zip/path/inside/the/zip/file
    2279                 :  * were path/to/the/file.zip is relative or absolute and path/inside/the/zip/file
    2280                 :  * is the relative path to the file inside the archive.
    2281                 :  * 
    2282                 :  * If the path is absolute, it should begin with a / on a Unix-like OS (or C:\ on Windows),
    2283                 :  * so the line looks like /vsizip//home/gdal/...
    2284                 :  * For example gdalinfo /vsizip/myarchive.zip/subdir1/file1.tif
    2285                 :  *
    2286                 :  * Syntaxic sugar : if the .zip file contains only one file located at its root,
    2287                 :  * just mentionning "/vsizip/path/to/the/file.zip" will work
    2288                 :  *
    2289                 :  * VSIStatL() will return the uncompressed size in st_size member and file
    2290                 :  * nature- file or directory - in st_mode member.
    2291                 :  *
    2292                 :  * Directory listing is available through VSIReadDir().
    2293                 :  *
    2294                 :  * Since GDAL 1.8.0, write capabilities are available. They allow creating
    2295                 :  * a new zip file and adding new files to an already existing (or just created)
    2296                 :  * zip file. Read and write operations cannot be interleaved : the new zip must
    2297                 :  * be closed before being re-opened for read.
    2298                 :  *
    2299                 :  * Additional documentation is to be found at http://trac.osgeo.org/gdal/wiki/UserDocs/ReadInZip
    2300                 :  *
    2301                 :  * @since GDAL 1.6.0
    2302                 :  */
    2303                 : 
    2304             757 : void VSIInstallZipFileHandler(void)
    2305                 : {
    2306             757 :     VSIFileManager::InstallHandler( "/vsizip/", new VSIZipFilesystemHandler() );
    2307             757 : }
    2308                 : 
    2309                 : 
    2310                 : /************************************************************************/
    2311                 : /*                         CPLZLibDeflate()                             */
    2312                 : /************************************************************************/
    2313                 : 
    2314                 : /**
    2315                 :  * \brief Compress a buffer with ZLib DEFLATE compression.
    2316                 :  *
    2317                 :  * @param ptr input buffer.
    2318                 :  * @param nBytes size of input buffer in bytes.
    2319                 :  * @param nLevel ZLib compression level (-1 for default).
    2320                 :  * @param outptr output buffer, or NULL to let the function allocate it.
    2321                 :  * @param nOutAvailableBytes size of output buffer if provided, or ignored.
    2322                 :  * @param pnOutBytes pointer to a size_t, where to store the size of the
    2323                 :  *                   output buffer.
    2324                 :  *
    2325                 :  * @return the output buffer (to be freed with VSIFree() if not provided)
    2326                 :  *         or NULL in case of error.
    2327                 :  *
    2328                 :  * @since GDAL 1.10.0
    2329                 :  */
    2330                 : 
    2331              22 : void* CPLZLibDeflate( const void* ptr, size_t nBytes, int nLevel,
    2332                 :                       void* outptr, size_t nOutAvailableBytes,
    2333                 :                       size_t* pnOutBytes )
    2334                 : {
    2335                 :     z_stream strm;
    2336              22 :     strm.zalloc = Z_NULL;
    2337              22 :     strm.zfree = Z_NULL;
    2338              22 :     strm.opaque = Z_NULL;
    2339              22 :     int ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
    2340              22 :     if (ret != Z_OK)
    2341                 :     {
    2342               0 :         if( pnOutBytes != NULL )
    2343               0 :             *pnOutBytes = 0;
    2344               0 :         return NULL;
    2345                 :     }
    2346                 : 
    2347                 :     size_t nTmpSize;
    2348                 :     void* pTmp;
    2349              22 :     if( outptr == NULL )
    2350                 :     {
    2351              20 :         nTmpSize = 8 + nBytes * 2;
    2352              20 :         pTmp = VSIMalloc(nTmpSize);
    2353              20 :         if( pTmp == NULL )
    2354                 :         {
    2355               0 :             deflateEnd(&strm);
    2356               0 :             if( pnOutBytes != NULL )
    2357               0 :                 *pnOutBytes = 0;
    2358               0 :             return NULL;
    2359                 :         }
    2360                 :     }
    2361                 :     else
    2362                 :     {
    2363               2 :         pTmp = outptr;
    2364               2 :         nTmpSize = nOutAvailableBytes;
    2365                 :     }
    2366                 : 
    2367              22 :     strm.avail_in = nBytes;
    2368              22 :     strm.next_in = (Bytef*) ptr;
    2369              22 :     strm.avail_out = nTmpSize;
    2370              22 :     strm.next_out = (Bytef*) pTmp;
    2371              22 :     ret = deflate(&strm, Z_FINISH);
    2372              22 :     if( ret != Z_STREAM_END )
    2373                 :     {
    2374               0 :         if( pTmp != outptr )
    2375               0 :             VSIFree(pTmp);
    2376               0 :         if( pnOutBytes != NULL )
    2377               0 :             *pnOutBytes = 0;
    2378               0 :         return NULL;
    2379                 :     }
    2380              22 :     if( pnOutBytes != NULL )
    2381              22 :         *pnOutBytes = nTmpSize - strm.avail_out;
    2382              22 :     deflateEnd(&strm);
    2383              22 :     return pTmp;
    2384                 : }
    2385                 : 
    2386                 : /************************************************************************/
    2387                 : /*                         CPLZLibInflate()                             */
    2388                 : /************************************************************************/
    2389                 : 
    2390                 : /**
    2391                 :  * \brief Uncompress a buffer compressed with ZLib DEFLATE compression.
    2392                 :  *
    2393                 :  * @param ptr input buffer.
    2394                 :  * @param nBytes size of input buffer in bytes.
    2395                 :  * @param outptr output buffer, or NULL to let the function allocate it.
    2396                 :  * @param nOutAvailableBytes size of output buffer if provided, or ignored.
    2397                 :  * @param pnOutBytes pointer to a size_t, where to store the size of the
    2398                 :  *                   output buffer.
    2399                 :  *
    2400                 :  * @return the output buffer (to be freed with VSIFree() if not provided)
    2401                 :  *         or NULL in case of error.
    2402                 :  *
    2403                 :  * @since GDAL 1.10.0
    2404                 :  */
    2405                 : 
    2406              91 : void* CPLZLibInflate( const void* ptr, size_t nBytes,
    2407                 :                       void* outptr, size_t nOutAvailableBytes,
    2408                 :                       size_t* pnOutBytes )
    2409                 : {
    2410                 :     z_stream strm;
    2411              91 :     strm.zalloc = Z_NULL;
    2412              91 :     strm.zfree = Z_NULL;
    2413              91 :     strm.opaque = Z_NULL;
    2414              91 :     strm.avail_in = nBytes;
    2415              91 :     strm.next_in = (Bytef*) ptr;
    2416              91 :     int ret = inflateInit(&strm);
    2417              91 :     if (ret != Z_OK)
    2418                 :     {
    2419               0 :         if( pnOutBytes != NULL )
    2420               0 :             *pnOutBytes = 0;
    2421               0 :         return NULL;
    2422                 :     }
    2423                 : 
    2424                 :     size_t nTmpSize;
    2425                 :     char* pszTmp;
    2426              91 :     if( outptr == NULL )
    2427                 :     {
    2428              43 :         nTmpSize = 2 * nBytes;
    2429              43 :         pszTmp = (char*) VSIMalloc(nTmpSize + 1);
    2430              43 :         if( pszTmp == NULL )
    2431                 :         {
    2432               0 :             inflateEnd(&strm);
    2433               0 :             if( pnOutBytes != NULL )
    2434               0 :                 *pnOutBytes = 0;
    2435               0 :             return NULL;
    2436                 :         }
    2437                 :     }
    2438                 :     else
    2439                 :     {
    2440              48 :         pszTmp = (char*) outptr;
    2441              48 :         nTmpSize = nOutAvailableBytes;
    2442                 :     }
    2443                 : 
    2444              91 :     strm.avail_out = nTmpSize;
    2445              91 :     strm.next_out = (Bytef*) pszTmp;
    2446                 : 
    2447              28 :     while(TRUE)
    2448                 :     {
    2449             119 :         ret = inflate(&strm, Z_FINISH);
    2450             119 :         if( ret == Z_BUF_ERROR )
    2451                 :         {
    2452              28 :             if( outptr == pszTmp )
    2453                 :             {
    2454               0 :                 inflateEnd(&strm);
    2455               0 :                 if( pnOutBytes != NULL )
    2456               0 :                     *pnOutBytes = 0;
    2457               0 :                 return NULL;
    2458                 :             }
    2459                 : 
    2460              28 :             size_t nAlreadyWritten = nTmpSize - strm.avail_out;
    2461              28 :             nTmpSize = nTmpSize * 2;
    2462              28 :             char* pszTmpNew = (char*) VSIRealloc(pszTmp, nTmpSize + 1);
    2463              28 :             if( pszTmpNew == NULL )
    2464                 :             {
    2465               0 :                 VSIFree(pszTmp);
    2466               0 :                 inflateEnd(&strm);
    2467               0 :                 if( pnOutBytes != NULL )
    2468               0 :                     *pnOutBytes = 0;
    2469               0 :                 return NULL;
    2470                 :             }
    2471              28 :             pszTmp = pszTmpNew;
    2472              28 :             strm.avail_out = nTmpSize - nAlreadyWritten;
    2473              28 :             strm.next_out = (Bytef*) (pszTmp + nAlreadyWritten);
    2474                 :         }
    2475                 :         else
    2476                 :             break;
    2477                 :     }
    2478                 : 
    2479              91 :     if (ret == Z_OK || ret == Z_STREAM_END)
    2480                 :     {
    2481              90 :         size_t nOutBytes = nTmpSize - strm.avail_out;
    2482                 :         /* Nul-terminate if possible */
    2483              90 :         if( outptr != pszTmp || nOutBytes < nTmpSize )
    2484              42 :             pszTmp[nOutBytes] = '\0';
    2485              90 :         inflateEnd(&strm);
    2486              90 :         if( pnOutBytes != NULL )
    2487               3 :             *pnOutBytes = nOutBytes;
    2488              90 :         return pszTmp;
    2489                 :     }
    2490                 :     else
    2491                 :     {
    2492               1 :         if( outptr != pszTmp )
    2493               1 :             VSIFree(pszTmp);
    2494               1 :         inflateEnd(&strm);
    2495               1 :         if( pnOutBytes != NULL )
    2496               1 :             *pnOutBytes = 0;
    2497               1 :         return NULL;
    2498                 :     }
    2499                 : }

Generated by: LCOV version 1.7