LCOV - code coverage report
Current view: directory - port - cpl_vsil_tar.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 104 96 92.3 %
Date: 2012-04-28 Functions: 25 20 80.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: cpl_vsil_tar.cpp 21781 2011-02-21 21:57:41Z rouault $
       3                 :  *
       4                 :  * Project:  CPL - Common Portability Library
       5                 :  * Purpose:  Implement VSI large file api for tar files (.tar).
       6                 :  * Author:   Even Rouault, even.rouault at mines-paris.org
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2010, 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                 : #include "cpl_vsi_virtual.h"
      31                 : 
      32                 : CPL_CVSID("$Id: cpl_vsil_tar.cpp 21781 2011-02-21 21:57:41Z rouault $");
      33                 : 
      34                 : 
      35                 : /************************************************************************/
      36                 : /* ==================================================================== */
      37                 : /*                       VSITarEntryFileOffset                          */
      38                 : /* ==================================================================== */
      39                 : /************************************************************************/
      40                 : 
      41                 : class VSITarEntryFileOffset : public VSIArchiveEntryFileOffset
      42              36 : {
      43                 : public:
      44                 :         GUIntBig nOffset;
      45                 : 
      46              36 :         VSITarEntryFileOffset(GUIntBig nOffset)
      47              36 :         {
      48              36 :             this->nOffset = nOffset;
      49              36 :         }
      50                 : };
      51                 : 
      52                 : /************************************************************************/
      53                 : /* ==================================================================== */
      54                 : /*                             VSITarReader                             */
      55                 : /* ==================================================================== */
      56                 : /************************************************************************/
      57                 : 
      58                 : class VSITarReader : public VSIArchiveReader
      59                 : {
      60                 :     private:
      61                 :         VSILFILE* fp;
      62                 :         GUIntBig nCurOffset;
      63                 :         GUIntBig nNextFileSize;
      64                 :         CPLString osNextFileName;
      65                 :         GIntBig nModifiedTime;
      66                 : 
      67                 :     public:
      68                 :         VSITarReader(const char* pszTarFileName);
      69                 :         virtual ~VSITarReader();
      70                 : 
      71              42 :         int IsValid() { return fp != NULL; }
      72                 : 
      73                 :         virtual int GotoFirstFile();
      74                 :         virtual int GotoNextFile();
      75              36 :         virtual VSIArchiveEntryFileOffset* GetFileOffset() { return new VSITarEntryFileOffset(nCurOffset); }
      76              40 :         virtual GUIntBig GetFileSize() { return nNextFileSize; }
      77              26 :         virtual CPLString GetFileName() { return osNextFileName; }
      78              16 :         virtual GIntBig GetModifiedTime() { return nModifiedTime; }
      79                 :         virtual int GotoFileOffset(VSIArchiveEntryFileOffset* pOffset);
      80                 : };
      81                 : 
      82                 : 
      83                 : /************************************************************************/
      84                 : /*                               VSIIsTGZ()                             */
      85                 : /************************************************************************/
      86                 : 
      87              66 : static int VSIIsTGZ(const char* pszFilename)
      88                 : {
      89                 :     return (!EQUALN(pszFilename, "/vsigzip/", 9) &&
      90                 :             ((strlen(pszFilename) > 4 &&
      91                 :             EQUALN(pszFilename + strlen(pszFilename) - 4, ".tgz", 4)) ||
      92                 :             (strlen(pszFilename) > 7 &&
      93              66 :             EQUALN(pszFilename + strlen(pszFilename) - 7, ".tar.gz", 7))));
      94                 : }
      95                 : 
      96                 : /************************************************************************/
      97                 : /*                           VSITarReader()                             */
      98                 : /************************************************************************/
      99                 : 
     100              42 : VSITarReader::VSITarReader(const char* pszTarFileName)
     101                 : {
     102              42 :     fp = VSIFOpenL(pszTarFileName, "rb");
     103              42 :     nNextFileSize = 0;
     104              42 :     nCurOffset = 0;
     105              42 :     nModifiedTime = 0;
     106              42 : }
     107                 : 
     108                 : /************************************************************************/
     109                 : /*                          ~VSITarReader()                             */
     110                 : /************************************************************************/
     111                 : 
     112              42 : VSITarReader::~VSITarReader()
     113                 : {
     114              42 :     if (fp)
     115              42 :         VSIFCloseL(fp);
     116              42 : }
     117                 : 
     118                 : /************************************************************************/
     119                 : /*                           GotoNextFile()                             */
     120                 : /************************************************************************/
     121                 : 
     122             104 : int VSITarReader::GotoNextFile()
     123                 : {
     124                 :     char abyHeader[512];
     125             104 :     if (VSIFReadL(abyHeader, 512, 1, fp) != 1)
     126               0 :         return FALSE;
     127                 : 
     128             832 :     if (abyHeader[99] != '\0' ||
     129             104 :         abyHeader[107] != '\0' ||
     130             104 :         abyHeader[115] != '\0' ||
     131             104 :         abyHeader[123] != '\0' ||
     132             104 :         (abyHeader[135] != '\0' && abyHeader[135] != ' ') ||
     133             104 :         (abyHeader[147] != '\0' && abyHeader[147] != ' ') ||
     134             104 :         abyHeader[154] != '\0' ||
     135             104 :         abyHeader[155] != ' ')
     136              18 :         return FALSE;
     137                 : 
     138              86 :     osNextFileName = abyHeader;
     139              86 :     nNextFileSize = 0;
     140                 :     int i;
     141            1032 :     for(i=0;i<11;i++)
     142             946 :         nNextFileSize = nNextFileSize * 8 + (abyHeader[124+i] - '0');
     143                 : 
     144              86 :     nModifiedTime = 0;
     145            1032 :     for(i=0;i<11;i++)
     146             946 :         nModifiedTime = nModifiedTime * 8 + (abyHeader[136+i] - '0');
     147                 : 
     148              86 :     nCurOffset = VSIFTellL(fp);
     149                 : 
     150              86 :     GUIntBig nBytesToSkip = ((nNextFileSize + 511) / 512) * 512;
     151              86 :     VSIFSeekL(fp, nBytesToSkip, SEEK_CUR);
     152                 : 
     153              86 :     return TRUE;
     154                 : }
     155                 : 
     156                 : /************************************************************************/
     157                 : /*                          GotoFirstFile()                             */
     158                 : /************************************************************************/
     159                 : 
     160              62 : int VSITarReader::GotoFirstFile()
     161                 : {
     162              62 :     VSIFSeekL(fp, 0, SEEK_SET);
     163              62 :     return GotoNextFile();
     164                 : }
     165                 : 
     166                 : /************************************************************************/
     167                 : /*                         GotoFileOffset()                             */
     168                 : /************************************************************************/
     169                 : 
     170              16 : int VSITarReader::GotoFileOffset(VSIArchiveEntryFileOffset* pOffset)
     171                 : {
     172              16 :     VSITarEntryFileOffset* pTarEntryOffset = (VSITarEntryFileOffset*)pOffset;
     173              16 :     VSIFSeekL(fp, pTarEntryOffset->nOffset - 512, SEEK_SET);
     174              16 :     return GotoNextFile();
     175                 : }
     176                 : 
     177                 : /************************************************************************/
     178                 : /* ==================================================================== */
     179                 : /*                        VSITarFilesystemHandler                      */
     180                 : /* ==================================================================== */
     181                 : /************************************************************************/
     182                 : 
     183                 : class VSITarFilesystemHandler : public VSIArchiveFilesystemHandler 
     184            2638 : {
     185                 : public:
     186             210 :     virtual const char* GetPrefix() { return "/vsitar"; }
     187                 :     virtual std::vector<CPLString> GetExtensions();
     188                 :     virtual VSIArchiveReader* CreateReader(const char* pszTarFileName);
     189                 : 
     190                 :     virtual VSIVirtualHandle *Open( const char *pszFilename, 
     191                 :                                     const char *pszAccess);
     192                 : };
     193                 : 
     194                 : 
     195                 : /************************************************************************/
     196                 : /*                          GetExtensions()                             */
     197                 : /************************************************************************/
     198                 : 
     199             904 : std::vector<CPLString> VSITarFilesystemHandler::GetExtensions()
     200                 : {
     201             904 :     std::vector<CPLString> oList;
     202             904 :     oList.push_back(".tar.gz");
     203             904 :     oList.push_back(".tar");
     204             904 :     oList.push_back(".tgz");
     205               0 :     return oList;
     206                 : }
     207                 : 
     208                 : /************************************************************************/
     209                 : /*                           CreateReader()                             */
     210                 : /************************************************************************/
     211                 : 
     212              42 : VSIArchiveReader* VSITarFilesystemHandler::CreateReader(const char* pszTarFileName)
     213                 : {
     214              42 :     CPLString osTarInFileName;
     215                 : 
     216              42 :     if (VSIIsTGZ(pszTarFileName))
     217                 :     {
     218              30 :         osTarInFileName = "/vsigzip/";
     219              30 :         osTarInFileName += pszTarFileName;
     220                 :     }
     221                 :     else
     222              12 :         osTarInFileName = pszTarFileName;
     223                 : 
     224              42 :     VSITarReader* poReader = new VSITarReader(osTarInFileName);
     225                 : 
     226              84 :     if (!poReader->IsValid())
     227                 :     {
     228               0 :         delete poReader;
     229               0 :         return NULL;
     230                 :     }
     231                 : 
     232              42 :     if (!poReader->GotoFirstFile())
     233                 :     {
     234               0 :         delete poReader;
     235               0 :         return NULL;
     236                 :     }
     237                 : 
     238              42 :     return poReader;
     239                 : }
     240                 : 
     241                 : /************************************************************************/
     242                 : /*                                 Open()                               */
     243                 : /************************************************************************/
     244                 : 
     245              46 : VSIVirtualHandle* VSITarFilesystemHandler::Open( const char *pszFilename, 
     246                 :                                                  const char *pszAccess)
     247                 : {
     248                 :     char* tarFilename;
     249              46 :     CPLString osTarInFileName;
     250                 : 
     251              46 :     if (strchr(pszAccess, 'w') != NULL ||
     252                 :         strchr(pszAccess, '+') != NULL)
     253                 :     {
     254                 :         CPLError(CE_Failure, CPLE_AppDefined,
     255               0 :                  "Only read-only mode is supported for /vsitar");
     256               0 :         return NULL;
     257                 :     }
     258                 : 
     259              46 :     tarFilename = SplitFilename(pszFilename, osTarInFileName, TRUE);
     260              46 :     if (tarFilename == NULL)
     261              16 :         return NULL;
     262                 : 
     263              30 :     VSIArchiveReader* poReader = OpenArchiveFile(tarFilename, osTarInFileName);
     264              30 :     if (poReader == NULL)
     265                 :     {
     266               6 :         CPLFree(tarFilename);
     267               6 :         return NULL;
     268                 :     }
     269                 : 
     270              24 :     CPLString osSubFileName("/vsisubfile/");
     271              24 :     VSITarEntryFileOffset* pOffset = (VSITarEntryFileOffset*) poReader->GetFileOffset();
     272              24 :     osSubFileName += CPLString().Printf(CPL_FRMT_GUIB, pOffset->nOffset);
     273              24 :     osSubFileName += "_";
     274              24 :     osSubFileName += CPLString().Printf(CPL_FRMT_GUIB, poReader->GetFileSize());
     275              24 :     osSubFileName += ",";
     276              24 :     delete pOffset;
     277                 :     
     278              24 :     if (VSIIsTGZ(tarFilename))
     279                 :     {
     280              16 :         osSubFileName += "/vsigzip/";
     281              16 :         osSubFileName += tarFilename;
     282                 :     }
     283                 :     else
     284               8 :         osSubFileName += tarFilename;
     285                 : 
     286              24 :     delete(poReader);
     287                 : 
     288              24 :     CPLFree(tarFilename);
     289              24 :     tarFilename = NULL;
     290                 : 
     291              24 :     return (VSIVirtualHandle* )VSIFOpenL(osSubFileName, "rb");
     292                 : }
     293                 : 
     294                 : /************************************************************************/
     295                 : /*                    VSIInstallTarFileHandler()                        */
     296                 : /************************************************************************/
     297                 : 
     298                 : /**
     299                 :  * \brief Install /vsitar/ file system handler.
     300                 :  *
     301                 :  * A special file handler is installed that allows reading on-the-fly in TAR
     302                 :  * (regular .tar, or compressed .tar.gz/.tgz) archives.
     303                 :  *
     304                 :  * All portions of the file system underneath the base path "/vsitar/" will be
     305                 :  * handled by this driver.
     306                 :  *
     307                 :  * The syntax to open a file inside a zip file is /vsitar/path/to/the/file.tar/path/inside/the/tar/file
     308                 :  * were path/to/the/file.tar is relative or absolute and path/inside/the/tar/file
     309                 :  * is the relative path to the file inside the archive.
     310                 :  *
     311                 :  * If the path is absolute, it should begin with a / on a Unix-like OS (or C:\ on Windows),
     312                 :  * so the line looks like /vsitar//home/gdal/...
     313                 :  * For example gdalinfo /vsitar/myarchive.tar/subdir1/file1.tif
     314                 :  *
     315                 :  * Syntaxic sugar : if the tar archive contains only one file located at its root,
     316                 :  * just mentionning "/vsitar/path/to/the/file.tar" will work
     317                 :  *
     318                 :  * VSIStatL() will return the uncompressed size in st_size member and file
     319                 :  * nature- file or directory - in st_mode member.
     320                 :  *
     321                 :  * Directory listing is available through VSIReadDir().
     322                 :  *
     323                 :  * @since GDAL 1.8.0
     324                 :  */
     325                 : 
     326            1341 : void VSIInstallTarFileHandler(void)
     327                 : {
     328            1341 :     VSIFileManager::InstallHandler( "/vsitar/", new VSITarFilesystemHandler() );
     329            1341 : }

Generated by: LCOV version 1.7