LTP GCOV extension - code coverage report
Current view: directory - port - cpl_vsil_abstract_archive.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 220
Code covered: 76.4 % Executed lines: 168

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

Generated by: LTP GCOV extension version 1.5