LTP GCOV extension - code coverage report
Current view: directory - port - cpl_vsi_mem.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 257
Code covered: 76.7 % Executed lines: 197

       1                 : /******************************************************************************
       2                 :  * $Id: cpl_vsi_mem.cpp 20025 2010-07-11 17:13:02Z rouault $
       3                 :  *
       4                 :  * Project:  VSI Virtual File System
       5                 :  * Purpose:  Implementation of Memory Buffer virtual IO functions.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
      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                 : /* Remove annoying warnings in eVC++ and VC++ 6.0 */
      31                 : #if defined(WIN32CE)
      32                 : #  pragma warning(disable:4786)
      33                 : #endif
      34                 : 
      35                 : #include "cpl_vsi_virtual.h"
      36                 : #include "cpl_string.h"
      37                 : #include "cpl_multiproc.h"
      38                 : #include <map>
      39                 : 
      40                 : #if defined(WIN32CE)
      41                 : #  include <wce_errno.h>
      42                 : #endif
      43                 : 
      44                 : 
      45                 : CPL_CVSID("$Id: cpl_vsi_mem.cpp 20025 2010-07-11 17:13:02Z rouault $");
      46                 : 
      47                 : /*
      48                 : ** Notes on Multithreading:
      49                 : **
      50                 : ** VSIMemFilesystemHandler: This class maintains a mutex to protect
      51                 : ** access and update of the oFileList array which has all the "files" in 
      52                 : ** the memory filesystem area.  It is expected that multiple threads would
      53                 : ** want to create and read different files at the same time and so might
      54                 : ** collide access oFileList without the mutex.
      55                 : **
      56                 : ** VSIMemFile: In theory we could allow different threads to update the
      57                 : ** the same memory file, but for simplicity we restrict to single writer,
      58                 : ** multiple reader as an expectation on the application code (not enforced
      59                 : ** here), which means we don't need to do any protection of this class.
      60                 : **
      61                 : ** VSIMemHandle: This is essentially a "current location" representing
      62                 : ** on accessor to a file, and is inherently intended only to be used in 
      63                 : ** a single thread. 
      64                 : **
      65                 : ** In General:
      66                 : **
      67                 : ** Multiple threads accessing the memory filesystem are ok as long as
      68                 : **  1) A given VSIMemHandle (ie. FILE * at app level) isn't used by multiple 
      69                 : **     threads at once. 
      70                 : **  2) A given memory file isn't accessed by more than one thread unless
      71                 : **     all threads are just reading.
      72                 : */ 
      73                 : 
      74                 : /************************************************************************/
      75                 : /* ==================================================================== */
      76                 : /*                              VSIMemFile                              */
      77                 : /* ==================================================================== */
      78                 : /************************************************************************/
      79                 : 
      80                 : class VSIMemFile
      81                 : {
      82                 : public:
      83                 :     CPLString     osFilename;
      84                 :     int           nRefCount;
      85                 : 
      86                 :     int           bIsDirectory;
      87                 : 
      88                 :     int           bOwnData;
      89                 :     GByte        *pabyData;
      90                 :     vsi_l_offset  nLength;
      91                 :     vsi_l_offset  nAllocLength;
      92                 : 
      93                 :                   VSIMemFile();
      94                 :     virtual       ~VSIMemFile();
      95                 : 
      96                 :     bool          SetLength( vsi_l_offset nNewSize );
      97                 : };
      98                 : 
      99                 : /************************************************************************/
     100                 : /* ==================================================================== */
     101                 : /*                             VSIMemHandle                             */
     102                 : /* ==================================================================== */
     103                 : /************************************************************************/
     104                 : 
     105                 : class VSIMemHandle : public VSIVirtualHandle
     106            1562 : { 
     107                 :   public:
     108                 :     VSIMemFile    *poFile;
     109                 :     vsi_l_offset  nOffset;
     110                 :     int           bUpdate;
     111                 : 
     112                 :     virtual int       Seek( vsi_l_offset nOffset, int nWhence );
     113                 :     virtual vsi_l_offset Tell();
     114                 :     virtual size_t    Read( void *pBuffer, size_t nSize, size_t nMemb );
     115                 :     virtual size_t    Write( const void *pBuffer, size_t nSize, size_t nMemb );
     116                 :     virtual int       Eof();
     117                 :     virtual int       Close();
     118                 : };
     119                 : 
     120                 : /************************************************************************/
     121                 : /* ==================================================================== */
     122                 : /*                       VSIMemFilesystemHandler                        */
     123                 : /* ==================================================================== */
     124                 : /************************************************************************/
     125                 : 
     126                 : class VSIMemFilesystemHandler : public VSIFilesystemHandler 
     127                 : {
     128                 : public:
     129                 :     std::map<CPLString,VSIMemFile*>   oFileList;
     130                 :     void             *hMutex;
     131                 : 
     132                 :                      VSIMemFilesystemHandler();
     133                 :     virtual          ~VSIMemFilesystemHandler();
     134                 : 
     135                 :     virtual VSIVirtualHandle *Open( const char *pszFilename, 
     136                 :                                     const char *pszAccess);
     137                 :     virtual int      Stat( const char *pszFilename, VSIStatBufL *pStatBuf );
     138                 :     virtual int      Unlink( const char *pszFilename );
     139                 :     virtual int      Mkdir( const char *pszDirname, long nMode );
     140                 :     virtual int      Rmdir( const char *pszDirname );
     141                 :     virtual char   **ReadDir( const char *pszDirname );
     142                 :     virtual int      Rename( const char *oldpath, const char *newpath );
     143                 : 
     144                 :     static  void     NormalizePath( CPLString & );
     145                 : };
     146                 : 
     147                 : /************************************************************************/
     148                 : /* ==================================================================== */
     149                 : /*                              VSIMemFile                              */
     150                 : /* ==================================================================== */
     151                 : /************************************************************************/
     152                 : 
     153                 : /************************************************************************/
     154                 : /*                             VSIMemFile()                             */
     155                 : /************************************************************************/
     156                 : 
     157             204 : VSIMemFile::VSIMemFile()
     158                 : 
     159                 : {
     160             204 :     nRefCount = 0;
     161             204 :     bIsDirectory = FALSE;
     162             204 :     bOwnData = TRUE;
     163             204 :     pabyData = NULL;
     164             204 :     nLength = 0;
     165             204 :     nAllocLength = 0;
     166             204 : }
     167                 : 
     168                 : /************************************************************************/
     169                 : /*                            ~VSIMemFile()                             */
     170                 : /************************************************************************/
     171                 : 
     172             194 : VSIMemFile::~VSIMemFile()
     173                 : 
     174                 : {
     175             194 :     if( nRefCount != 0 )
     176                 :         CPLDebug( "VSIMemFile", "Memory file %s deleted with %d references.",
     177               0 :                   osFilename.c_str(), nRefCount );
     178                 : 
     179             194 :     if( bOwnData && pabyData )
     180              97 :         CPLFree( pabyData );
     181             194 : }
     182                 : 
     183                 : /************************************************************************/
     184                 : /*                             SetLength()                              */
     185                 : /************************************************************************/
     186                 : 
     187            6258 : bool VSIMemFile::SetLength( vsi_l_offset nNewLength )
     188                 : 
     189                 : {
     190                 : /* -------------------------------------------------------------------- */
     191                 : /*      Grow underlying array if needed.                                */
     192                 : /* -------------------------------------------------------------------- */
     193            6258 :     if( nNewLength > nAllocLength )
     194                 :     {
     195                 :         /* If we don't own the buffer, we cannot reallocate it because */
     196                 :         /* the return address might be different from the one passed by */
     197                 :         /* the caller. Hence, the caller would not be able to free */
     198                 :         /* the buffer... */
     199             164 :         if( !bOwnData )
     200                 :         {
     201                 :             CPLError(CE_Failure, CPLE_NotSupported,
     202               0 :                      "Cannot extended in-memory file whose ownership was not transfered");
     203               0 :             return false;
     204                 :         }
     205                 :         
     206                 :         GByte *pabyNewData;
     207             164 :         vsi_l_offset nNewAlloc = (nNewLength + nNewLength / 10) + 5000;
     208                 : 
     209             164 :         pabyNewData = (GByte *) VSIRealloc(pabyData, (size_t)nNewAlloc);
     210             164 :         if( pabyNewData == NULL )
     211               0 :             return false;
     212                 :             
     213                 :         /* Clear the new allocated part of the buffer */
     214             164 :         memset(pabyNewData + nAllocLength, 0, nNewAlloc - nAllocLength);
     215                 : 
     216             164 :         pabyData = pabyNewData;
     217             164 :         nAllocLength = nNewAlloc;
     218                 :     }
     219                 : 
     220            6258 :     nLength = nNewLength;
     221                 : 
     222            6258 :     return true;
     223                 : }
     224                 : 
     225                 : /************************************************************************/
     226                 : /* ==================================================================== */
     227                 : /*                             VSIMemHandle                             */
     228                 : /* ==================================================================== */
     229                 : /************************************************************************/
     230                 : 
     231                 : 
     232                 : /************************************************************************/
     233                 : /*                               Close()                                */
     234                 : /************************************************************************/
     235                 : 
     236             781 : int VSIMemHandle::Close()
     237                 : 
     238                 : {
     239             781 :     if( --(poFile->nRefCount) == 0 )
     240               2 :         delete poFile;
     241                 : 
     242             781 :     poFile = NULL;
     243                 : 
     244             781 :     return 0;
     245                 : }
     246                 : 
     247                 : /************************************************************************/
     248                 : /*                                Seek()                                */
     249                 : /************************************************************************/
     250                 : 
     251            5914 : int VSIMemHandle::Seek( vsi_l_offset nOffset, int nWhence )
     252                 : 
     253                 : {
     254            5914 :     if( nWhence == SEEK_CUR )
     255             130 :         this->nOffset += nOffset;
     256            5784 :     else if( nWhence == SEEK_SET )
     257            5366 :         this->nOffset = nOffset;
     258             418 :     else if( nWhence == SEEK_END )
     259             418 :         this->nOffset = poFile->nLength + nOffset;
     260                 :     else
     261                 :     {
     262               0 :         errno = EINVAL;
     263               0 :         return -1;
     264                 :     }
     265                 : 
     266                 :     if( this->nOffset < 0 )
     267                 :     {
     268                 :         this->nOffset = 0;
     269                 :         return -1;
     270                 :     }
     271                 :     
     272            5914 :     if( this->nOffset > poFile->nLength )
     273                 :     {
     274              35 :         if( !bUpdate ) // Read-only files cannot be extended by seek.
     275                 :         {
     276                 :             CPLDebug( "VSIMemHandle", 
     277                 :                       "Attempt to extend read-only file '%s' to length %d from %d, .", 
     278                 :                       poFile->osFilename.c_str(), 
     279               0 :                       (int) this->nOffset, (int) poFile->nLength );
     280                 : 
     281               0 :             this->nOffset = poFile->nLength;
     282               0 :             errno = EACCES;
     283               0 :             return -1;
     284                 :         }
     285                 :         else // Writeable files are zero-extended by seek past end.
     286                 :         {
     287              35 :             if( !poFile->SetLength( this->nOffset ) )
     288               0 :                 return -1;
     289                 :         }
     290                 :     }
     291                 : 
     292            5914 :     return 0;
     293                 : }
     294                 : 
     295                 : /************************************************************************/
     296                 : /*                                Tell()                                */
     297                 : /************************************************************************/
     298                 : 
     299            3079 : vsi_l_offset VSIMemHandle::Tell()
     300                 : 
     301                 : {
     302            3079 :     return nOffset;
     303                 : }
     304                 : 
     305                 : /************************************************************************/
     306                 : /*                                Read()                                */
     307                 : /************************************************************************/
     308                 : 
     309           42334 : size_t VSIMemHandle::Read( void * pBuffer, size_t nSize, size_t nCount )
     310                 : 
     311                 : {
     312                 :     // FIXME: Integer overflow check should be placed here:
     313           42334 :     size_t nBytesToRead = nSize * nCount; 
     314                 : 
     315           42334 :     if( nBytesToRead + nOffset > poFile->nLength )
     316                 :     {
     317             633 :         nBytesToRead = (size_t)(poFile->nLength - nOffset);
     318             633 :         nCount = nBytesToRead / nSize;
     319                 :     }
     320                 : 
     321           42334 :     memcpy( pBuffer, poFile->pabyData + nOffset, (size_t)nBytesToRead );
     322           42334 :     nOffset += nBytesToRead;
     323                 : 
     324           42334 :     return nCount;
     325                 : }
     326                 : 
     327                 : /************************************************************************/
     328                 : /*                               Write()                                */
     329                 : /************************************************************************/
     330                 : 
     331            7200 : size_t VSIMemHandle::Write( const void * pBuffer, size_t nSize, size_t nCount )
     332                 : 
     333                 : {
     334            7200 :     if( !bUpdate )
     335                 :     {
     336               0 :         errno = EACCES;
     337               0 :         return 0;
     338                 :     }
     339                 : 
     340                 :     // FIXME: Integer overflow check should be placed here:
     341            7200 :     size_t nBytesToWrite = nSize * nCount; 
     342                 : 
     343            7200 :     if( nBytesToWrite + nOffset > poFile->nLength )
     344                 :     {
     345            6189 :         if( !poFile->SetLength( nBytesToWrite + nOffset ) )
     346               0 :             return 0;
     347                 :     }
     348                 : 
     349            7200 :     memcpy( poFile->pabyData + nOffset, pBuffer, nBytesToWrite );
     350            7200 :     nOffset += nBytesToWrite;
     351                 : 
     352            7200 :     return nCount;
     353                 : }
     354                 : 
     355                 : /************************************************************************/
     356                 : /*                                Eof()                                 */
     357                 : /************************************************************************/
     358                 : 
     359            3736 : int VSIMemHandle::Eof()
     360                 : 
     361                 : {
     362            3736 :     return nOffset == poFile->nLength;
     363                 : }
     364                 : 
     365                 : /************************************************************************/
     366                 : /* ==================================================================== */
     367                 : /*                       VSIMemFilesystemHandler                        */
     368                 : /* ==================================================================== */
     369                 : /************************************************************************/
     370                 : 
     371                 : /************************************************************************/
     372                 : /*                      VSIMemFilesystemHandler()                       */
     373                 : /************************************************************************/
     374                 : 
     375             447 : VSIMemFilesystemHandler::VSIMemFilesystemHandler()
     376                 : 
     377                 : {
     378             447 :     hMutex = NULL;
     379             447 : }
     380                 : 
     381                 : /************************************************************************/
     382                 : /*                      ~VSIMemFilesystemHandler()                      */
     383                 : /************************************************************************/
     384                 : 
     385             432 : VSIMemFilesystemHandler::~VSIMemFilesystemHandler()
     386                 : 
     387                 : {
     388             432 :     std::map<CPLString,VSIMemFile*>::const_iterator iter;
     389                 : 
     390             432 :     for( iter = oFileList.begin(); iter != oFileList.end(); ++iter )
     391                 :     {
     392               0 :         iter->second->nRefCount--;
     393               0 :         delete iter->second;
     394                 :     }
     395                 : 
     396             432 :     if( hMutex != NULL )
     397               1 :         CPLDestroyMutex( hMutex );
     398             432 :     hMutex = NULL;
     399             432 : }
     400                 : 
     401                 : /************************************************************************/
     402                 : /*                                Open()                                */
     403                 : /************************************************************************/
     404                 : 
     405                 : VSIVirtualHandle *
     406                 : VSIMemFilesystemHandler::Open( const char *pszFilename, 
     407            1728 :                                const char *pszAccess )
     408                 : 
     409                 : {
     410            1728 :     CPLMutexHolder oHolder( &hMutex );
     411                 :     VSIMemFile *poFile;
     412            1728 :     CPLString osFilename = pszFilename;
     413            1728 :     NormalizePath( osFilename );
     414                 : 
     415                 : /* -------------------------------------------------------------------- */
     416                 : /*      Get the filename we are opening, create if needed.              */
     417                 : /* -------------------------------------------------------------------- */
     418            1728 :     if( oFileList.find(osFilename) == oFileList.end() )
     419            1052 :         poFile = NULL;
     420                 :     else
     421             676 :         poFile = oFileList[osFilename];
     422                 : 
     423            1728 :     if( strstr(pszAccess,"w") == NULL && poFile == NULL )
     424                 :     {
     425             947 :         errno = ENOENT;
     426             947 :         return NULL;
     427                 :     }
     428                 : 
     429             781 :     if( strstr(pszAccess,"w") )
     430                 :     {
     431             139 :         if( poFile )
     432              34 :             poFile->SetLength( 0 );
     433                 :         else
     434                 :         {
     435             105 :             poFile = new VSIMemFile;
     436             105 :             poFile->osFilename = osFilename;
     437             105 :             oFileList[poFile->osFilename] = poFile;
     438             105 :             poFile->nRefCount++; // for file list
     439                 :         }
     440                 :     }
     441                 : 
     442             781 :     if( poFile->bIsDirectory )
     443                 :     {
     444               0 :         errno = EISDIR;
     445               0 :         return NULL;
     446                 :     }
     447                 : 
     448                 : /* -------------------------------------------------------------------- */
     449                 : /*      Setup the file handle on this file.                             */
     450                 : /* -------------------------------------------------------------------- */
     451             781 :     VSIMemHandle *poHandle = new VSIMemHandle;
     452                 : 
     453             781 :     poHandle->poFile = poFile;
     454             781 :     poHandle->nOffset = 0;
     455            1700 :     if( strstr(pszAccess,"w") || strstr(pszAccess,"+") 
     456                 :         || strstr(pszAccess,"a") )
     457             277 :         poHandle->bUpdate = TRUE;
     458                 :     else
     459             504 :         poHandle->bUpdate = FALSE;
     460                 : 
     461             781 :     poFile->nRefCount++;
     462                 : 
     463             781 :     if( strstr(pszAccess,"a") )
     464               0 :         poHandle->nOffset = poFile->nLength;
     465                 : 
     466             781 :     return poHandle;
     467                 : }
     468                 : 
     469                 : /************************************************************************/
     470                 : /*                                Stat()                                */
     471                 : /************************************************************************/
     472                 : 
     473                 : int VSIMemFilesystemHandler::Stat( const char * pszFilename, 
     474            1415 :                                    VSIStatBufL * pStatBuf )
     475                 :     
     476                 : {
     477            1415 :     CPLMutexHolder oHolder( &hMutex );
     478                 : 
     479            1415 :     CPLString osFilename = pszFilename;
     480            1415 :     NormalizePath( osFilename );
     481                 : 
     482            1415 :     memset( pStatBuf, 0, sizeof(VSIStatBufL) );
     483                 : 
     484            1415 :     if ( osFilename == "/vsimem/" )
     485                 :     {
     486               1 :         pStatBuf->st_size = 0;
     487               1 :         pStatBuf->st_mode = S_IFDIR;
     488               1 :         return 0;
     489                 :     }
     490                 : 
     491            1414 :     if( oFileList.find(osFilename) == oFileList.end() )
     492                 :     {
     493            1153 :         errno = ENOENT;
     494            1153 :         return -1;
     495                 :     }
     496                 : 
     497             261 :     VSIMemFile *poFile = oFileList[osFilename];
     498                 : 
     499             261 :     memset( pStatBuf, 0, sizeof(VSIStatBufL) );
     500                 : 
     501             261 :     if( poFile->bIsDirectory )
     502                 :     {
     503               0 :         pStatBuf->st_size = 0;
     504               0 :         pStatBuf->st_mode = S_IFDIR;
     505                 :     }
     506                 :     else
     507                 :     {
     508             261 :         pStatBuf->st_size = (long)poFile->nLength;
     509             261 :         pStatBuf->st_mode = S_IFREG;
     510                 :     }
     511                 : 
     512             261 :     return 0;
     513                 : }
     514                 : 
     515                 : /************************************************************************/
     516                 : /*                               Unlink()                               */
     517                 : /************************************************************************/
     518                 : 
     519             291 : int VSIMemFilesystemHandler::Unlink( const char * pszFilename )
     520                 : 
     521                 : {
     522             291 :     CPLMutexHolder oHolder( &hMutex );
     523                 : 
     524             291 :     CPLString osFilename = pszFilename;
     525             291 :     NormalizePath( osFilename );
     526                 : 
     527                 :     VSIMemFile *poFile;
     528                 : 
     529             291 :     if( oFileList.find(osFilename) == oFileList.end() )
     530                 :     {
     531             100 :         errno = ENOENT;
     532             100 :         return -1;
     533                 :     }
     534                 :     else
     535                 :     {
     536             191 :         poFile = oFileList[osFilename];
     537                 : 
     538             191 :         if( --(poFile->nRefCount) == 0 )
     539             189 :             delete poFile;
     540                 : 
     541             191 :         oFileList.erase( oFileList.find(osFilename) );
     542                 : 
     543             191 :         return 0;
     544               0 :     }
     545                 : }
     546                 : 
     547                 : /************************************************************************/
     548                 : /*                               Mkdir()                                */
     549                 : /************************************************************************/
     550                 : 
     551                 : int VSIMemFilesystemHandler::Mkdir( const char * pszPathname,
     552               0 :                                     long nMode )
     553                 : 
     554                 : {
     555               0 :     CPLMutexHolder oHolder( &hMutex );
     556                 : 
     557               0 :     CPLString osPathname = pszPathname;
     558                 : 
     559               0 :     NormalizePath( osPathname );
     560                 : 
     561               0 :     if( oFileList.find(osPathname) != oFileList.end() )
     562                 :     {
     563               0 :         errno = EEXIST;
     564               0 :         return -1;
     565                 :     }
     566                 : 
     567               0 :     VSIMemFile *poFile = new VSIMemFile;
     568                 : 
     569               0 :     poFile->osFilename = osPathname;
     570               0 :     poFile->bIsDirectory = TRUE;
     571               0 :     oFileList[osPathname] = poFile;
     572               0 :     poFile->nRefCount++; /* referenced by file list */
     573                 : 
     574               0 :     return 0;
     575                 : }
     576                 : 
     577                 : /************************************************************************/
     578                 : /*                               Rmdir()                                */
     579                 : /************************************************************************/
     580                 : 
     581               0 : int VSIMemFilesystemHandler::Rmdir( const char * pszPathname )
     582                 : 
     583                 : {
     584               0 :     CPLMutexHolder oHolder( &hMutex );
     585                 : 
     586               0 :     return Unlink( pszPathname );
     587                 : }
     588                 : 
     589                 : /************************************************************************/
     590                 : /*                              ReadDir()                               */
     591                 : /************************************************************************/
     592                 : 
     593               7 : char **VSIMemFilesystemHandler::ReadDir( const char *pszPath )
     594                 : 
     595                 : {
     596               7 :     CPLMutexHolder oHolder( &hMutex );
     597                 : 
     598               7 :     CPLString osPath = pszPath;
     599                 : 
     600               7 :     NormalizePath( osPath );
     601                 : 
     602               7 :     std::map<CPLString,VSIMemFile*>::const_iterator iter;
     603               7 :     char **papszDir = NULL;
     604               7 :     int nPathLen = strlen(osPath);
     605                 : 
     606               7 :     if( osPath[nPathLen-1] == '/' )
     607               1 :         nPathLen--;
     608                 : 
     609                 :     /* In case of really big number of files in the directory, CSLAddString */
     610                 :     /* can be slow (see #2158). We then directly build the list. */
     611               7 :     int nItems=0;
     612               7 :     int nAllocatedItems=0;
     613                 : 
     614              46 :     for( iter = oFileList.begin(); iter != oFileList.end(); ++iter )
     615                 :     {
     616              39 :         const char *pszFilePath = iter->second->osFilename.c_str();
     617              39 :         if( EQUALN(osPath,pszFilePath,nPathLen)
     618                 :             && pszFilePath[nPathLen] == '/' 
     619                 :             && strstr(pszFilePath+nPathLen+1,"/") == NULL )
     620                 :         {
     621              18 :             if (nItems == 0)
     622                 :             {
     623               7 :                 papszDir = (char**) CPLCalloc(2,sizeof(char*));
     624               7 :                 nAllocatedItems = 1;
     625                 :             }
     626              11 :             else if (nItems >= nAllocatedItems)
     627                 :             {
     628               8 :                 nAllocatedItems = nAllocatedItems * 2;
     629                 :                 papszDir = (char**)CPLRealloc(papszDir, 
     630               8 :                                               (nAllocatedItems+2)*sizeof(char*));
     631                 :             }
     632                 : 
     633              18 :             papszDir[nItems] = CPLStrdup(pszFilePath+nPathLen+1);
     634              18 :             papszDir[nItems+1] = NULL;
     635                 : 
     636              18 :             nItems++;
     637                 :         }
     638                 :     }
     639                 : 
     640               7 :     return papszDir;
     641                 : }
     642                 : 
     643                 : /************************************************************************/
     644                 : /*                               Rename()                               */
     645                 : /************************************************************************/
     646                 : 
     647                 : int VSIMemFilesystemHandler::Rename( const char *pszOldPath,
     648               0 :                                      const char *pszNewPath )
     649                 : 
     650                 : {
     651               0 :     CPLMutexHolder oHolder( &hMutex );
     652                 : 
     653               0 :     CPLString osOldPath = pszOldPath;
     654               0 :     CPLString osNewPath = pszNewPath;
     655                 : 
     656               0 :     NormalizePath( osOldPath );
     657               0 :     NormalizePath( osNewPath );
     658                 : 
     659               0 :     if ( osOldPath.compare(osNewPath) == 0 )
     660               0 :         return 0;
     661                 : 
     662               0 :     if( oFileList.find(osOldPath) == oFileList.end() )
     663                 :     {
     664               0 :         errno = ENOENT;
     665               0 :         return -1;
     666                 :     }
     667                 :     else
     668                 :     {
     669               0 :         VSIMemFile* poFile = oFileList[osOldPath];
     670                 : 
     671               0 :         oFileList.erase( oFileList.find(osOldPath) );
     672                 : 
     673               0 :         Unlink(osNewPath);
     674                 : 
     675               0 :         oFileList[osNewPath] = poFile;
     676               0 :         poFile->osFilename = osNewPath;
     677                 : 
     678               0 :         return 0;
     679               0 :     }
     680                 : }
     681                 : 
     682                 : /************************************************************************/
     683                 : /*      NormalizePath()         */
     684                 : /************************************************************************/
     685                 : 
     686            3563 : void VSIMemFilesystemHandler::NormalizePath( CPLString &oPath )
     687                 : 
     688                 : {
     689            3563 :     int  i, nSize = oPath.size();
     690                 : 
     691           79761 :     for( i = 0; i < nSize; i++ )
     692                 :     {
     693           76198 :         if( oPath[i] == '\\' )
     694              12 :             oPath[i] = '/';
     695                 :     }
     696                 : 
     697            3563 : }
     698                 : 
     699                 : /************************************************************************/
     700                 : /*                     VSIInstallLargeFileHandler()                     */
     701                 : /************************************************************************/
     702                 : 
     703                 : /**
     704                 :  * \brief Install "memory" file system handler. 
     705                 :  *
     706                 :  * A special file handler is installed that allows block of memory to be
     707                 :  * treated as files.   All portions of the file system underneath the base
     708                 :  * path "/vsimem/" will be handled by this driver.  
     709                 :  *
     710                 :  * Normal VSI*L functions can be used freely to create and destroy memory
     711                 :  * arrays treating them as if they were real file system objects.  Some
     712                 :  * additional methods exist to efficient create memory file system objects
     713                 :  * without duplicating original copies of the data or to "steal" the block
     714                 :  * of memory associated with a memory file. 
     715                 :  *
     716                 :  * At this time the memory handler does not properly handle directory
     717                 :  * semantics for the memory portion of the filesystem.  The VSIReadDir()
     718                 :  * function is not supported though this will be corrected in the future. 
     719                 :  *
     720                 :  * Calling this function repeatedly should do no harm, though it is not
     721                 :  * necessary.  It is already called the first time a virtualizable 
     722                 :  * file access function (ie. VSIFOpenL(), VSIMkDir(), etc) is called. 
     723                 :  *
     724                 :  * This code example demonstrates using GDAL to translate from one memory
     725                 :  * buffer to another.
     726                 :  *
     727                 :  * \code
     728                 :  * GByte *ConvertBufferFormat( GByte *pabyInData, vsi_l_offset nInDataLength, 
     729                 :  *                             vsi_l_offset *pnOutDataLength )
     730                 :  * {
     731                 :  *     // create memory file system object from buffer.
     732                 :  *     VSIFCloseL( VSIFileFromMemBuffer( "/vsimem/work.dat", pabyInData,
     733                 :  *                                       nInDataLength, FALSE ) );
     734                 :  *
     735                 :  *     // Open memory buffer for read.
     736                 :  *     GDALDatasetH hDS = GDALOpen( "/vsimem/work.dat", GA_ReadOnly );
     737                 :  * 
     738                 :  *     // Get output format driver. 
     739                 :  *     GDALDriverH hDriver = GDALGetDriverByName( "GTiff" );
     740                 :  *     GDALDatasetH hOutDS;
     741                 :  *
     742                 :  *     hOutDS = GDALCreateCopy( hDriver, "/vsimem/out.tif", hDS, TRUE, NULL, 
     743                 :  *                              NULL, NULL );
     744                 :  * 
     745                 :  *     // close source file, and "unlink" it.  
     746                 :  *     GDALClose( hDS );
     747                 :  *     VSIUnlink( "/vsimem/work.dat" );
     748                 :  *
     749                 :  *     // seize the buffer associated with the output file.
     750                 :  *
     751                 :  *     return VSIGetMemFileBuffer( "/vsimem/out.tif", pnOutDataLength, TRUE );
     752                 :  * }
     753                 :  * \endcode
     754                 :  */
     755                 : 
     756             447 : void VSIInstallMemFileHandler()
     757                 : {
     758             447 :     VSIFileManager::InstallHandler( "/vsimem/", new VSIMemFilesystemHandler );
     759             447 : }
     760                 : 
     761                 : /************************************************************************/
     762                 : /*                        VSIFileFromMemBuffer()                        */
     763                 : /************************************************************************/
     764                 : 
     765                 : /**
     766                 :  * \brief Create memory "file" from a buffer.
     767                 :  *
     768                 :  * A virtual memory file is created from the passed buffer with the indicated
     769                 :  * filename.  Under normal conditions the filename would need to be absolute
     770                 :  * and within the /vsimem/ portion of the filesystem.  
     771                 :  *
     772                 :  * If bTakeOwnership is TRUE, then the memory file system handler will take
     773                 :  * ownership of the buffer, freeing it when the file is deleted.  Otherwise
     774                 :  * it remains the responsibility of the caller, but should not be freed as
     775                 :  * long as it might be accessed as a file.  In no circumstances does this
     776                 :  * function take a copy of the pabyData contents. 
     777                 :  *
     778                 :  * @param pszFilename the filename to be created.
     779                 :  * @param pabyData the data buffer for the file. 
     780                 :  * @param nDataLength the length of buffer in bytes.
     781                 :  * @param bTakeOwnership TRUE to transfer "ownership" of buffer or FALSE. 
     782                 :  *
     783                 :  * @return open file handle on created file (see VSIFOpenL()). 
     784                 :  */
     785                 : 
     786                 : FILE *VSIFileFromMemBuffer( const char *pszFilename, 
     787                 :                           GByte *pabyData, 
     788                 :                           vsi_l_offset nDataLength,
     789              99 :                           int bTakeOwnership )
     790                 : 
     791                 : {
     792              99 :     if( VSIFileManager::GetHandler("") 
     793                 :         == VSIFileManager::GetHandler("/vsimem/") )
     794               0 :         VSIInstallMemFileHandler();
     795                 : 
     796                 :     VSIMemFilesystemHandler *poHandler = (VSIMemFilesystemHandler *) 
     797              99 :         VSIFileManager::GetHandler("/vsimem/");
     798                 : 
     799              99 :     if (pszFilename == NULL)
     800               0 :         return NULL;
     801                 : 
     802              99 :     CPLString osFilename = pszFilename;
     803              99 :     VSIMemFilesystemHandler::NormalizePath( osFilename );
     804                 : 
     805              99 :     VSIMemFile *poFile = new VSIMemFile;
     806                 : 
     807              99 :     poFile->osFilename = osFilename;
     808              99 :     poFile->bOwnData = bTakeOwnership;
     809              99 :     poFile->pabyData = pabyData;
     810              99 :     poFile->nLength = nDataLength;
     811              99 :     poFile->nAllocLength = nDataLength;
     812                 : 
     813                 :     {
     814              99 :         CPLMutexHolder oHolder( &poHandler->hMutex );
     815              99 :         poHandler->Unlink(osFilename);
     816              99 :         poHandler->oFileList[poFile->osFilename] = poFile;
     817              99 :         poFile->nRefCount++;
     818                 :     }
     819                 : 
     820              99 :     return (FILE *) poHandler->Open( osFilename, "r+" );
     821                 : }
     822                 : 
     823                 : /************************************************************************/
     824                 : /*                        VSIGetMemFileBuffer()                         */
     825                 : /************************************************************************/
     826                 : 
     827                 : /**
     828                 :  * \brief Fetch buffer underlying memory file. 
     829                 :  *
     830                 :  * This function returns a pointer to the memory buffer underlying a 
     831                 :  * virtual "in memory" file.  If bUnlinkAndSeize is TRUE the filesystem
     832                 :  * object will be deleted, and ownership of the buffer will pass to the 
     833                 :  * caller otherwise the underlying file will remain in existance. 
     834                 :  *
     835                 :  * @param pszFilename the name of the file to grab the buffer of.
     836                 :  * @param pnDataLength (file) length returned in this variable.
     837                 :  * @param bUnlinkAndSeize TRUE to remove the file, or FALSE to leave unaltered.
     838                 :  *
     839                 :  * @return pointer to memory buffer or NULL on failure.
     840                 :  */
     841                 : 
     842                 : GByte *VSIGetMemFileBuffer( const char *pszFilename, 
     843                 :                             vsi_l_offset *pnDataLength,
     844              23 :                             int bUnlinkAndSeize )
     845                 : 
     846                 : {
     847                 :     VSIMemFilesystemHandler *poHandler = (VSIMemFilesystemHandler *) 
     848              23 :         VSIFileManager::GetHandler("/vsimem/");
     849                 : 
     850              23 :     if (pszFilename == NULL)
     851               0 :         return NULL;
     852                 : 
     853              23 :     CPLString osFilename = pszFilename;
     854              23 :     VSIMemFilesystemHandler::NormalizePath( osFilename );
     855                 : 
     856              23 :     CPLMutexHolder oHolder( &poHandler->hMutex );
     857                 : 
     858              23 :     if( poHandler->oFileList.find(osFilename) == poHandler->oFileList.end() )
     859              23 :         return NULL;
     860                 : 
     861              23 :     VSIMemFile *poFile = poHandler->oFileList[osFilename];
     862                 :     GByte *pabyData;
     863                 : 
     864              23 :     pabyData = poFile->pabyData;
     865              23 :     if( pnDataLength != NULL )
     866              23 :         *pnDataLength = poFile->nLength;
     867                 :     
     868              23 :     if( bUnlinkAndSeize )
     869                 :     {
     870               3 :         if( !poFile->bOwnData )
     871                 :             CPLDebug( "VSIMemFile", 
     872               0 :                       "File doesn't own data in VSIGetMemFileBuffer!" );
     873                 :         else
     874               3 :             poFile->bOwnData = FALSE;
     875                 : 
     876               3 :         poHandler->oFileList.erase( poHandler->oFileList.find(osFilename) );
     877               3 :         --(poFile->nRefCount);
     878               3 :         delete poFile;
     879                 :     }
     880                 : 
     881              23 :     return pabyData;
     882                 : }
     883                 :                             

Generated by: LTP GCOV extension version 1.5