LCOV - code coverage report
Current view: directory - port - cpl_vsil_abstract_archive.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 255 205 80.4 %
Date: 2011-12-18 Functions: 21 10 47.6 %

       1                 : /******************************************************************************
       2                 :  * $Id: cpl_vsil_abstract_archive.cpp 22980 2011-08-25 22:29:12Z rouault $
       3                 :  *
       4                 :  * Project:  CPL - Common Portability Library
       5                 :  * Purpose:  Implement VSI large file api for archive files.
       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                 : #include "cpl_string.h"
      32                 : #include "cpl_multiproc.h"
      33                 : #include <map>
      34                 : #include <set>
      35                 : 
      36                 : #define ENABLE_DEBUG 0
      37                 : 
      38                 : CPL_CVSID("$Id: cpl_vsil_abstract_archive.cpp 22980 2011-08-25 22:29:12Z rouault $");
      39                 : 
      40                 : /************************************************************************/
      41                 : /*                    ~VSIArchiveEntryFileOffset()                      */
      42                 : /************************************************************************/
      43                 : 
      44             206 : VSIArchiveEntryFileOffset::~VSIArchiveEntryFileOffset()
      45                 : {
      46             206 : }
      47                 : 
      48                 : /************************************************************************/
      49                 : /*                        ~VSIArchiveReader()                           */
      50                 : /************************************************************************/
      51                 : 
      52             118 : VSIArchiveReader::~VSIArchiveReader()
      53                 : {
      54             118 : }
      55                 : 
      56                 : /************************************************************************/
      57                 : /*                   VSIArchiveFilesystemHandler()                      */
      58                 : /************************************************************************/
      59                 : 
      60            1294 : VSIArchiveFilesystemHandler::VSIArchiveFilesystemHandler()
      61                 : {
      62            1294 :     hMutex = NULL;
      63            1294 : }
      64                 : 
      65                 : /************************************************************************/
      66                 : /*                   ~VSIArchiveFilesystemHandler()                     */
      67                 : /************************************************************************/
      68                 : 
      69            1256 : VSIArchiveFilesystemHandler::~VSIArchiveFilesystemHandler()
      70                 : 
      71                 : {
      72            1256 :     std::map<CPLString,VSIArchiveContent*>::const_iterator iter;
      73                 : 
      74            1276 :     for( iter = oFileList.begin(); iter != oFileList.end(); ++iter )
      75                 :     {
      76              20 :         VSIArchiveContent* content = iter->second;
      77                 :         int i;
      78             215 :         for(i=0;i<content->nEntries;i++)
      79                 :         {
      80             195 :             delete content->entries[i].file_pos;
      81             195 :             CPLFree(content->entries[i].fileName);
      82                 :         }
      83              20 :         CPLFree(content->entries);
      84              20 :         delete content;
      85                 :     }
      86                 : 
      87            1256 :     if( hMutex != NULL )
      88               2 :         CPLDestroyMutex( hMutex );
      89            1256 :     hMutex = NULL;
      90            1256 : }
      91                 : 
      92                 : /************************************************************************/
      93                 : /*                       GetContentOfArchive()                          */
      94                 : /************************************************************************/
      95                 : 
      96             150 : const VSIArchiveContent* VSIArchiveFilesystemHandler::GetContentOfArchive
      97                 :         (const char* archiveFilename, VSIArchiveReader* poReader)
      98                 : {
      99             150 :     CPLMutexHolder oHolder( &hMutex );
     100                 : 
     101             150 :     if (oFileList.find(archiveFilename) != oFileList.end() )
     102                 :     {
     103             128 :         return oFileList[archiveFilename];
     104                 :     }
     105                 : 
     106              22 :     int bMustClose = (poReader == NULL);
     107              22 :     if (poReader == NULL)
     108                 :     {
     109              22 :         poReader = CreateReader(archiveFilename);
     110              22 :         if (!poReader)
     111               0 :             return NULL;
     112                 :     }
     113                 : 
     114              22 :     if (poReader->GotoFirstFile() == FALSE)
     115                 :     {
     116               0 :         if (bMustClose)
     117               0 :             delete(poReader);
     118               0 :         return NULL;
     119                 :     }
     120                 : 
     121              22 :     VSIArchiveContent* content = new VSIArchiveContent;
     122              22 :     content->nEntries = 0;
     123              22 :     content->entries = NULL;
     124              22 :     oFileList[archiveFilename] = content;
     125                 : 
     126              22 :     std::set<CPLString> oSet;
     127                 : 
     128             194 :     do
     129                 :     {
     130             194 :         CPLString osFileName = poReader->GetFileName();
     131             194 :         const char* fileName = osFileName.c_str();
     132                 : 
     133                 :         /* Remove ./ pattern at the beginning of a filename */
     134             194 :         if (fileName[0] == '.' && fileName[1] == '/')
     135                 :         {
     136               0 :             fileName += 2;
     137               0 :             if (fileName[0] == '\0')
     138               0 :                 continue;
     139                 :         }
     140                 : 
     141             194 :         char* pszStrippedFileName = CPLStrdup(fileName);
     142                 :         int bIsDir = strlen(fileName) > 0 &&
     143             194 :                       (fileName[strlen(fileName)-1] == '/' || fileName[strlen(fileName)-1] == '\\');
     144             194 :         if (bIsDir)
     145                 :         {
     146                 :             /* Remove trailing slash */
     147               5 :             pszStrippedFileName[strlen(fileName)-1] = 0;
     148                 :         }
     149                 : 
     150             194 :         if (oSet.find(pszStrippedFileName) == oSet.end())
     151                 :         {
     152             194 :             oSet.insert(pszStrippedFileName);
     153                 : 
     154                 :             /* Add intermediate directory structure */
     155                 :             char* pszIter;
     156            2418 :             for(pszIter = pszStrippedFileName;*pszIter;pszIter++)
     157                 :             {
     158            2224 :                 if (*pszIter == '/' || *pszIter == '\\')
     159                 :                 {
     160              41 :                     char* pszStrippedFileName2 = CPLStrdup(pszStrippedFileName);
     161              41 :                     pszStrippedFileName2[pszIter - pszStrippedFileName] = 0;
     162              41 :                     if (oSet.find(pszStrippedFileName2) == oSet.end())
     163                 :                     {
     164               4 :                         oSet.insert(pszStrippedFileName2);
     165                 : 
     166                 :                         content->entries = (VSIArchiveEntry*)CPLRealloc(content->entries,
     167               4 :                                 sizeof(VSIArchiveEntry) * (content->nEntries + 1));
     168               4 :                         content->entries[content->nEntries].fileName = pszStrippedFileName2;
     169               4 :                         content->entries[content->nEntries].nModifiedTime = poReader->GetModifiedTime();
     170               4 :                         content->entries[content->nEntries].uncompressed_size = 0;
     171               4 :                         content->entries[content->nEntries].bIsDir = TRUE;
     172               4 :                         content->entries[content->nEntries].file_pos = NULL;
     173                 :                         if (ENABLE_DEBUG)
     174                 :                             CPLDebug("VSIArchive", "[%d] %s : " CPL_FRMT_GUIB " bytes", content->nEntries+1,
     175                 :                                 content->entries[content->nEntries].fileName,
     176                 :                                 content->entries[content->nEntries].uncompressed_size);
     177               4 :                         content->nEntries++;
     178                 :                     }
     179                 :                     else
     180                 :                     {
     181              37 :                         CPLFree(pszStrippedFileName2);
     182                 :                     }
     183                 :                 }
     184                 :             }
     185                 : 
     186                 :             content->entries = (VSIArchiveEntry*)CPLRealloc(content->entries,
     187             194 :                                 sizeof(VSIArchiveEntry) * (content->nEntries + 1));
     188             194 :             content->entries[content->nEntries].fileName = pszStrippedFileName;
     189             194 :             content->entries[content->nEntries].nModifiedTime = poReader->GetModifiedTime();
     190             194 :             content->entries[content->nEntries].uncompressed_size = poReader->GetFileSize();
     191             194 :             content->entries[content->nEntries].bIsDir = bIsDir;
     192             194 :             content->entries[content->nEntries].file_pos = poReader->GetFileOffset();
     193                 :             if (ENABLE_DEBUG)
     194                 :                 CPLDebug("VSIArchive", "[%d] %s : " CPL_FRMT_GUIB " bytes", content->nEntries+1,
     195                 :                     content->entries[content->nEntries].fileName,
     196                 :                     content->entries[content->nEntries].uncompressed_size);
     197             194 :             content->nEntries++;
     198                 :         }
     199                 :         else
     200                 :         {
     201               0 :             CPLFree(pszStrippedFileName);
     202               0 :         }
     203             194 :     } while(poReader->GotoNextFile());
     204                 : 
     205              22 :     if (bMustClose)
     206              22 :         delete(poReader);
     207                 : 
     208              22 :     return content;
     209                 : }
     210                 : 
     211                 : /************************************************************************/
     212                 : /*                        FindFileInArchive()                           */
     213                 : /************************************************************************/
     214                 : 
     215             120 : int VSIArchiveFilesystemHandler::FindFileInArchive(const char* archiveFilename,
     216                 :                                            const char* fileInArchiveName,
     217                 :                                            const VSIArchiveEntry** archiveEntry)
     218                 : {
     219             120 :     if (fileInArchiveName == NULL)
     220               0 :         return FALSE;
     221                 : 
     222             120 :     const VSIArchiveContent* content = GetContentOfArchive(archiveFilename);
     223             120 :     if (content)
     224                 :     {
     225                 :         int i;
     226            1180 :         for(i=0;i<content->nEntries;i++)
     227                 :         {
     228            1145 :             if (strcmp(fileInArchiveName, content->entries[i].fileName) == 0)
     229                 :             {
     230              85 :                 if (archiveEntry)
     231              85 :                     *archiveEntry = &content->entries[i];
     232              85 :                 return TRUE;
     233                 :             }
     234                 :         }
     235                 :     }
     236              35 :     return FALSE;
     237                 : }
     238                 : 
     239                 : /************************************************************************/
     240                 : /*                           SplitFilename()                            */
     241                 : /************************************************************************/
     242                 : 
     243             304 : char* VSIArchiveFilesystemHandler::SplitFilename(const char *pszFilename,
     244                 :                                                  CPLString &osFileInArchive,
     245                 :                                                  int bCheckMainFileExists)
     246                 : {
     247             304 :     int i = 0;
     248                 : 
     249             304 :     if (strcmp(pszFilename, GetPrefix()) == 0)
     250               0 :         return NULL;
     251                 : 
     252                 :     /* Allow natural chaining of VSI drivers without requiring double slash */
     253                 :     
     254             304 :     CPLString osDoubleVsi(GetPrefix());
     255             304 :     osDoubleVsi += "/vsi";
     256                 :     
     257             304 :     if (strncmp(pszFilename, osDoubleVsi.c_str(), osDoubleVsi.size()) == 0)
     258              53 :         pszFilename += strlen(GetPrefix());
     259                 :     else
     260             251 :         pszFilename += strlen(GetPrefix()) + 1;
     261                 : 
     262             304 :     while(pszFilename[i])
     263                 :     {
     264            8486 :         std::vector<CPLString> oExtensions = GetExtensions();
     265            8486 :         std::vector<CPLString>::const_iterator iter;
     266            8486 :         int nToSkip = 0;
     267                 : 
     268           25343 :         for( iter = oExtensions.begin(); iter != oExtensions.end(); ++iter )
     269                 :         {
     270           17144 :             const CPLString& osExtension = *iter;
     271           17144 :             if (EQUALN(pszFilename + i, osExtension.c_str(), strlen(osExtension.c_str())))
     272                 :             {
     273             287 :                 nToSkip = strlen(osExtension.c_str());
     274             287 :                 break;
     275                 :             }
     276                 :         }
     277                 : 
     278            8486 :         if (nToSkip != 0)
     279                 :         {
     280                 :             VSIStatBufL statBuf;
     281             287 :             char* archiveFilename = CPLStrdup(pszFilename);
     282             287 :             int bArchiveFileExists = FALSE;
     283                 : 
     284             375 :             if (archiveFilename[i + nToSkip] == '/' ||
     285              88 :                 archiveFilename[i + nToSkip] == '\\')
     286                 :             {
     287             199 :                 archiveFilename[i + nToSkip] = 0;
     288                 :             }
     289                 : 
     290             287 :             if (!bCheckMainFileExists)
     291                 :             {
     292              15 :                 bArchiveFileExists = TRUE;
     293                 :             }
     294                 :             else
     295                 :             {
     296             272 :                 CPLMutexHolder oHolder( &hMutex );
     297                 : 
     298             272 :                 if (oFileList.find(archiveFilename) != oFileList.end() )
     299                 :                 {
     300             196 :                     bArchiveFileExists = TRUE;
     301             272 :                 }
     302                 :             }
     303                 : 
     304             287 :             if (!bArchiveFileExists)
     305                 :             {
     306                 :                 VSIFilesystemHandler *poFSHandler = 
     307              76 :                     VSIFileManager::GetHandler( archiveFilename );
     308              76 :                 if (poFSHandler->Stat(archiveFilename, &statBuf,
     309              76 :                                       VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0 &&
     310                 :                     !VSI_ISDIR(statBuf.st_mode))
     311                 :                 {
     312              55 :                     bArchiveFileExists = TRUE;
     313                 :                 }
     314                 :             }
     315                 : 
     316             287 :             if (bArchiveFileExists)
     317                 :             {
     318             532 :                 if (pszFilename[i + nToSkip] == '/' ||
     319              67 :                     pszFilename[i + nToSkip] == '\\')
     320                 :                 {
     321             199 :                     char* pszArchiveInFileName = CPLStrdup(pszFilename + i + nToSkip + 1);
     322                 : 
     323                 :                     /* Replace a/../b by b and foo/a/../b by foo/b */
     324               0 :                     while(TRUE)
     325                 :                     {
     326             199 :                         char* pszPrevDir = strstr(pszArchiveInFileName, "/../");
     327             199 :                         if (pszPrevDir == NULL || pszPrevDir == pszArchiveInFileName)
     328                 :                             break;
     329                 : 
     330               0 :                         char* pszPrevSlash = pszPrevDir - 1;
     331               0 :                         while(pszPrevSlash != pszArchiveInFileName &&
     332                 :                                 *pszPrevSlash != '/')
     333               0 :                             pszPrevSlash --;
     334               0 :                         if (pszPrevSlash == pszArchiveInFileName)
     335               0 :                             memmove(pszArchiveInFileName, pszPrevDir + nToSkip, strlen(pszPrevDir + nToSkip) + 1);
     336                 :                         else
     337               0 :                             memmove(pszPrevSlash + 1, pszPrevDir + nToSkip, strlen(pszPrevDir + nToSkip) + 1);
     338                 :                     }
     339                 : 
     340             398 :                     osFileInArchive = pszArchiveInFileName;
     341             199 :                     CPLFree(pszArchiveInFileName);
     342                 :                 }
     343                 :                 else
     344              67 :                     osFileInArchive = "";
     345                 : 
     346                 :                 /* Remove trailing slash */
     347             266 :                 if (strlen(osFileInArchive))
     348                 :                 {
     349             199 :                     char lastC = osFileInArchive[strlen(osFileInArchive) - 1];
     350             199 :                     if (lastC == '\\' || lastC == '/')
     351               2 :                         osFileInArchive[strlen(osFileInArchive) - 1] = 0;
     352                 :                 }
     353                 : 
     354             266 :                 return archiveFilename;
     355                 :             }
     356              21 :             CPLFree(archiveFilename);
     357                 :         }
     358            8220 :         i++;
     359                 :     }
     360              38 :     return NULL;
     361                 : }
     362                 : 
     363                 : /************************************************************************/
     364                 : /*                           OpenArchiveFile()                          */
     365                 : /************************************************************************/
     366                 : 
     367              85 : VSIArchiveReader* VSIArchiveFilesystemHandler::OpenArchiveFile(const char* archiveFilename, 
     368                 :                                                                const char* fileInArchiveName)
     369                 : {
     370              85 :     VSIArchiveReader* poReader = CreateReader(archiveFilename);
     371                 : 
     372              85 :     if (poReader == NULL)
     373                 :     {
     374               0 :         return NULL;
     375                 :     }
     376                 : 
     377              95 :     if (fileInArchiveName == NULL || strlen(fileInArchiveName) == 0)
     378                 :     {
     379              10 :         if (poReader->GotoFirstFile() == FALSE)
     380                 :         {
     381               0 :             delete(poReader);
     382               0 :             return NULL;
     383                 :         }
     384                 : 
     385                 :         /* Skip optionnal leading subdir */
     386              10 :         CPLString osFileName = poReader->GetFileName();
     387              10 :         const char* fileName = osFileName.c_str();
     388              10 :         if (fileName[strlen(fileName)-1] == '/' || fileName[strlen(fileName)-1] == '\\')
     389                 :         {
     390               2 :             if (poReader->GotoNextFile() == FALSE)
     391                 :             {
     392               0 :                 delete(poReader);
     393               0 :                 return NULL;
     394                 :             }
     395                 :         }
     396                 : 
     397              10 :         if (poReader->GotoNextFile())
     398                 :         {
     399               0 :             CPLString msg;
     400                 :             msg.Printf("Support only 1 file in archive file %s when no explicit in-archive filename is specified",
     401               0 :                        archiveFilename);
     402               0 :             const VSIArchiveContent* content = GetContentOfArchive(archiveFilename, poReader);
     403               0 :             if (content)
     404                 :             {
     405                 :                 int i;
     406               0 :                 msg += "\nYou could try one of the following :\n";
     407               0 :                 for(i=0;i<content->nEntries;i++)
     408                 :                 {
     409               0 :                     msg += CPLString().Printf("  %s/%s/%s\n", GetPrefix(), archiveFilename, content->entries[i].fileName);
     410                 :                 }
     411                 :             }
     412                 : 
     413               0 :             CPLError(CE_Failure, CPLE_NotSupported, "%s", msg.c_str());
     414                 : 
     415               0 :             delete(poReader);
     416               0 :             return NULL;
     417               0 :         }
     418                 :     }
     419                 :     else
     420                 :     {
     421              75 :         const VSIArchiveEntry* archiveEntry = NULL;
     422              75 :         if (FindFileInArchive(archiveFilename, fileInArchiveName, &archiveEntry) == FALSE ||
     423                 :             archiveEntry->bIsDir)
     424                 :         {
     425              23 :             delete(poReader);
     426              23 :             return NULL;
     427                 :         }
     428              52 :         if (!poReader->GotoFileOffset(archiveEntry->file_pos))
     429                 :         {
     430               0 :             delete poReader;
     431               0 :             return NULL;
     432                 :         }
     433                 :     }
     434              62 :     return poReader;
     435                 : }
     436                 : 
     437                 : /************************************************************************/
     438                 : /*                                 Stat()                               */
     439                 : /************************************************************************/
     440                 : 
     441              58 : int VSIArchiveFilesystemHandler::Stat( const char *pszFilename, VSIStatBufL *pStatBuf, int nFlags )
     442                 : {
     443              58 :     int ret = -1;
     444              58 :     CPLString osFileInArchive;
     445                 : 
     446              58 :     memset(pStatBuf, 0, sizeof(VSIStatBufL));
     447                 : 
     448              58 :     char* archiveFilename = SplitFilename(pszFilename, osFileInArchive, TRUE);
     449              58 :     if (archiveFilename == NULL)
     450               2 :         return -1;
     451                 : 
     452              56 :     if (strlen(osFileInArchive) != 0)
     453                 :     {
     454                 :         if (ENABLE_DEBUG) CPLDebug("VSIArchive", "Looking for %s %s\n",
     455                 :                                     archiveFilename, osFileInArchive.c_str());
     456                 : 
     457              45 :         const VSIArchiveEntry* archiveEntry = NULL;
     458              45 :         if (FindFileInArchive(archiveFilename, osFileInArchive, &archiveEntry))
     459                 :         {
     460                 :             /* Patching st_size with uncompressed file size */
     461              33 :             pStatBuf->st_size = (long)archiveEntry->uncompressed_size;
     462              33 :             pStatBuf->st_mtime = (time_t)archiveEntry->nModifiedTime;
     463              33 :             if (archiveEntry->bIsDir)
     464               0 :                 pStatBuf->st_mode = S_IFDIR;
     465                 :             else
     466              33 :                 pStatBuf->st_mode = S_IFREG;
     467              33 :             ret = 0;
     468                 :         }
     469                 :     }
     470                 :     else
     471                 :     {
     472              11 :         VSIArchiveReader* poReader = CreateReader(archiveFilename);
     473              11 :         CPLFree(archiveFilename);
     474              11 :         archiveFilename = NULL;
     475                 : 
     476              11 :         if (poReader != NULL && poReader->GotoFirstFile())
     477                 :         {
     478                 :             /* Skip optionnal leading subdir */
     479              11 :             CPLString osFileName = poReader->GetFileName();
     480              11 :             const char* fileName = osFileName.c_str();
     481              11 :             if (fileName[strlen(fileName)-1] == '/' || fileName[strlen(fileName)-1] == '\\')
     482                 :             {
     483               1 :                 if (poReader->GotoNextFile() == FALSE)
     484                 :                 {
     485               0 :                     delete(poReader);
     486               0 :                     return -1;
     487                 :                 }
     488                 :             }
     489                 : 
     490              11 :             if (poReader->GotoNextFile())
     491                 :             {
     492                 :                 /* Several files in archive --> treat as dir */
     493               6 :                 pStatBuf->st_size = 0;
     494               6 :                 pStatBuf->st_mode = S_IFDIR;
     495                 :             }
     496                 :             else
     497                 :             {
     498                 :                 /* Patching st_size with uncompressed file size */
     499               5 :                 pStatBuf->st_size = (long)poReader->GetFileSize();
     500               5 :                 pStatBuf->st_mtime = (time_t)poReader->GetModifiedTime();
     501               5 :                 pStatBuf->st_mode = S_IFREG;
     502                 :             }
     503                 : 
     504              11 :             ret = 0;
     505                 :         }
     506                 : 
     507              11 :         delete(poReader);
     508                 :     }
     509                 : 
     510              56 :     CPLFree(archiveFilename);
     511              56 :     return ret;
     512                 : }
     513                 : 
     514                 : /************************************************************************/
     515                 : /*                              Unlink()                                */
     516                 : /************************************************************************/
     517                 : 
     518               0 : int VSIArchiveFilesystemHandler::Unlink( const char *pszFilename )
     519                 : {
     520               0 :     return -1;
     521                 : }
     522                 : 
     523                 : /************************************************************************/
     524                 : /*                             Rename()                                 */
     525                 : /************************************************************************/
     526                 : 
     527               0 : int VSIArchiveFilesystemHandler::Rename( const char *oldpath, const char *newpath )
     528                 : {
     529               0 :     return -1;
     530                 : }
     531                 : 
     532                 : /************************************************************************/
     533                 : /*                             Mkdir()                                  */
     534                 : /************************************************************************/
     535                 : 
     536               0 : int VSIArchiveFilesystemHandler::Mkdir( const char *pszDirname, long nMode )
     537                 : {
     538               0 :     return -1;
     539                 : }
     540                 : 
     541                 : /************************************************************************/
     542                 : /*                             Rmdir()                                  */
     543                 : /************************************************************************/
     544                 : 
     545               0 : int VSIArchiveFilesystemHandler::Rmdir( const char *pszDirname )
     546                 : {
     547               0 :     return -1;
     548                 : }
     549                 : 
     550                 : /************************************************************************/
     551                 : /*                             ReadDir()                                */
     552                 : /************************************************************************/
     553                 : 
     554              32 : char** VSIArchiveFilesystemHandler::ReadDir( const char *pszDirname )
     555                 : {
     556              32 :     CPLString osInArchiveSubDir;
     557              32 :     char* archiveFilename = SplitFilename(pszDirname, osInArchiveSubDir, TRUE);
     558              32 :     if (archiveFilename == NULL)
     559               2 :         return NULL;
     560              30 :     int lenInArchiveSubDir = strlen(osInArchiveSubDir);
     561                 : 
     562              30 :     char **papszDir = NULL;
     563                 :     
     564              30 :     const VSIArchiveContent* content = GetContentOfArchive(archiveFilename);
     565              30 :     if (!content)
     566                 :     {
     567               0 :         CPLFree(archiveFilename);
     568               0 :         return NULL;
     569                 :     }
     570                 : 
     571                 :     if (ENABLE_DEBUG) CPLDebug("VSIArchive", "Read dir %s", pszDirname);
     572                 :     int i;
     573             264 :     for(i=0;i<content->nEntries;i++)
     574                 :     {
     575             234 :         const char* fileName = content->entries[i].fileName;
     576                 :         /* Only list entries at the same level of inArchiveSubDir */
     577             296 :         if (lenInArchiveSubDir != 0 &&
     578                 :             strncmp(fileName, osInArchiveSubDir, lenInArchiveSubDir) == 0 &&
     579              42 :             (fileName[lenInArchiveSubDir] == '/' || fileName[lenInArchiveSubDir] == '\\') &&
     580              20 :             fileName[lenInArchiveSubDir + 1] != 0)
     581                 :         {
     582              20 :             const char* slash = strchr(fileName + lenInArchiveSubDir + 1, '/');
     583              20 :             if (slash == NULL)
     584              13 :                 slash = strchr(fileName + lenInArchiveSubDir + 1, '\\');
     585              20 :             if (slash == NULL || slash[1] == 0)
     586                 :             {
     587              13 :                 char* tmpFileName = CPLStrdup(fileName);
     588              13 :                 if (slash != NULL)
     589                 :                 {
     590               0 :                     tmpFileName[strlen(tmpFileName)-1] = 0;
     591                 :                 }
     592                 :                 if (ENABLE_DEBUG)
     593                 :                     CPLDebug("VSIArchive", "Add %s as in directory %s\n",
     594                 :                             tmpFileName + lenInArchiveSubDir + 1, pszDirname);
     595              13 :                 papszDir = CSLAddString(papszDir, tmpFileName + lenInArchiveSubDir + 1);
     596              13 :                 CPLFree(tmpFileName);
     597                 :             }
     598                 :         }
     599             214 :         else if (lenInArchiveSubDir == 0 &&
     600                 :                  strchr(fileName, '/') == NULL && strchr(fileName, '\\') == NULL)
     601                 :         {
     602                 :             /* Only list toplevel files and directories */
     603                 :             if (ENABLE_DEBUG) CPLDebug("VSIArchive", "Add %s as in directory %s\n", fileName, pszDirname);
     604             182 :             papszDir = CSLAddString(papszDir, fileName);
     605                 :         }
     606                 :     }
     607                 : 
     608              30 :     CPLFree(archiveFilename);
     609              30 :     return papszDir;
     610                 : }

Generated by: LCOV version 1.7