LCOV - code coverage report
Current view: directory - port - cpl_vsil_gzip.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 821 618 75.3 %
Date: 2011-12-18 Functions: 99 64 64.6 %

       1                 : /******************************************************************************
       2                 :  * $Id: cpl_vsil_gzip.cpp 23588 2011-12-17 13:36:47Z 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 23588 2011-12-17 13:36:47Z 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              94 :     vsi_l_offset      GetLastReadOffset() { return nLastReadOffset; }
     179             290 :     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              47 : VSIGZipHandle* VSIGZipHandle::Duplicate()
     216                 : {
     217              47 :     CPLAssert (offset == 0);
     218              47 :     CPLAssert (compressed_size != 0);
     219              47 :     CPLAssert (pszBaseFileName != NULL);
     220                 : 
     221                 :     VSIFilesystemHandler *poFSHandler = 
     222              47 :         VSIFileManager::GetHandler( pszBaseFileName );
     223                 : 
     224                 :     VSIVirtualHandle* poNewBaseHandle =
     225              47 :         poFSHandler->Open( pszBaseFileName, "rb" );
     226                 : 
     227              47 :     if (poNewBaseHandle == NULL)
     228               0 :         return NULL;
     229                 : 
     230                 :     VSIGZipHandle* poHandle = new VSIGZipHandle(poNewBaseHandle,
     231                 :                                                 pszBaseFileName,
     232                 :                                                 0,
     233                 :                                                 compressed_size,
     234              47 :                                                 uncompressed_size);
     235                 : 
     236              47 :     poHandle->nLastReadOffset = nLastReadOffset;
     237                 : 
     238                 :     /* Most important : duplicate the snapshots ! */
     239                 : 
     240                 :     unsigned int i;
     241              50 :     for(i=0;i<compressed_size / snapshot_byte_interval + 1;i++)
     242                 :     {
     243              47 :         if (snapshots[i].uncompressed_pos == 0)
     244              44 :             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              47 :     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             108 : 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             108 :                              int transparent)
     279                 : {
     280             108 :     this->poBaseHandle = poBaseHandle;
     281             108 :     this->expected_crc = expected_crc;
     282             108 :     this->pszBaseFileName = (pszBaseFileName) ? CPLStrdup(pszBaseFileName) : NULL;
     283             108 :     this->offset = offset;
     284             108 :     if (compressed_size)
     285                 :     {
     286              97 :         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             108 :     this->uncompressed_size = uncompressed_size;
     295             108 :     offsetEndCompressedData = offset + compressed_size;
     296                 : 
     297             108 :     VSIFSeekL((VSILFILE*)poBaseHandle, offset, SEEK_SET);
     298                 : 
     299             108 :     nLastReadOffset = 0;
     300             108 :     stream.zalloc = (alloc_func)0;
     301             108 :     stream.zfree = (free_func)0;
     302             108 :     stream.opaque = (voidpf)0;
     303             108 :     stream.next_in = inbuf = Z_NULL;
     304             108 :     stream.next_out = outbuf = Z_NULL;
     305             108 :     stream.avail_in = stream.avail_out = 0;
     306             108 :     z_err = Z_OK;
     307             108 :     z_eof = 0;
     308             108 :     in = 0;
     309             108 :     out = 0;
     310             108 :     crc = crc32(0L, Z_NULL, 0);
     311             108 :     this->transparent = transparent;
     312                 : 
     313             108 :     stream.next_in  = inbuf = (Byte*)ALLOC(Z_BUFSIZE);
     314                 : 
     315             108 :     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             108 :     if (err != Z_OK || inbuf == Z_NULL) {
     323               0 :         CPLError(CE_Failure, CPLE_NotSupported, "inflateInit2 init failed");
     324                 :     }
     325             108 :     stream.avail_out = Z_BUFSIZE;
     326                 : 
     327             108 :     if (offset == 0) check_header(); /* skip the .gz header */
     328             108 :     startOff = VSIFTellL((VSILFILE*)poBaseHandle) - stream.avail_in;
     329                 : 
     330             108 :     if (transparent == 0)
     331                 :     {
     332             106 :         snapshot_byte_interval = MAX(Z_BUFSIZE, compressed_size / 100);
     333             106 :         snapshots = (GZipSnapshot*)CPLCalloc(sizeof(GZipSnapshot), (size_t) (compressed_size / snapshot_byte_interval + 1));
     334                 :     }
     335                 :     else
     336                 :     {
     337               2 :         snapshots = NULL;
     338                 :     }
     339             108 : }
     340                 : 
     341                 : /************************************************************************/
     342                 : /*                      ~VSIGZipHandle()                                */
     343                 : /************************************************************************/
     344                 : 
     345             108 : VSIGZipHandle::~VSIGZipHandle()
     346                 : {
     347                 :     
     348             108 :     if (pszBaseFileName)
     349                 :     {
     350                 :         VSIFilesystemHandler *poFSHandler = 
     351              58 :             VSIFileManager::GetHandler( "/vsigzip/" );
     352              58 :         ((VSIGZipFilesystemHandler*)poFSHandler)->SaveInfo(this);
     353                 :     }
     354                 :     
     355             108 :     if (stream.state != NULL) {
     356             108 :         inflateEnd(&(stream));
     357                 :     }
     358                 : 
     359             108 :     TRYFREE(inbuf);
     360             108 :     TRYFREE(outbuf);
     361                 : 
     362             108 :     if (snapshots != NULL)
     363                 :     {
     364                 :         unsigned int i;
     365             238 :         for(i=0;i<compressed_size / snapshot_byte_interval + 1;i++)
     366                 :         {
     367             132 :             if (snapshots[i].uncompressed_pos)
     368                 :             {
     369              66 :                 inflateEnd(&(snapshots[i].stream));
     370                 :             }
     371                 :         }
     372             106 :         CPLFree(snapshots);
     373                 :     }
     374             108 :     CPLFree(pszBaseFileName);
     375                 : 
     376             108 :     if (poBaseHandle)
     377              97 :         VSIFCloseL((VSILFILE*)poBaseHandle);
     378             108 : }
     379                 : 
     380                 : /************************************************************************/
     381                 : /*                      check_header()                                  */
     382                 : /************************************************************************/
     383                 : 
     384              77 : 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              77 :     len = stream.avail_in;
     395              77 :     if (len < 2) {
     396              77 :         if (len) inbuf[0] = stream.next_in[0];
     397              77 :         errno = 0;
     398              77 :         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              77 :         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              77 :         if (len == 0 /* && ferror(file)*/)
     407                 :         {
     408              19 :             if (VSIFTellL((VSILFILE*)poBaseHandle) != offsetEndCompressedData)
     409               0 :                 z_err = Z_ERRNO;
     410                 :         }
     411              77 :         stream.avail_in += len;
     412              77 :         stream.next_in = inbuf;
     413              77 :         if (stream.avail_in < 2) {
     414              19 :             transparent = stream.avail_in;
     415              19 :             return;
     416                 :         }
     417                 :     }
     418                 : 
     419                 :     /* Peek ahead to check the gzip magic header */
     420             174 :     if (stream.next_in[0] != gz_magic[0] ||
     421             116 :         stream.next_in[1] != gz_magic[1]) {
     422               0 :         transparent = 1;
     423               0 :         return;
     424                 :     }
     425              58 :     stream.avail_in -= 2;
     426              58 :     stream.next_in += 2;
     427                 : 
     428                 :     /* Check the rest of the gzip header */
     429              58 :     method = get_byte();
     430              58 :     flags = get_byte();
     431              58 :     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              58 :     for (len = 0; len < 6; len++) (void)get_byte();
     438                 : 
     439              58 :     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              58 :     if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
     446               0 :         while ((c = get_byte()) != 0 && c != EOF) ;
     447                 :     }
     448              58 :     if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
     449               0 :         while ((c = get_byte()) != 0 && c != EOF) ;
     450                 :     }
     451              58 :     if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
     452               0 :         for (len = 0; len < 2; len++) (void)get_byte();
     453                 :     }
     454              58 :     z_err = z_eof ? Z_DATA_ERROR : Z_OK;
     455                 : }
     456                 : 
     457                 : /************************************************************************/
     458                 : /*                            get_byte()                                */
     459                 : /************************************************************************/
     460                 : 
     461             616 : int VSIGZipHandle::get_byte()
     462                 : {
     463             616 :     if (z_eof) return EOF;
     464             616 :     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             616 :     stream.avail_in--;
     484             616 :     return *(stream.next_in)++;
     485                 : }
     486                 : 
     487                 : /************************************************************************/
     488                 : /*                            gzrewind()                                */
     489                 : /************************************************************************/
     490                 : 
     491              56 : int VSIGZipHandle::gzrewind ()
     492                 : {
     493              56 :     z_err = Z_OK;
     494              56 :     z_eof = 0;
     495              56 :     stream.avail_in = 0;
     496              56 :     stream.next_in = inbuf;
     497              56 :     crc = crc32(0L, Z_NULL, 0);
     498              56 :     if (!transparent) (void)inflateReset(&stream);
     499              56 :     in = 0;
     500              56 :     out = 0;
     501              56 :     return VSIFSeekL((VSILFILE*)poBaseHandle, startOff, SEEK_SET);
     502                 : }
     503                 : 
     504                 : /************************************************************************/
     505                 : /*                              Seek()                                  */
     506                 : /************************************************************************/
     507                 : 
     508             311 : 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             311 :     int ret = gzseek(nOffset, nWhence);
     514             311 :     return (ret >= 0) ? 0 : ret;
     515                 : }
     516                 : 
     517                 : /************************************************************************/
     518                 : /*                            gzseek()                                  */
     519                 : /************************************************************************/
     520                 : 
     521             311 : int VSIGZipHandle::gzseek( vsi_l_offset offset, int whence )
     522                 : {
     523             311 :     vsi_l_offset original_offset = offset;
     524             311 :     int original_nWhence = whence;
     525                 : 
     526                 :     if (ENABLE_DEBUG) CPLDebug("GZIP", "Seek(" CPL_FRMT_GUIB ",%d)", offset, whence);
     527                 : 
     528             311 :     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             308 :     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              20 :         if (offset == 0 && uncompressed_size != 0)
     586                 :         {
     587              14 :             out = uncompressed_size;
     588              14 :             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               6 :         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               6 :         whence = SEEK_CUR;
     601               6 :         offset = 1024 * 1024 * 1024;
     602               6 :         offset *= 1024 * 1024;
     603                 :     }
     604                 : 
     605             294 :     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             294 :     if (whence == SEEK_CUR) {
     615               6 :         offset += out;
     616                 :     }
     617                 : 
     618                 :     /* For a negative seek, rewind and use positive seek */
     619             294 :     if (offset >= out) {
     620             238 :         offset -= out;
     621              56 :     } else if (gzrewind() < 0) {
     622               0 :             CPL_VSIL_GZ_RETURN_MINUS_ONE();
     623               0 :             return -1L;
     624                 :     }
     625                 :     
     626                 :     unsigned int i;
     627             298 :     for(i=0;i<compressed_size / snapshot_byte_interval + 1;i++)
     628                 :     {
     629             298 :         if (snapshots[i].uncompressed_pos == 0)
     630             222 :             break;
     631              99 :         if (snapshots[i].out <= out + offset &&
     632              23 :             (i == compressed_size / snapshot_byte_interval || snapshots[i+1].out == 0 || snapshots[i+1].out > out+offset))
     633                 :         {
     634              72 :             if (out >= snapshots[i].out)
     635              72 :                 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             294 :     if (offset != 0 && outbuf == Z_NULL) {
     659              41 :         outbuf = (Byte*)ALLOC(Z_BUFSIZE);
     660              41 :         if (outbuf == Z_NULL) {
     661               0 :             CPL_VSIL_GZ_RETURN_MINUS_ONE();
     662               0 :             return -1L;
     663                 :         }
     664                 :     }
     665                 : 
     666             294 :     if (original_nWhence == SEEK_END && z_err == Z_STREAM_END)
     667                 :     {
     668                 :         if (ENABLE_DEBUG) CPLDebug("GZIP", "gzseek return " CPL_FRMT_GUIB, out);
     669               1 :         return (int) out;
     670                 :     }
     671                 : 
     672             788 :     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               5 :             if (size != read_size)
     684                 :             {
     685               5 :                 z_err = Z_STREAM_END;
     686               5 :                 break;
     687                 :             }
     688                 :         }
     689             202 :         offset -= read_size;
     690                 :     }
     691                 :     if (ENABLE_DEBUG) CPLDebug("GZIP", "gzseek return " CPL_FRMT_GUIB, out);
     692                 : 
     693             292 :     if (original_offset == 0 && original_nWhence == SEEK_END)
     694                 :     {
     695               5 :         uncompressed_size = out;
     696                 : 
     697               5 :         if (pszBaseFileName)
     698                 :         {
     699               5 :             CPLString osCacheFilename (pszBaseFileName);
     700               5 :             osCacheFilename += ".properties";
     701                 : 
     702                 :             /* Write a .properties file to avoid seeking next time */
     703               5 :             VSILFILE* fpCacheLength = VSIFOpenL(osCacheFilename.c_str(), "wb");
     704               5 :             if (fpCacheLength)
     705                 :             {
     706                 :                 char* pszFirstNonSpace;
     707                 :                 char szBuffer[32];
     708               5 :                 szBuffer[31] = 0;
     709                 : 
     710               5 :                 CPLPrintUIntBig(szBuffer, compressed_size, 31);
     711               5 :                 pszFirstNonSpace = szBuffer;
     712               5 :                 while (*pszFirstNonSpace == ' ') pszFirstNonSpace ++;
     713               5 :                 VSIFPrintfL(fpCacheLength, "compressed_size=%s\n", pszFirstNonSpace);
     714                 : 
     715               5 :                 CPLPrintUIntBig(szBuffer, uncompressed_size, 31);
     716               5 :                 pszFirstNonSpace = szBuffer;
     717               5 :                 while (*pszFirstNonSpace == ' ') pszFirstNonSpace ++;
     718               5 :                 VSIFPrintfL(fpCacheLength, "uncompressed_size=%s\n", pszFirstNonSpace);
     719                 : 
     720               5 :                 VSIFCloseL(fpCacheLength);
     721               5 :             }
     722                 :         }
     723                 :     }
     724                 : 
     725             292 :     return (int) out;
     726                 : }
     727                 : 
     728                 : /************************************************************************/
     729                 : /*                              Tell()                                  */
     730                 : /************************************************************************/
     731                 : 
     732              21 : vsi_l_offset VSIGZipHandle::Tell()
     733                 : {
     734                 :     if (ENABLE_DEBUG) CPLDebug("GZIP", "Tell() = " CPL_FRMT_GUIB, out);
     735              21 :     return out;
     736                 : }
     737                 : 
     738                 : /************************************************************************/
     739                 : /*                              Read()                                  */
     740                 : /************************************************************************/
     741                 : 
     742            1763 : 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            1763 :     unsigned len = nSize * nMemb;
     747                 : 
     748            1763 :     Bytef *pStart = (Bytef*)buf; /* startOffing point for crc computation */
     749                 :     Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
     750                 : 
     751            1763 :     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            1763 :     if  (z_err == Z_STREAM_END)
     757                 :     {
     758                 :         if (ENABLE_DEBUG) CPLDebug("GZIP", "Read: Eof");
     759               7 :         return 0;  /* EOF */
     760                 :     }
     761                 : 
     762            1756 :     next_out = (Byte*)buf;
     763            1756 :     stream.next_out = (Bytef*)buf;
     764            1756 :     stream.avail_out = len;
     765                 : 
     766            5217 :     while  (stream.avail_out != 0) {
     767                 : 
     768            1758 :         if  (transparent) {
     769                 :             /* Copy first the lookahead bytes: */
     770               2 :             uInt nRead = 0;
     771               2 :             uInt n = stream.avail_in;
     772               2 :             if (n > stream.avail_out) n = stream.avail_out;
     773               2 :             if (n > 0) {
     774               0 :                 memcpy (stream.next_out, stream.next_in, n);
     775               0 :                 next_out += n;
     776               0 :                 stream.next_out = next_out;
     777               0 :                 stream.next_in   += n;
     778               0 :                 stream.avail_out -= n;
     779               0 :                 stream.avail_in  -= n;
     780               0 :                 nRead += n;
     781                 :             }
     782               2 :             if  (stream.avail_out > 0) {
     783               2 :                 uInt nToRead = (uInt) MIN(compressed_size - (in + nRead), stream.avail_out);
     784                 :                 uInt nReadFromFile =
     785               2 :                     (uInt)VSIFReadL(next_out, 1, nToRead, (VSILFILE*)poBaseHandle);
     786               2 :                 stream.avail_out -= nReadFromFile;
     787               2 :                 nRead += nReadFromFile;
     788                 :             }
     789               2 :             in  += nRead;
     790               2 :             out += nRead;
     791               2 :             if (nRead < len) z_eof = 1;
     792                 :             if (ENABLE_DEBUG) CPLDebug("GZIP", "Read return %d", (int)(nRead / nSize));
     793               2 :             return (int)nRead / nSize;
     794                 :         }
     795            1756 :         if  (stream.avail_in == 0 && !z_eof)
     796                 :         {
     797             102 :             vsi_l_offset uncompressed_pos = VSIFTellL((VSILFILE*)poBaseHandle);
     798             102 :             GZipSnapshot* snapshot = &snapshots[(uncompressed_pos - startOff) / snapshot_byte_interval];
     799             102 :             if (snapshot->uncompressed_pos == 0)
     800                 :             {
     801              63 :                 snapshot->crc = crc32 (crc, pStart, (uInt) (stream.next_out - pStart));
     802                 :                 if (ENABLE_DEBUG)
     803                 :                     CPLDebug("SNAPSHOT",
     804                 :                              "creating snapshot %d : uncompressed_pos=" CPL_FRMT_GUIB
     805                 :                                                    " in=" CPL_FRMT_GUIB
     806                 :                                                    " out=" CPL_FRMT_GUIB
     807                 :                                                    " crc=%X",
     808                 :                           (int)((uncompressed_pos - startOff) / snapshot_byte_interval),
     809                 :                           uncompressed_pos, in, out, (unsigned int)snapshot->crc);
     810              63 :                 snapshot->uncompressed_pos = uncompressed_pos;
     811              63 :                 inflateCopy(&snapshot->stream, &stream);
     812              63 :                 snapshot->transparent = transparent;
     813              63 :                 snapshot->in = in;
     814              63 :                 snapshot->out = out;
     815                 : 
     816              63 :                 if (out > nLastReadOffset)
     817               1 :                     nLastReadOffset = out;
     818                 :             }
     819                 : 
     820             102 :             errno = 0;
     821             102 :             stream.avail_in = (uInt)VSIFReadL(inbuf, 1, Z_BUFSIZE, (VSILFILE*)poBaseHandle);
     822                 :             if (ENABLE_DEBUG)
     823                 :                 CPLDebug("GZIP", CPL_FRMT_GUIB " " CPL_FRMT_GUIB,
     824                 :                                  VSIFTellL((VSILFILE*)poBaseHandle), offsetEndCompressedData);
     825             102 :             if (VSIFTellL((VSILFILE*)poBaseHandle) > offsetEndCompressedData)
     826                 :             {
     827                 :                 if (ENABLE_DEBUG) CPLDebug("GZIP", "avail_in before = %d", stream.avail_in);
     828              72 :                 stream.avail_in = stream.avail_in + (uInt) (offsetEndCompressedData - VSIFTellL((VSILFILE*)poBaseHandle));
     829              72 :                 VSIFSeekL((VSILFILE*)poBaseHandle, offsetEndCompressedData, SEEK_SET);
     830              72 :                 if (ENABLE_DEBUG) CPLDebug("GZIP", "avail_in after = %d", stream.avail_in);
     831                 :             }
     832             102 :             if  (stream.avail_in == 0) {
     833               0 :                 z_eof = 1;
     834               0 :                 if (VSIFTellL((VSILFILE*)poBaseHandle) != offsetEndCompressedData)
     835                 :                 {
     836               0 :                     z_err = Z_ERRNO;
     837               0 :                     break;
     838                 :                 }
     839                 :                 /*if (ferror (file)) {
     840                 :                     z_err = Z_ERRNO;
     841                 :                     break;
     842                 :                 }*/
     843                 :             }
     844             102 :             stream.next_in = inbuf;
     845                 :         }
     846            1756 :         in += stream.avail_in;
     847            1756 :         out += stream.avail_out;
     848            1756 :         z_err = inflate(& (stream), Z_NO_FLUSH);
     849            1756 :         in -= stream.avail_in;
     850            1756 :         out -= stream.avail_out;
     851                 :         
     852            1756 :         if  (z_err == Z_STREAM_END) {
     853                 :             /* Check CRC and original size */
     854              51 :             crc = crc32 (crc, pStart, (uInt) (stream.next_out - pStart));
     855              51 :             pStart = stream.next_out;
     856              51 :             if (expected_crc)
     857                 :             {
     858              32 :                 if (ENABLE_DEBUG) CPLDebug("GZIP", "Computed CRC = %X. Expected CRC = %X", (unsigned int)crc, expected_crc);
     859                 :             }
     860              51 :             if (expected_crc != 0 && expected_crc != crc)
     861                 :             {
     862               0 :                 CPLError(CE_Failure, CPLE_FileIO, "CRC error. Got %X instead of %X", (unsigned int)crc, expected_crc);
     863               0 :                 z_err = Z_DATA_ERROR;
     864                 :             }
     865              51 :             else if (expected_crc == 0)
     866                 :             {
     867              19 :                 unsigned int read_crc = getLong();
     868              19 :                 if (read_crc != crc)
     869                 :                 {
     870               0 :                     CPLError(CE_Failure, CPLE_FileIO, "CRC error. Got %X instead of %X", (unsigned int)crc, read_crc);
     871               0 :                     z_err = Z_DATA_ERROR;
     872                 :                 }
     873                 :                 else
     874                 :                 {
     875              19 :                     (void)getLong();
     876                 :                     /* The uncompressed length returned by above getlong() may be
     877                 :                     * different from out in case of concatenated .gz files.
     878                 :                     * Check for such files:
     879                 :                     */
     880              19 :                     check_header();
     881              19 :                     if  (z_err == Z_OK) {
     882               0 :                         inflateReset(& (stream));
     883               0 :                         crc = crc32(0L, Z_NULL, 0);
     884                 :                     }
     885                 :                 }
     886                 :             }
     887                 :         }
     888            1756 :         if  (z_err != Z_OK || z_eof) break;
     889                 :     }
     890            1754 :     crc = crc32 (crc, pStart, (uInt) (stream.next_out - pStart));
     891                 : 
     892            1754 :     if (len == stream.avail_out &&
     893                 :             (z_err == Z_DATA_ERROR || z_err == Z_ERRNO))
     894                 :     {
     895               0 :         CPL_VSIL_GZ_RETURN_MINUS_ONE();
     896               0 :         return 0;
     897                 :     }
     898                 :     if (ENABLE_DEBUG)
     899                 :         CPLDebug("GZIP", "Read return %d (z_err=%d, z_eof=%d)",
     900                 :                 (int)((len - stream.avail_out) / nSize), z_err, z_eof);
     901            1754 :     return (int)(len - stream.avail_out) / nSize;
     902                 : }
     903                 : 
     904                 : /************************************************************************/
     905                 : /*                              getLong()                               */
     906                 : /************************************************************************/
     907                 : 
     908              38 : uLong VSIGZipHandle::getLong ()
     909                 : {
     910              38 :     uLong x = (uLong)get_byte();
     911                 :     int c;
     912                 : 
     913              38 :     x += ((uLong)get_byte())<<8;
     914              38 :     x += ((uLong)get_byte())<<16;
     915              38 :     c = get_byte();
     916              38 :     if (c == EOF) z_err = Z_DATA_ERROR;
     917              38 :     x += ((uLong)c)<<24;
     918              38 :     return x;
     919                 : }
     920                 : 
     921                 : /************************************************************************/
     922                 : /*                              Write()                                 */
     923                 : /************************************************************************/
     924                 : 
     925               0 : size_t VSIGZipHandle::Write( const void *pBuffer, size_t nSize, size_t nMemb )
     926                 : {
     927               0 :     CPLError(CE_Failure, CPLE_NotSupported, "VSIFWriteL is not supported on GZip streams");
     928               0 :     return 0;
     929                 : }
     930                 : 
     931                 : /************************************************************************/
     932                 : /*                               Eof()                                  */
     933                 : /************************************************************************/
     934                 : 
     935                 : 
     936            1555 : int VSIGZipHandle::Eof()
     937                 : {
     938                 :     if (ENABLE_DEBUG) CPLDebug("GZIP", "Eof()");
     939            1555 :     if (z_eof) return 1;
     940            1553 :     return z_err == Z_STREAM_END;
     941                 : }
     942                 : 
     943                 : /************************************************************************/
     944                 : /*                              Flush()                                 */
     945                 : /************************************************************************/
     946                 : 
     947               0 : int VSIGZipHandle::Flush()
     948                 : {
     949               0 :     return 0;
     950                 : }
     951                 : 
     952                 : /************************************************************************/
     953                 : /*                              Close()                                 */
     954                 : /************************************************************************/
     955                 : 
     956              97 : int VSIGZipHandle::Close()
     957                 : {
     958              97 :     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                 : 
     978                 :   public:
     979                 : 
     980                 :     VSIGZipWriteHandle(VSIVirtualHandle* poBaseHandle);
     981                 : 
     982                 :     ~VSIGZipWriteHandle();
     983                 : 
     984                 :     virtual int       Seek( vsi_l_offset nOffset, int nWhence );
     985                 :     virtual vsi_l_offset Tell();
     986                 :     virtual size_t    Read( void *pBuffer, size_t nSize, size_t nMemb );
     987                 :     virtual size_t    Write( const void *pBuffer, size_t nSize, size_t nMemb );
     988                 :     virtual int       Eof();
     989                 :     virtual int       Flush();
     990                 :     virtual int       Close();
     991                 : };
     992                 : 
     993                 : /************************************************************************/
     994                 : /*                         VSIGZipWriteHandle()                         */
     995                 : /************************************************************************/
     996                 : 
     997              24 : VSIGZipWriteHandle::VSIGZipWriteHandle( VSIVirtualHandle *poBaseHandle )
     998                 : 
     999                 : {
    1000              24 :     nCurOffset = 0;
    1001                 : 
    1002              24 :     this->poBaseHandle = poBaseHandle;
    1003                 : 
    1004              24 :     nCRC = crc32(0L, Z_NULL, 0);
    1005              24 :     sStream.zalloc = (alloc_func)0;
    1006              24 :     sStream.zfree = (free_func)0;
    1007              24 :     sStream.opaque = (voidpf)0;
    1008              24 :     sStream.next_in = Z_NULL;
    1009              24 :     sStream.next_out = Z_NULL;
    1010              24 :     sStream.avail_in = sStream.avail_out = 0;
    1011                 : 
    1012              24 :     pabyInBuf = (Byte *) CPLMalloc( Z_BUFSIZE );
    1013              24 :     sStream.next_in  = pabyInBuf;
    1014                 : 
    1015              24 :     pabyOutBuf = (Byte *) CPLMalloc( Z_BUFSIZE );
    1016                 : 
    1017              24 :     if( deflateInit2( &sStream, Z_DEFAULT_COMPRESSION,
    1018                 :                       Z_DEFLATED, -MAX_WBITS, 8,
    1019                 :                       Z_DEFAULT_STRATEGY ) != Z_OK )
    1020               0 :         bCompressActive = false;
    1021                 :     else
    1022                 :     {
    1023                 :         char header[11];
    1024                 : 
    1025                 :         /* Write a very simple .gz header:
    1026                 :          */
    1027              24 :         sprintf( header, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
    1028                 :                  Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, 
    1029              24 :                  0x03 );
    1030              24 :         poBaseHandle->Write( header, 1, 10 );
    1031                 : 
    1032              24 :         bCompressActive = true;
    1033                 :     }
    1034              24 : }
    1035                 : 
    1036                 : /************************************************************************/
    1037                 : /*                        ~VSIGZipWriteHandle()                         */
    1038                 : /************************************************************************/
    1039                 : 
    1040              24 : VSIGZipWriteHandle::~VSIGZipWriteHandle()
    1041                 : 
    1042                 : {
    1043              24 :     if( bCompressActive )
    1044               0 :         Close();
    1045                 : 
    1046              24 :     CPLFree( pabyInBuf );
    1047              24 :     CPLFree( pabyOutBuf );
    1048              24 : }
    1049                 : 
    1050                 : /************************************************************************/
    1051                 : /*                               Close()                                */
    1052                 : /************************************************************************/
    1053                 : 
    1054              24 : int VSIGZipWriteHandle::Close()
    1055                 : 
    1056                 : {
    1057              24 :     if( bCompressActive )
    1058                 :     {
    1059              24 :         sStream.next_out = pabyOutBuf;
    1060              24 :         sStream.avail_out = Z_BUFSIZE;
    1061                 : 
    1062              24 :         deflate( &sStream, Z_FINISH );
    1063                 : 
    1064              24 :         size_t nOutBytes = Z_BUFSIZE - sStream.avail_out;
    1065                 : 
    1066              24 :         if( poBaseHandle->Write( pabyOutBuf, 1, nOutBytes ) < nOutBytes )
    1067               0 :             return EOF;
    1068                 : 
    1069              24 :         deflateEnd( &sStream );
    1070                 : 
    1071                 :         GUInt32 anTrailer[2];
    1072                 : 
    1073              24 :         anTrailer[0] = CPL_LSBWORD32( nCRC );
    1074              24 :         anTrailer[1] = CPL_LSBWORD32( (GUInt32) nCurOffset );
    1075                 : 
    1076              24 :         poBaseHandle->Write( anTrailer, 1, 8 );
    1077              24 :         poBaseHandle->Close();
    1078                 : 
    1079              24 :         delete poBaseHandle;
    1080                 : 
    1081              24 :         bCompressActive = false;
    1082                 :     }
    1083                 : 
    1084              24 :     return 0;
    1085                 : }
    1086                 : 
    1087                 : /************************************************************************/
    1088                 : /*                                Read()                                */
    1089                 : /************************************************************************/
    1090                 : 
    1091               0 : size_t VSIGZipWriteHandle::Read( void *pBuffer, size_t nSize, size_t nMemb )
    1092                 : 
    1093                 : {
    1094               0 :     CPLError(CE_Failure, CPLE_NotSupported, "VSIFReadL is not supported on GZip write streams\n");
    1095               0 :     return 0;
    1096                 : }
    1097                 : 
    1098                 : /************************************************************************/
    1099                 : /*                               Write()                                */
    1100                 : /************************************************************************/
    1101                 : 
    1102            1167 : size_t VSIGZipWriteHandle::Write( const void *pBuffer, 
    1103                 :                                   size_t nSize, size_t nMemb )
    1104                 : 
    1105                 : {
    1106                 :     int  nBytesToWrite, nNextByte;
    1107                 : 
    1108            1167 :     nBytesToWrite = (int) (nSize * nMemb);
    1109            1167 :     nNextByte = 0;
    1110                 : 
    1111            1167 :     nCRC = crc32(nCRC, (const Bytef *)pBuffer, nBytesToWrite);
    1112                 : 
    1113            1167 :     if( !bCompressActive )
    1114               0 :         return 0;
    1115                 : 
    1116            3501 :     while( nNextByte < nBytesToWrite )
    1117                 :     {
    1118            1167 :         sStream.next_out = pabyOutBuf;
    1119            1167 :         sStream.avail_out = Z_BUFSIZE;
    1120                 : 
    1121            1167 :         if( sStream.avail_in > 0 )
    1122               0 :             memmove( pabyInBuf, sStream.next_in, sStream.avail_in );
    1123                 : 
    1124            1167 :         int nNewBytesToWrite = MIN((int) (Z_BUFSIZE-sStream.avail_in),
    1125                 :                                    nBytesToWrite - nNextByte);
    1126                 :         memcpy( pabyInBuf + sStream.avail_in, 
    1127                 :                 ((Byte *) pBuffer) + nNextByte, 
    1128            1167 :                 nNewBytesToWrite );
    1129                 :         
    1130            1167 :         sStream.next_in = pabyInBuf;
    1131            1167 :         sStream.avail_in += nNewBytesToWrite;
    1132                 : 
    1133            1167 :         deflate( &sStream, Z_NO_FLUSH );
    1134                 : 
    1135            1167 :         size_t nOutBytes = Z_BUFSIZE - sStream.avail_out;
    1136                 : 
    1137            1167 :         if( nOutBytes > 0 )
    1138                 :         {
    1139               0 :             if( poBaseHandle->Write( pabyOutBuf, 1, nOutBytes ) < nOutBytes )
    1140               0 :                 return 0;
    1141                 :         }
    1142                 : 
    1143            1167 :         nNextByte += nNewBytesToWrite;
    1144            1167 :         nCurOffset += nNewBytesToWrite;
    1145                 :     }
    1146                 : 
    1147            1167 :     return nMemb;
    1148                 : }
    1149                 : 
    1150                 : /************************************************************************/
    1151                 : /*                               Flush()                                */
    1152                 : /************************************************************************/
    1153                 : 
    1154               0 : int VSIGZipWriteHandle::Flush()
    1155                 : 
    1156                 : {
    1157                 :     // we *could* do something for this but for now we choose not to.
    1158                 : 
    1159               0 :     return 0;
    1160                 : }
    1161                 : 
    1162                 : /************************************************************************/
    1163                 : /*                                Eof()                                 */
    1164                 : /************************************************************************/
    1165                 : 
    1166               0 : int VSIGZipWriteHandle::Eof()
    1167                 : 
    1168                 : {
    1169               0 :     return 1;
    1170                 : }
    1171                 : 
    1172                 : /************************************************************************/
    1173                 : /*                                Seek()                                */
    1174                 : /************************************************************************/
    1175                 : 
    1176               0 : int VSIGZipWriteHandle::Seek( vsi_l_offset nOffset, int nWhence )
    1177                 : 
    1178                 : {
    1179               0 :     if( nOffset == 0 && (nWhence == SEEK_END || nWhence == SEEK_CUR) )
    1180               0 :         return 0;
    1181               0 :     else if( nWhence == SEEK_SET && nOffset == nCurOffset )
    1182               0 :         return 0;
    1183                 :     else
    1184                 :     {
    1185                 :         CPLError(CE_Failure, CPLE_NotSupported,
    1186               0 :                  "Seeking on writable compressed data streams not supported." );
    1187                 :                
    1188               0 :         return -1;
    1189                 :     }
    1190                 : }
    1191                 : 
    1192                 : /************************************************************************/
    1193                 : /*                                Tell()                                */
    1194                 : /************************************************************************/
    1195                 : 
    1196               0 : vsi_l_offset VSIGZipWriteHandle::Tell()
    1197                 : 
    1198                 : {
    1199               0 :     return nCurOffset;
    1200                 : }
    1201                 : 
    1202                 : 
    1203                 : /************************************************************************/
    1204                 : /* ==================================================================== */
    1205                 : /*                       VSIGZipFilesystemHandler                       */
    1206                 : /* ==================================================================== */
    1207                 : /************************************************************************/
    1208                 : 
    1209                 : 
    1210                 : /************************************************************************/
    1211                 : /*                   VSIGZipFilesystemHandler()                         */
    1212                 : /************************************************************************/
    1213                 : 
    1214             647 : VSIGZipFilesystemHandler::VSIGZipFilesystemHandler()
    1215                 : {
    1216             647 :     hMutex = NULL;
    1217                 : 
    1218             647 :     poHandleLastGZipFile = NULL;
    1219             647 :     bInSaveInfo = FALSE;
    1220             647 : }
    1221                 : 
    1222                 : /************************************************************************/
    1223                 : /*                  ~VSIGZipFilesystemHandler()                         */
    1224                 : /************************************************************************/
    1225                 : 
    1226             628 : VSIGZipFilesystemHandler::~VSIGZipFilesystemHandler()
    1227                 : {
    1228             628 :     if (poHandleLastGZipFile)
    1229               1 :         delete poHandleLastGZipFile;
    1230                 : 
    1231             628 :     if( hMutex != NULL )
    1232               1 :         CPLDestroyMutex( hMutex );
    1233             628 :     hMutex = NULL;
    1234             628 : }
    1235                 : 
    1236                 : /************************************************************************/
    1237                 : /*                            SaveInfo()                                */
    1238                 : /************************************************************************/
    1239                 : 
    1240              58 : void VSIGZipFilesystemHandler::SaveInfo(  VSIGZipHandle* poHandle )
    1241                 : {
    1242              58 :     CPLMutexHolder oHolder(&hMutex);
    1243                 : 
    1244              58 :     if (bInSaveInfo)
    1245                 :         return;
    1246              58 :     bInSaveInfo = TRUE;
    1247                 :     
    1248              58 :     CPLAssert(poHandle->GetBaseFileName() != NULL);
    1249                 : 
    1250              58 :     if (poHandleLastGZipFile &&
    1251                 :         strcmp(poHandleLastGZipFile->GetBaseFileName(), poHandle->GetBaseFileName()) == 0)
    1252                 :     {
    1253              47 :         if (poHandle->GetLastReadOffset() > poHandleLastGZipFile->GetLastReadOffset())
    1254                 :         {
    1255               0 :             VSIGZipHandle* poTmp = poHandleLastGZipFile;
    1256               0 :             poHandleLastGZipFile = NULL;
    1257               0 :             delete poTmp;
    1258               0 :             poHandleLastGZipFile = poHandle->Duplicate();
    1259               0 :             poHandleLastGZipFile->CloseBaseHandle();
    1260                 :         }
    1261                 :     }
    1262                 :     else
    1263                 :     {
    1264              11 :         VSIGZipHandle* poTmp = poHandleLastGZipFile;
    1265              11 :         poHandleLastGZipFile = NULL;
    1266              11 :         delete poTmp;
    1267              11 :         poHandleLastGZipFile = poHandle->Duplicate();
    1268              11 :         poHandleLastGZipFile->CloseBaseHandle();
    1269                 :     }
    1270                 : 
    1271              58 :     bInSaveInfo = FALSE;
    1272                 : }
    1273                 : 
    1274                 : /************************************************************************/
    1275                 : /*                                Open()                                */
    1276                 : /************************************************************************/
    1277                 : 
    1278             121 : VSIVirtualHandle* VSIGZipFilesystemHandler::Open( const char *pszFilename, 
    1279                 :                                                   const char *pszAccess)
    1280                 : {
    1281                 :     VSIFilesystemHandler *poFSHandler = 
    1282             121 :         VSIFileManager::GetHandler( pszFilename + strlen("/vsigzip/"));
    1283                 : 
    1284                 : /* -------------------------------------------------------------------- */
    1285                 : /*      Is this an attempt to write a new file without update (w+)      */
    1286                 : /*      access?  If so, create a writable handle for the underlying     */
    1287                 : /*      filename.                                                       */
    1288                 : /* -------------------------------------------------------------------- */
    1289             121 :     if (strchr(pszAccess, 'w') != NULL )
    1290                 :     {
    1291              26 :         if( strchr(pszAccess, '+') != NULL )
    1292                 :         {
    1293                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1294               0 :                      "Write+update (w+) not supported for /vsigzip, only read-only or write-only.");
    1295               0 :             return NULL;
    1296                 :         }
    1297                 : 
    1298                 :         VSIVirtualHandle* poVirtualHandle =
    1299              26 :             poFSHandler->Open( pszFilename + strlen("/vsigzip/"), "wb" );
    1300                 : 
    1301              26 :         if (poVirtualHandle == NULL)
    1302               2 :             return NULL;
    1303                 : 
    1304                 :         else
    1305              24 :             return new VSIGZipWriteHandle( poVirtualHandle );
    1306                 :     }
    1307                 : 
    1308                 : /* -------------------------------------------------------------------- */
    1309                 : /*      Otherwise we are in the read access case.                       */
    1310                 : /* -------------------------------------------------------------------- */
    1311                 : 
    1312              95 :     VSIGZipHandle* poGZIPHandle = OpenGZipReadOnly(pszFilename, pszAccess);
    1313              95 :     if (poGZIPHandle)
    1314                 :         /* Wrap the VSIGZipHandle inside a buffered reader that will */
    1315                 :         /* improve dramatically performance when doing small backward */
    1316                 :         /* seeks */
    1317              47 :         return VSICreateBufferedReaderHandle(poGZIPHandle);
    1318                 :     else
    1319              48 :         return NULL;
    1320                 : }
    1321                 : 
    1322                 : /************************************************************************/
    1323                 : /*                          OpenGZipReadOnly()                          */
    1324                 : /************************************************************************/
    1325                 : 
    1326              95 : VSIGZipHandle* VSIGZipFilesystemHandler::OpenGZipReadOnly( const char *pszFilename, 
    1327                 :                                                       const char *pszAccess)
    1328                 : {
    1329                 :     VSIFilesystemHandler *poFSHandler = 
    1330              95 :         VSIFileManager::GetHandler( pszFilename + strlen("/vsigzip/"));
    1331                 : 
    1332              95 :     CPLMutexHolder oHolder(&hMutex);
    1333                 : 
    1334              95 :     if (poHandleLastGZipFile != NULL &&
    1335                 :         strcmp(pszFilename + strlen("/vsigzip/"), poHandleLastGZipFile->GetBaseFileName()) == 0 &&
    1336                 :         EQUAL(pszAccess, "rb"))
    1337                 :     {
    1338              36 :         VSIGZipHandle* poHandle = poHandleLastGZipFile->Duplicate();
    1339              36 :         if (poHandle)
    1340              36 :             return poHandle;
    1341                 :     }
    1342                 : 
    1343                 :     unsigned char signature[2];
    1344                 : 
    1345                 :     VSIVirtualHandle* poVirtualHandle =
    1346              59 :         poFSHandler->Open( pszFilename + strlen("/vsigzip/"), "rb" );
    1347                 : 
    1348              59 :     if (poVirtualHandle == NULL)
    1349              48 :         return NULL;
    1350                 : 
    1351              11 :     if (VSIFReadL(signature, 1, 2, (VSILFILE*)poVirtualHandle) != 2)
    1352               0 :         return NULL;
    1353                 : 
    1354              11 :     if (signature[0] != gz_magic[0] || signature[1] != gz_magic[1])
    1355               0 :         return NULL;
    1356                 : 
    1357              11 :     if (poHandleLastGZipFile)
    1358              10 :         delete poHandleLastGZipFile;
    1359              11 :     poHandleLastGZipFile = NULL;
    1360                 : 
    1361              11 :     return new VSIGZipHandle(poVirtualHandle, pszFilename + strlen("/vsigzip/"));
    1362                 : }
    1363                 : 
    1364                 : /************************************************************************/
    1365                 : /*                                Stat()                                */
    1366                 : /************************************************************************/
    1367                 : 
    1368              44 : int VSIGZipFilesystemHandler::Stat( const char *pszFilename,
    1369                 :                                     VSIStatBufL *pStatBuf,
    1370                 :                                     int nFlags )
    1371                 : {
    1372              44 :     CPLMutexHolder oHolder(&hMutex);
    1373                 : 
    1374              44 :     memset(pStatBuf, 0, sizeof(VSIStatBufL));
    1375                 : 
    1376              44 :     if (poHandleLastGZipFile != NULL &&
    1377                 :         strcmp(pszFilename+strlen("/vsigzip/"), poHandleLastGZipFile->GetBaseFileName()) == 0)
    1378                 :     {
    1379               5 :         if (poHandleLastGZipFile->GetUncompressedSize() != 0)
    1380                 :         {
    1381               0 :             pStatBuf->st_mode = S_IFREG;
    1382               0 :             pStatBuf->st_size = poHandleLastGZipFile->GetUncompressedSize();
    1383               0 :             return 0;
    1384                 :         }
    1385                 :     }
    1386                 : 
    1387                 :     /* Begin by doing a stat on the real file */
    1388              44 :     int ret = VSIStatExL(pszFilename+strlen("/vsigzip/"), pStatBuf, nFlags);
    1389                 : 
    1390              44 :     if (ret == 0 && (nFlags & VSI_STAT_SIZE_FLAG))
    1391                 :     {
    1392               0 :         CPLString osCacheFilename(pszFilename+strlen("/vsigzip/"));
    1393               0 :         osCacheFilename += ".properties";
    1394                 : 
    1395                 :         /* Can we save a bit of seeking by using a .properties file ? */
    1396               0 :         VSILFILE* fpCacheLength = VSIFOpenL(osCacheFilename.c_str(), "rb");
    1397               0 :         if (fpCacheLength)
    1398                 :         {
    1399                 :             const char* pszLine;
    1400               0 :             GUIntBig nCompressedSize = 0;
    1401               0 :             GUIntBig nUncompressedSize = 0;
    1402               0 :             while ((pszLine = CPLReadLineL(fpCacheLength)) != NULL)
    1403                 :             {
    1404               0 :                 if (EQUALN(pszLine, "compressed_size=", strlen("compressed_size=")))
    1405                 :                 {
    1406               0 :                     const char* pszBuffer = pszLine + strlen("compressed_size=");
    1407                 :                     nCompressedSize = 
    1408               0 :                             CPLScanUIntBig(pszBuffer, strlen(pszBuffer));
    1409                 :                 }
    1410               0 :                 else if (EQUALN(pszLine, "uncompressed_size=", strlen("uncompressed_size=")))
    1411                 :                 {
    1412               0 :                     const char* pszBuffer = pszLine + strlen("uncompressed_size=");
    1413                 :                     nUncompressedSize =
    1414               0 :                              CPLScanUIntBig(pszBuffer, strlen(pszBuffer));
    1415                 :                 }
    1416                 :             }
    1417                 : 
    1418               0 :             VSIFCloseL(fpCacheLength);
    1419                 : 
    1420               0 :             if (nCompressedSize == (GUIntBig) pStatBuf->st_size)
    1421                 :             {
    1422                 :                 /* Patch with the uncompressed size */
    1423               0 :                 pStatBuf->st_size = (long)nUncompressedSize;
    1424                 : 
    1425                 :                 VSIGZipHandle* poHandle =
    1426               0 :                     VSIGZipFilesystemHandler::OpenGZipReadOnly(pszFilename, "rb");
    1427               0 :                 if (poHandle)
    1428                 :                 {
    1429               0 :                     poHandle->SetUncompressedSize(nUncompressedSize);
    1430               0 :                     SaveInfo(poHandle);
    1431               0 :                     delete poHandle;
    1432                 :                 }
    1433                 : 
    1434               0 :                 return ret;
    1435                 :             }
    1436                 :         }
    1437                 : 
    1438                 :         /* No, then seek at the end of the data (slow) */
    1439                 :         VSIGZipHandle* poHandle =
    1440               0 :                 VSIGZipFilesystemHandler::OpenGZipReadOnly(pszFilename, "rb");
    1441               0 :         if (poHandle)
    1442                 :         {
    1443                 :             GUIntBig uncompressed_size;
    1444               0 :             poHandle->Seek(0, SEEK_END);
    1445               0 :             uncompressed_size = (GUIntBig) poHandle->Tell();
    1446               0 :             poHandle->Seek(0, SEEK_SET);
    1447                 : 
    1448                 :             /* Patch with the uncompressed size */
    1449               0 :             pStatBuf->st_size = (long)uncompressed_size;
    1450                 : 
    1451               0 :             delete poHandle;
    1452                 :         }
    1453                 :         else
    1454                 :         {
    1455               0 :             ret = -1;
    1456               0 :         }
    1457                 :     }
    1458                 : 
    1459              44 :     return ret;
    1460                 : }
    1461                 : 
    1462                 : /************************************************************************/
    1463                 : /*                               Unlink()                               */
    1464                 : /************************************************************************/
    1465                 : 
    1466               0 : int VSIGZipFilesystemHandler::Unlink( const char *pszFilename )
    1467                 : {
    1468               0 :     return -1;
    1469                 : }
    1470                 : 
    1471                 : /************************************************************************/
    1472                 : /*                               Rename()                               */
    1473                 : /************************************************************************/
    1474                 : 
    1475               0 : int VSIGZipFilesystemHandler::Rename( const char *oldpath, const char *newpath )
    1476                 : {
    1477               0 :     return -1;
    1478                 : }
    1479                 : 
    1480                 : /************************************************************************/
    1481                 : /*                               Mkdir()                                */
    1482                 : /************************************************************************/
    1483                 : 
    1484               0 : int VSIGZipFilesystemHandler::Mkdir( const char *pszDirname, long nMode )
    1485                 : {
    1486               0 :     return -1;
    1487                 : }
    1488                 : /************************************************************************/
    1489                 : /*                               Rmdir()                                */
    1490                 : /************************************************************************/
    1491                 : 
    1492               0 : int VSIGZipFilesystemHandler::Rmdir( const char *pszDirname )
    1493                 : {
    1494               0 :     return -1;
    1495                 : }
    1496                 : 
    1497                 : /************************************************************************/
    1498                 : /*                             ReadDir()                                */
    1499                 : /************************************************************************/
    1500                 : 
    1501               5 : char** VSIGZipFilesystemHandler::ReadDir( const char *pszDirname )
    1502                 : {
    1503               5 :     return NULL;
    1504                 : }
    1505                 : 
    1506                 : /************************************************************************/
    1507                 : /*                   VSIInstallGZipFileHandler()                        */
    1508                 : /************************************************************************/
    1509                 : 
    1510                 : 
    1511                 : /**
    1512                 :  * \brief Install GZip file system handler. 
    1513                 :  *
    1514                 :  * A special file handler is installed that allows reading on-the-fly and 
    1515                 :  * writing in GZip (.gz) files.
    1516                 :  *
    1517                 :  * All portions of the file system underneath the base
    1518                 :  * path "/vsigzip/" will be handled by this driver.
    1519                 :  *
    1520                 :  * Additional documentation is to be found at http://trac.osgeo.org/gdal/wiki/UserDocs/ReadInZip
    1521                 :  *
    1522                 :  * @since GDAL 1.6.0
    1523                 :  */
    1524                 : 
    1525             647 : void VSIInstallGZipFileHandler(void)
    1526                 : {
    1527             647 :     VSIFileManager::InstallHandler( "/vsigzip/", new VSIGZipFilesystemHandler );
    1528             647 : }
    1529                 : 
    1530                 : 
    1531                 : /************************************************************************/
    1532                 : /* ==================================================================== */
    1533                 : /*                         VSIZipEntryFileOffset                        */
    1534                 : /* ==================================================================== */
    1535                 : /************************************************************************/
    1536                 : 
    1537                 : class VSIZipEntryFileOffset : public VSIArchiveEntryFileOffset
    1538             188 : {
    1539                 : public:
    1540                 :         unz_file_pos file_pos;
    1541                 : 
    1542             188 :         VSIZipEntryFileOffset(unz_file_pos file_pos)
    1543             188 :         {
    1544             188 :             this->file_pos.pos_in_zip_directory = file_pos.pos_in_zip_directory;
    1545             188 :             this->file_pos.num_of_file = file_pos.num_of_file;
    1546             188 :         }
    1547                 : };
    1548                 : 
    1549                 : /************************************************************************/
    1550                 : /* ==================================================================== */
    1551                 : /*                             VSIZipReader                             */
    1552                 : /* ==================================================================== */
    1553                 : /************************************************************************/
    1554                 : 
    1555                 : class VSIZipReader : public VSIArchiveReader
    1556                 : {
    1557                 :     private:
    1558                 :         unzFile unzF;
    1559                 :         unz_file_pos file_pos;
    1560                 :         GUIntBig nNextFileSize;
    1561                 :         CPLString osNextFileName;
    1562                 :         GIntBig nModifiedTime;
    1563                 : 
    1564                 :         void SetInfo();
    1565                 : 
    1566                 :     public:
    1567                 :         VSIZipReader(const char* pszZipFileName);
    1568                 :         virtual ~VSIZipReader();
    1569                 : 
    1570              97 :         int IsValid() { return unzF != NULL; }
    1571                 : 
    1572              50 :         unzFile GetUnzFileHandle() { return unzF; }
    1573                 : 
    1574                 :         virtual int GotoFirstFile();
    1575                 :         virtual int GotoNextFile();
    1576             188 :         virtual VSIArchiveEntryFileOffset* GetFileOffset() { return new VSIZipEntryFileOffset(file_pos); }
    1577             191 :         virtual GUIntBig GetFileSize() { return nNextFileSize; }
    1578             202 :         virtual CPLString GetFileName() { return osNextFileName; }
    1579             195 :         virtual GIntBig GetModifiedTime() { return nModifiedTime; }
    1580                 :         virtual int GotoFileOffset(VSIArchiveEntryFileOffset* pOffset);
    1581                 : };
    1582                 : 
    1583                 : 
    1584                 : /************************************************************************/
    1585                 : /*                           VSIZipReader()                             */
    1586                 : /************************************************************************/
    1587                 : 
    1588              97 : VSIZipReader::VSIZipReader(const char* pszZipFileName)
    1589                 : {
    1590              97 :     unzF = cpl_unzOpen(pszZipFileName);
    1591              97 :     nNextFileSize = 0;
    1592              97 :     nModifiedTime = 0;
    1593              97 : }
    1594                 : 
    1595                 : /************************************************************************/
    1596                 : /*                          ~VSIZipReader()                             */
    1597                 : /************************************************************************/
    1598                 : 
    1599              97 : VSIZipReader::~VSIZipReader()
    1600                 : {
    1601              97 :     if (unzF)
    1602              97 :         cpl_unzClose(unzF);
    1603              97 : }
    1604                 : 
    1605                 : /************************************************************************/
    1606                 : /*                              SetInfo()                               */
    1607                 : /************************************************************************/
    1608                 : 
    1609             351 : void VSIZipReader::SetInfo()
    1610                 : {
    1611                 :     char fileName[512];
    1612                 :     unz_file_info file_info;
    1613             351 :     cpl_unzGetCurrentFileInfo (unzF, &file_info, fileName, 512, NULL, 0, NULL, 0);
    1614             351 :     osNextFileName = fileName;
    1615             351 :     nNextFileSize = file_info.uncompressed_size;
    1616                 :     struct tm brokendowntime;
    1617             351 :     brokendowntime.tm_sec = file_info.tmu_date.tm_sec;
    1618             351 :     brokendowntime.tm_min = file_info.tmu_date.tm_min;
    1619             351 :     brokendowntime.tm_hour = file_info.tmu_date.tm_hour;
    1620             351 :     brokendowntime.tm_mday = file_info.tmu_date.tm_mday;
    1621             351 :     brokendowntime.tm_mon = file_info.tmu_date.tm_mon;
    1622             351 :     brokendowntime.tm_year = file_info.tmu_date.tm_year - 1900; /* the minizip conventions differs from the Unix one */
    1623             351 :     nModifiedTime = CPLYMDHMSToUnixTime(&brokendowntime);
    1624                 : 
    1625             351 :     cpl_unzGetFilePos(unzF, &this->file_pos);
    1626             351 : }
    1627                 : 
    1628                 : /************************************************************************/
    1629                 : /*                           GotoNextFile()                             */
    1630                 : /************************************************************************/
    1631                 : 
    1632             205 : int VSIZipReader::GotoNextFile()
    1633                 : {
    1634             205 :     if (cpl_unzGoToNextFile(unzF) != UNZ_OK)
    1635              28 :         return FALSE;
    1636                 : 
    1637             177 :     SetInfo();
    1638                 : 
    1639             177 :     return TRUE;
    1640                 : }
    1641                 : 
    1642                 : /************************************************************************/
    1643                 : /*                          GotoFirstFile()                             */
    1644                 : /************************************************************************/
    1645                 : 
    1646             130 : int VSIZipReader::GotoFirstFile()
    1647                 : {
    1648             130 :     if (cpl_unzGoToFirstFile(unzF) != UNZ_OK)
    1649               0 :         return FALSE;
    1650                 : 
    1651             130 :     SetInfo();
    1652                 : 
    1653             130 :     return TRUE;
    1654                 : }
    1655                 : 
    1656                 : /************************************************************************/
    1657                 : /*                         GotoFileOffset()                             */
    1658                 : /************************************************************************/
    1659                 : 
    1660              44 : int VSIZipReader::GotoFileOffset(VSIArchiveEntryFileOffset* pOffset)
    1661                 : {
    1662              44 :     VSIZipEntryFileOffset* pZipEntryOffset = (VSIZipEntryFileOffset*)pOffset;
    1663              44 :     cpl_unzGoToFilePos(unzF, &(pZipEntryOffset->file_pos));
    1664                 : 
    1665              44 :     SetInfo();
    1666                 : 
    1667              44 :     return TRUE;
    1668                 : }
    1669                 : 
    1670                 : /************************************************************************/
    1671                 : /* ==================================================================== */
    1672                 : /*                       VSIZipFilesystemHandler                  */
    1673                 : /* ==================================================================== */
    1674                 : /************************************************************************/
    1675                 : 
    1676                 : class VSIZipWriteHandle;
    1677                 : 
    1678                 : class VSIZipFilesystemHandler : public VSIArchiveFilesystemHandler 
    1679             647 : {
    1680                 :     std::map<CPLString, VSIZipWriteHandle*> oMapZipWriteHandles;
    1681                 : 
    1682                 : public:
    1683                 :     virtual ~VSIZipFilesystemHandler();
    1684                 :     
    1685             807 :     virtual const char* GetPrefix() { return "/vsizip"; }
    1686                 :     virtual std::vector<CPLString> GetExtensions();
    1687                 :     virtual VSIArchiveReader* CreateReader(const char* pszZipFileName);
    1688                 : 
    1689                 :     virtual VSIVirtualHandle *Open( const char *pszFilename, 
    1690                 :                                     const char *pszAccess);
    1691                 : 
    1692                 :     virtual VSIVirtualHandle *OpenForWrite( const char *pszFilename,
    1693                 :                                             const char *pszAccess );
    1694                 : 
    1695                 :     virtual int      Mkdir( const char *pszDirname, long nMode );
    1696                 :     virtual char   **ReadDir( const char *pszDirname );
    1697                 :     virtual int      Stat( const char *pszFilename, VSIStatBufL *pStatBuf, int nFlags );
    1698                 : 
    1699                 :     void RemoveFromMap(VSIZipWriteHandle* poHandle);
    1700                 : };
    1701                 : 
    1702                 : /************************************************************************/
    1703                 : /* ==================================================================== */
    1704                 : /*                       VSIZipWriteHandle                              */
    1705                 : /* ==================================================================== */
    1706                 : /************************************************************************/
    1707                 : 
    1708                 : class VSIZipWriteHandle : public VSIVirtualHandle
    1709                 : {
    1710                 :    VSIZipFilesystemHandler *poFS;
    1711                 :    void                    *hZIP;
    1712                 :    VSIZipWriteHandle       *poChildInWriting;
    1713                 :    VSIZipWriteHandle       *poParent;
    1714                 :    int                      bAutoDeleteParent;
    1715                 : 
    1716                 :   public:
    1717                 : 
    1718                 :     VSIZipWriteHandle(VSIZipFilesystemHandler* poFS,
    1719                 :                       void *hZIP,
    1720                 :                       VSIZipWriteHandle* poParent);
    1721                 : 
    1722                 :     ~VSIZipWriteHandle();
    1723                 : 
    1724                 :     virtual int       Seek( vsi_l_offset nOffset, int nWhence );
    1725                 :     virtual vsi_l_offset Tell();
    1726                 :     virtual size_t    Read( void *pBuffer, size_t nSize, size_t nMemb );
    1727                 :     virtual size_t    Write( const void *pBuffer, size_t nSize, size_t nMemb );
    1728                 :     virtual int       Eof();
    1729                 :     virtual int       Flush();
    1730                 :     virtual int       Close();
    1731                 : 
    1732                 :     void  StartNewFile(VSIZipWriteHandle* poSubFile);
    1733                 :     void  StopCurrentFile();
    1734               9 :     void* GetHandle() { return hZIP; }
    1735              10 :     VSIZipWriteHandle* GetChildInWriting() { return poChildInWriting; };
    1736               3 :     void SetAutoDeleteParent() { bAutoDeleteParent = TRUE; }
    1737                 : };
    1738                 : 
    1739                 : /************************************************************************/
    1740                 : /*                      ~VSIZipFilesystemHandler()                      */
    1741                 : /************************************************************************/
    1742                 : 
    1743             628 : VSIZipFilesystemHandler::~VSIZipFilesystemHandler()
    1744                 : {
    1745             628 :     std::map<CPLString,VSIZipWriteHandle*>::const_iterator iter;
    1746                 : 
    1747             628 :     for( iter = oMapZipWriteHandles.begin(); iter != oMapZipWriteHandles.end(); ++iter )
    1748                 :     {
    1749                 :         CPLError(CE_Failure, CPLE_AppDefined, "%s has not been closed",
    1750               0 :                  iter->first.c_str());
    1751                 :     }
    1752             628 : }
    1753                 : 
    1754                 : /************************************************************************/
    1755                 : /*                          GetExtensions()                             */
    1756                 : /************************************************************************/
    1757                 : 
    1758            8034 : std::vector<CPLString> VSIZipFilesystemHandler::GetExtensions()
    1759                 : {
    1760            8034 :     std::vector<CPLString> oList;
    1761            8034 :     oList.push_back(".zip");
    1762            8034 :     oList.push_back(".kmz");
    1763               0 :     return oList;
    1764                 : }
    1765                 : 
    1766                 : /************************************************************************/
    1767                 : /*                           CreateReader()                             */
    1768                 : /************************************************************************/
    1769                 : 
    1770              97 : VSIArchiveReader* VSIZipFilesystemHandler::CreateReader(const char* pszZipFileName)
    1771                 : {
    1772              97 :     VSIZipReader* poReader = new VSIZipReader(pszZipFileName);
    1773                 : 
    1774              97 :     if (!poReader->IsValid())
    1775                 :     {
    1776               0 :         delete poReader;
    1777               0 :         return NULL;
    1778                 :     }
    1779                 : 
    1780              97 :     if (!poReader->GotoFirstFile())
    1781                 :     {
    1782               0 :         delete poReader;
    1783               0 :         return NULL;
    1784                 :     }
    1785                 : 
    1786              97 :     return poReader;
    1787                 : }
    1788                 : 
    1789                 : /************************************************************************/
    1790                 : /*                                 Open()                               */
    1791                 : /************************************************************************/
    1792                 : 
    1793              98 : VSIVirtualHandle* VSIZipFilesystemHandler::Open( const char *pszFilename, 
    1794                 :                                                  const char *pszAccess)
    1795                 : {
    1796                 :     char* zipFilename;
    1797              98 :     CPLString osZipInFileName;
    1798                 : 
    1799              98 :     if (strchr(pszAccess, 'w') != NULL)
    1800                 :     {
    1801              11 :         return OpenForWrite(pszFilename, pszAccess);
    1802                 :     }
    1803                 : 
    1804              87 :     if (strchr(pszAccess, '+') != NULL)
    1805                 :     {
    1806                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1807               0 :                  "Random access not supported for /vsizip");
    1808               0 :         return NULL;
    1809                 :     }
    1810                 : 
    1811              87 :     zipFilename = SplitFilename(pszFilename, osZipInFileName, TRUE);
    1812              87 :     if (zipFilename == NULL)
    1813              16 :         return NULL;
    1814                 : 
    1815                 :     {
    1816              71 :         CPLMutexHolder oHolder(&hMutex);
    1817              71 :         if (oMapZipWriteHandles.find(zipFilename) != oMapZipWriteHandles.end() )
    1818                 :         {
    1819                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1820               1 :                     "Cannot read a zip file being written");
    1821               1 :             CPLFree(zipFilename);
    1822               1 :             return NULL;
    1823               0 :         }
    1824                 :     }
    1825                 : 
    1826              70 :     VSIArchiveReader* poReader = OpenArchiveFile(zipFilename, osZipInFileName);
    1827              70 :     if (poReader == NULL)
    1828                 :     {
    1829              20 :         CPLFree(zipFilename);
    1830              20 :         return NULL;
    1831                 :     }
    1832                 : 
    1833                 :     VSIFilesystemHandler *poFSHandler = 
    1834              50 :         VSIFileManager::GetHandler( zipFilename);
    1835                 : 
    1836                 :     VSIVirtualHandle* poVirtualHandle =
    1837              50 :         poFSHandler->Open( zipFilename, "rb" );
    1838                 : 
    1839              50 :     CPLFree(zipFilename);
    1840              50 :     zipFilename = NULL;
    1841                 : 
    1842              50 :     if (poVirtualHandle == NULL)
    1843                 :     {
    1844               0 :         delete poReader;
    1845               0 :         return NULL;
    1846                 :     }
    1847                 : 
    1848              50 :     unzFile unzF = ((VSIZipReader*)poReader)->GetUnzFileHandle();
    1849                 : 
    1850              50 :     cpl_unzOpenCurrentFile(unzF);
    1851                 : 
    1852              50 :     uLong64 pos = cpl_unzGetCurrentFileZStreamPos(unzF);
    1853                 : 
    1854                 :     unz_file_info file_info;
    1855              50 :     cpl_unzGetCurrentFileInfo (unzF, &file_info, NULL, 0, NULL, 0, NULL, 0);
    1856                 : 
    1857              50 :     cpl_unzCloseCurrentFile(unzF);
    1858                 : 
    1859              50 :     delete poReader;
    1860                 : 
    1861                 :     VSIGZipHandle* poGZIPHandle = new VSIGZipHandle(poVirtualHandle,
    1862                 :                              NULL,
    1863                 :                              pos,
    1864                 :                              file_info.compressed_size,
    1865                 :                              file_info.uncompressed_size,
    1866                 :                              file_info.crc,
    1867              50 :                              file_info.compression_method == 0);
    1868                 :     /* Wrap the VSIGZipHandle inside a buffered reader that will */
    1869                 :     /* improve dramatically performance when doing small backward */
    1870                 :     /* seeks */
    1871             100 :     return VSICreateBufferedReaderHandle(poGZIPHandle);
    1872                 : }
    1873                 : 
    1874                 : /************************************************************************/
    1875                 : /*                                Mkdir()                               */
    1876                 : /************************************************************************/
    1877                 : 
    1878               1 : int VSIZipFilesystemHandler::Mkdir( const char *pszDirname, long nMode )
    1879                 : {
    1880               1 :     CPLString osDirname = pszDirname;
    1881               1 :     if (osDirname.size() != 0 && osDirname[osDirname.size() - 1] != '/')
    1882               1 :         osDirname += "/";
    1883               1 :     VSIVirtualHandle* poZIPHandle = OpenForWrite(osDirname, "wb");
    1884               1 :     if (poZIPHandle == NULL)
    1885               0 :         return -1;
    1886               1 :     delete poZIPHandle;
    1887               1 :     return 0;
    1888                 : }
    1889                 : 
    1890                 : /************************************************************************/
    1891                 : /*                                ReadDir()                             */
    1892                 : /************************************************************************/
    1893                 : 
    1894              31 : char **VSIZipFilesystemHandler::ReadDir( const char *pszDirname )
    1895                 : {
    1896              31 :     CPLString osInArchiveSubDir;
    1897              31 :     char* zipFilename = SplitFilename(pszDirname, osInArchiveSubDir, TRUE);
    1898              31 :     if (zipFilename == NULL)
    1899               3 :         return NULL;
    1900                 : 
    1901                 :     {
    1902              28 :         CPLMutexHolder oHolder(&hMutex);
    1903                 : 
    1904              28 :         if (oMapZipWriteHandles.find(zipFilename) != oMapZipWriteHandles.end() )
    1905                 :         {
    1906                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1907               1 :                     "Cannot read a zip file being written");
    1908               1 :             CPLFree(zipFilename);
    1909               1 :             return NULL;
    1910               0 :         }
    1911                 :     }
    1912              27 :     CPLFree(zipFilename);
    1913                 : 
    1914              27 :     return VSIArchiveFilesystemHandler::ReadDir(pszDirname);
    1915                 : }
    1916                 : 
    1917                 : 
    1918                 : /************************************************************************/
    1919                 : /*                                 Stat()                               */
    1920                 : /************************************************************************/
    1921                 : 
    1922              58 : int VSIZipFilesystemHandler::Stat( const char *pszFilename,
    1923                 :                                    VSIStatBufL *pStatBuf, int nFlags )
    1924                 : {
    1925              58 :     CPLString osInArchiveSubDir;
    1926                 : 
    1927              58 :     memset(pStatBuf, 0, sizeof(VSIStatBufL));
    1928                 : 
    1929              58 :     char* zipFilename = SplitFilename(pszFilename, osInArchiveSubDir, TRUE);
    1930              58 :     if (zipFilename == NULL)
    1931               7 :         return -1;
    1932                 : 
    1933                 :     {
    1934              51 :         CPLMutexHolder oHolder(&hMutex);
    1935                 : 
    1936              51 :         if (oMapZipWriteHandles.find(zipFilename) != oMapZipWriteHandles.end() )
    1937                 :         {
    1938                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1939               0 :                     "Cannot read a zip file being written");
    1940               0 :             CPLFree(zipFilename);
    1941               0 :             return -1;
    1942               0 :         }
    1943                 :     }
    1944              51 :     CPLFree(zipFilename);
    1945                 : 
    1946              51 :     return VSIArchiveFilesystemHandler::Stat(pszFilename, pStatBuf, nFlags);
    1947                 : }
    1948                 : 
    1949                 : /************************************************************************/
    1950                 : /*                             RemoveFromMap()                           */
    1951                 : /************************************************************************/
    1952                 : 
    1953               5 : void VSIZipFilesystemHandler::RemoveFromMap(VSIZipWriteHandle* poHandle)
    1954                 : {
    1955               5 :     CPLMutexHolder oHolder( &hMutex );
    1956               5 :     std::map<CPLString,VSIZipWriteHandle*>::iterator iter;
    1957                 : 
    1958               5 :     for( iter = oMapZipWriteHandles.begin();
    1959                 :          iter != oMapZipWriteHandles.end(); ++iter )
    1960                 :     {
    1961               5 :         if (iter->second == poHandle)
    1962                 :         {
    1963               5 :             oMapZipWriteHandles.erase(iter);
    1964               5 :             break;
    1965                 :         }
    1966               5 :     }
    1967               5 : }
    1968                 : 
    1969                 : /************************************************************************/
    1970                 : /*                             OpenForWrite()                           */
    1971                 : /************************************************************************/
    1972                 : 
    1973              15 : VSIVirtualHandle* VSIZipFilesystemHandler::OpenForWrite( const char *pszFilename,
    1974                 :                                                          const char *pszAccess)
    1975                 : {
    1976                 :     char* zipFilename;
    1977              15 :     CPLString osZipInFileName;
    1978                 : 
    1979              15 :     CPLMutexHolder oHolder( &hMutex );
    1980                 : 
    1981              15 :     zipFilename = SplitFilename(pszFilename, osZipInFileName, FALSE);
    1982              15 :     if (zipFilename == NULL)
    1983               0 :         return NULL;
    1984              15 :     CPLString osZipFilename = zipFilename;
    1985              15 :     CPLFree(zipFilename);
    1986              15 :     zipFilename = NULL;
    1987                 : 
    1988                 :     /* Invalidate cached file list */
    1989              15 :     std::map<CPLString,VSIArchiveContent*>::iterator iter = oFileList.find(osZipFilename);
    1990              15 :     if (iter != oFileList.end())
    1991                 :     {
    1992               2 :         VSIArchiveContent* content = iter->second;
    1993                 :         int i;
    1994               5 :         for(i=0;i<content->nEntries;i++)
    1995                 :         {
    1996               3 :             delete content->entries[i].file_pos;
    1997               3 :             CPLFree(content->entries[i].fileName);
    1998                 :         }
    1999               2 :         CPLFree(content->entries);
    2000               2 :         delete content;
    2001                 : 
    2002               2 :         oFileList.erase(iter);
    2003                 :     }
    2004                 : 
    2005                 :     VSIZipWriteHandle* poZIPHandle;
    2006                 : 
    2007              15 :     if (oMapZipWriteHandles.find(osZipFilename) != oMapZipWriteHandles.end() )
    2008                 :     {
    2009              10 :         if (strchr(pszAccess, '+') != NULL)
    2010                 :         {
    2011                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2012               0 :                     "Random access not supported for writable file in /vsizip");
    2013               0 :             return NULL;
    2014                 :         }
    2015                 : 
    2016              10 :         poZIPHandle = oMapZipWriteHandles[osZipFilename];
    2017                 : 
    2018              10 :         if (poZIPHandle->GetChildInWriting() != NULL)
    2019                 :         {
    2020                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2021                 :                      "Cannot create %s while another file is being written in the .zip",
    2022               1 :                      osZipInFileName.c_str());
    2023               1 :             return NULL;
    2024                 :         }
    2025                 : 
    2026               9 :         poZIPHandle->StopCurrentFile();
    2027                 : 
    2028               9 :         if (CPLCreateFileInZip(poZIPHandle->GetHandle(),
    2029                 :                                osZipInFileName, NULL) != CE_None)
    2030               0 :             return NULL;
    2031                 : 
    2032                 :         VSIZipWriteHandle* poChildHandle =
    2033               9 :             new VSIZipWriteHandle(this, NULL, poZIPHandle);
    2034                 : 
    2035               9 :         poZIPHandle->StartNewFile(poChildHandle);
    2036                 : 
    2037               9 :         return poChildHandle;
    2038                 :     }
    2039                 :     else
    2040                 :     {
    2041               5 :         char** papszOptions = NULL;
    2042               5 :         if ((strchr(pszAccess, '+') && osZipInFileName.size() == 0) ||
    2043                 :              osZipInFileName.size() != 0)
    2044                 :         {
    2045                 :             VSIStatBufL sBuf;
    2046               3 :             if (VSIStatExL(osZipFilename, &sBuf, VSI_STAT_EXISTS_FLAG) == 0)
    2047               2 :                 papszOptions = CSLAddNameValue(papszOptions, "APPEND", "TRUE");
    2048                 :         }
    2049                 : 
    2050               5 :         void* hZIP = CPLCreateZip(osZipFilename, papszOptions);
    2051               5 :         CSLDestroy(papszOptions);
    2052                 : 
    2053               5 :         if (hZIP == NULL)
    2054               0 :             return NULL;
    2055                 : 
    2056                 :         oMapZipWriteHandles[osZipFilename] =
    2057               5 :             new VSIZipWriteHandle(this, hZIP, NULL);
    2058                 : 
    2059               5 :         if (osZipInFileName.size() != 0)
    2060                 :         {
    2061                 :             VSIZipWriteHandle* poRes =
    2062               3 :                 (VSIZipWriteHandle*)OpenForWrite(pszFilename, pszAccess);
    2063               3 :             if (poRes == NULL)
    2064                 :             {
    2065               0 :                 delete oMapZipWriteHandles[osZipFilename];
    2066               0 :                 return NULL;
    2067                 :             }
    2068                 : 
    2069               3 :             poRes->SetAutoDeleteParent();
    2070                 : 
    2071               3 :             return poRes;
    2072                 :         }
    2073                 : 
    2074               2 :         return oMapZipWriteHandles[osZipFilename];
    2075               0 :     }
    2076                 : }
    2077                 : 
    2078                 : 
    2079                 : /************************************************************************/
    2080                 : /*                          VSIZipWriteHandle()                         */
    2081                 : /************************************************************************/
    2082                 : 
    2083              14 : VSIZipWriteHandle::VSIZipWriteHandle(VSIZipFilesystemHandler* poFS,
    2084                 :                                      void* hZIP,
    2085              14 :                                      VSIZipWriteHandle* poParent)
    2086                 : {
    2087              14 :     this->poFS = poFS;
    2088              14 :     this->hZIP = hZIP;
    2089              14 :     this->poParent = poParent;
    2090              14 :     poChildInWriting = NULL;
    2091              14 :     bAutoDeleteParent = FALSE;
    2092              14 : }
    2093                 : 
    2094                 : /************************************************************************/
    2095                 : /*                         ~VSIZipWriteHandle()                         */
    2096                 : /************************************************************************/
    2097                 : 
    2098              14 : VSIZipWriteHandle::~VSIZipWriteHandle()
    2099                 : {
    2100              14 :     Close();
    2101              14 : }
    2102                 : 
    2103                 : /************************************************************************/
    2104                 : /*                               Seek()                                 */
    2105                 : /************************************************************************/
    2106                 : 
    2107               0 : int VSIZipWriteHandle::Seek( vsi_l_offset nOffset, int nWhence )
    2108                 : {
    2109                 :     CPLError(CE_Failure, CPLE_NotSupported,
    2110               0 :              "VSIFSeekL() is not supported on writable Zip files");
    2111               0 :     return -1;
    2112                 : }
    2113                 : 
    2114                 : /************************************************************************/
    2115                 : /*                               Tell()                                 */
    2116                 : /************************************************************************/
    2117                 : 
    2118               0 : vsi_l_offset VSIZipWriteHandle::Tell()
    2119                 : {
    2120                 :     CPLError(CE_Failure, CPLE_NotSupported,
    2121               0 :              "VSIFTellL() is not supported on writable Zip files");
    2122               0 :     return 0;
    2123                 : }
    2124                 : 
    2125                 : /************************************************************************/
    2126                 : /*                               Read()                                 */
    2127                 : /************************************************************************/
    2128                 : 
    2129               0 : size_t    VSIZipWriteHandle::Read( void *pBuffer, size_t nSize, size_t nMemb )
    2130                 : {
    2131                 :     CPLError(CE_Failure, CPLE_NotSupported,
    2132               0 :              "VSIFReadL() is not supported on writable Zip files");
    2133               0 :     return 0;
    2134                 : }
    2135                 : 
    2136                 : /************************************************************************/
    2137                 : /*                               Write()                                 */
    2138                 : /************************************************************************/
    2139                 : 
    2140               7 : size_t    VSIZipWriteHandle::Write( const void *pBuffer, size_t nSize, size_t nMemb )
    2141                 : {
    2142               7 :     if (poParent == NULL)
    2143                 :     {
    2144                 :         CPLError(CE_Failure, CPLE_NotSupported,
    2145               0 :                  "VSIFWriteL() is not supported on main Zip file or closed subfiles");
    2146               0 :         return 0;
    2147                 :     }
    2148                 : 
    2149               7 :     if (CPLWriteFileInZip( poParent->hZIP, pBuffer, (int)(nSize * nMemb) ) != CE_None)
    2150               0 :         return 0;
    2151                 : 
    2152               7 :     return nMemb;
    2153                 : }
    2154                 : 
    2155                 : /************************************************************************/
    2156                 : /*                                Eof()                                 */
    2157                 : /************************************************************************/
    2158                 : 
    2159               0 : int VSIZipWriteHandle::Eof()
    2160                 : {
    2161                 :     CPLError(CE_Failure, CPLE_NotSupported,
    2162               0 :              "VSIFEofL() is not supported on writable Zip files");
    2163               0 :     return FALSE;
    2164                 : }
    2165                 : 
    2166                 : /************************************************************************/
    2167                 : /*                               Flush()                                */
    2168                 : /************************************************************************/
    2169                 : 
    2170               0 : int VSIZipWriteHandle::Flush()
    2171                 : {
    2172                 :     CPLError(CE_Failure, CPLE_NotSupported,
    2173               0 :              "VSIFFlushL() is not supported on writable Zip files");
    2174               0 :     return 0;
    2175                 : }
    2176                 : 
    2177                 : /************************************************************************/
    2178                 : /*                               Close()                                */
    2179                 : /************************************************************************/
    2180                 : 
    2181              24 : int VSIZipWriteHandle::Close()
    2182                 : {
    2183              24 :     if (poParent)
    2184                 :     {
    2185               9 :         CPLCloseFileInZip(poParent->hZIP);
    2186               9 :         poParent->poChildInWriting = NULL;
    2187               9 :         if (bAutoDeleteParent)
    2188               3 :             delete poParent;
    2189               9 :         poParent = NULL;
    2190                 :     }
    2191              24 :     if (poChildInWriting)
    2192                 :     {
    2193               0 :         poChildInWriting->Close();
    2194               0 :         poChildInWriting = NULL;
    2195                 :     }
    2196              24 :     if (hZIP)
    2197                 :     {
    2198               5 :         CPLCloseZip(hZIP);
    2199               5 :         hZIP = NULL;
    2200                 : 
    2201               5 :         poFS->RemoveFromMap(this);
    2202                 :     }
    2203                 : 
    2204              24 :     return 0;
    2205                 : }
    2206                 : 
    2207                 : /************************************************************************/
    2208                 : /*                           StopCurrentFile()                          */
    2209                 : /************************************************************************/
    2210                 : 
    2211               9 : void  VSIZipWriteHandle::StopCurrentFile()
    2212                 : {
    2213               9 :     if (poChildInWriting)
    2214               0 :         poChildInWriting->Close();
    2215               9 :     poChildInWriting = NULL;
    2216               9 : }
    2217                 : 
    2218                 : /************************************************************************/
    2219                 : /*                           StartNewFile()                             */
    2220                 : /************************************************************************/
    2221                 : 
    2222               9 : void  VSIZipWriteHandle::StartNewFile(VSIZipWriteHandle* poSubFile)
    2223                 : {
    2224               9 :     poChildInWriting = poSubFile;
    2225               9 : }
    2226                 : 
    2227                 : /************************************************************************/
    2228                 : /*                    VSIInstallZipFileHandler()                        */
    2229                 : /************************************************************************/
    2230                 : 
    2231                 : 
    2232                 : /**
    2233                 :  * \brief Install ZIP file system handler. 
    2234                 :  *
    2235                 :  * A special file handler is installed that allows reading on-the-fly in ZIP
    2236                 :  * (.zip) archives.
    2237                 :  *
    2238                 :  * All portions of the file system underneath the base path "/vsizip/" will be
    2239                 :  * handled by this driver.
    2240                 :  *
    2241                 :  * The syntax to open a file inside a zip file is /vsizip/path/to/the/file.zip/path/inside/the/zip/file
    2242                 :  * were path/to/the/file.zip is relative or absolute and path/inside/the/zip/file
    2243                 :  * is the relative path to the file inside the archive.
    2244                 :  * 
    2245                 :  * If the path is absolute, it should begin with a / on a Unix-like OS (or C:\ on Windows),
    2246                 :  * so the line looks like /vsizip//home/gdal/...
    2247                 :  * For example gdalinfo /vsizip/myarchive.zip/subdir1/file1.tif
    2248                 :  *
    2249                 :  * Syntaxic sugar : if the .zip file contains only one file located at its root,
    2250                 :  * just mentionning "/vsizip/path/to/the/file.zip" will work
    2251                 :  *
    2252                 :  * VSIStatL() will return the uncompressed size in st_size member and file
    2253                 :  * nature- file or directory - in st_mode member.
    2254                 :  *
    2255                 :  * Directory listing is available through VSIReadDir().
    2256                 :  *
    2257                 :  * Since GDAL 1.8.0, write capabilities are available. They allow creating
    2258                 :  * a new zip file and adding new files to an already existing (or just created)
    2259                 :  * zip file. Read and write operations cannot be interleaved : the new zip must
    2260                 :  * be closed before being re-opened for read.
    2261                 :  *
    2262                 :  * Additional documentation is to be found at http://trac.osgeo.org/gdal/wiki/UserDocs/ReadInZip
    2263                 :  *
    2264                 :  * @since GDAL 1.6.0
    2265                 :  */
    2266                 : 
    2267             647 : void VSIInstallZipFileHandler(void)
    2268                 : {
    2269             647 :     VSIFileManager::InstallHandler( "/vsizip/", new VSIZipFilesystemHandler() );
    2270             647 : }
    2271                 : 

Generated by: LCOV version 1.7