LCOV - code coverage report
Current view: directory - port - cpl_vsi_mem.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 226 180 79.6 %
Date: 2010-01-09 Functions: 26 24 92.3 %

       1                 : /******************************************************************************
       2                 :  * $Id: cpl_vsi_mem.cpp 18253 2009-12-10 19:53:21Z 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 18253 2009-12-10 19:53:21Z 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            1512 : { 
     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                 :     static  void     NormalizePath( CPLString & );
     143                 : };
     144                 : 
     145                 : /************************************************************************/
     146                 : /* ==================================================================== */
     147                 : /*                              VSIMemFile                              */
     148                 : /* ==================================================================== */
     149                 : /************************************************************************/
     150                 : 
     151                 : /************************************************************************/
     152                 : /*                             VSIMemFile()                             */
     153                 : /************************************************************************/
     154                 : 
     155             116 : VSIMemFile::VSIMemFile()
     156                 : 
     157                 : {
     158             116 :     nRefCount = 0;
     159             116 :     bIsDirectory = FALSE;
     160             116 :     bOwnData = TRUE;
     161             116 :     pabyData = NULL;
     162             116 :     nLength = 0;
     163             116 :     nAllocLength = 0;
     164             116 : }
     165                 : 
     166                 : /************************************************************************/
     167                 : /*                            ~VSIMemFile()                             */
     168                 : /************************************************************************/
     169                 : 
     170             224 : VSIMemFile::~VSIMemFile()
     171                 : 
     172                 : {
     173             112 :     if( nRefCount != 0 )
     174                 :         CPLDebug( "VSIMemFile", "Memory file %s deleted with %d references.",
     175               0 :                   osFilename.c_str(), nRefCount );
     176                 : 
     177             112 :     if( bOwnData && pabyData )
     178              51 :         CPLFree( pabyData );
     179             224 : }
     180                 : 
     181                 : /************************************************************************/
     182                 : /*                             SetLength()                              */
     183                 : /************************************************************************/
     184                 : 
     185            4892 : bool VSIMemFile::SetLength( vsi_l_offset nNewLength )
     186                 : 
     187                 : {
     188                 : /* -------------------------------------------------------------------- */
     189                 : /*      Grow underlying array if needed.                                */
     190                 : /* -------------------------------------------------------------------- */
     191            4892 :     if( nNewLength > nAllocLength )
     192                 :     {
     193                 :         /* If we don't own the buffer, we cannot reallocate it because */
     194                 :         /* the return address might be different from the one passed by */
     195                 :         /* the caller. Hence, the caller would not be able to free */
     196                 :         /* the buffer... */
     197             125 :         if( !bOwnData )
     198                 :         {
     199                 :             CPLError(CE_Failure, CPLE_NotSupported,
     200               0 :                      "Cannot extended in-memory file whose ownership was not transfered");
     201               0 :             return false;
     202                 :         }
     203                 :         
     204                 :         GByte *pabyNewData;
     205             125 :         vsi_l_offset nNewAlloc = (nNewLength + nNewLength / 10) + 5000;
     206                 : 
     207             125 :         pabyNewData = (GByte *) VSIRealloc(pabyData, (size_t)nNewAlloc);
     208             125 :         if( pabyNewData == NULL )
     209               0 :             return false;
     210                 :             
     211                 :         /* Clear the new allocated part of the buffer */
     212             125 :         memset(pabyNewData + nAllocLength, 0, nNewAlloc - nAllocLength);
     213                 : 
     214             125 :         pabyData = pabyNewData;
     215             125 :         nAllocLength = nNewAlloc;
     216                 :     }
     217                 : 
     218            4892 :     nLength = nNewLength;
     219                 : 
     220            4892 :     return true;
     221                 : }
     222                 : 
     223                 : /************************************************************************/
     224                 : /* ==================================================================== */
     225                 : /*                             VSIMemHandle                             */
     226                 : /* ==================================================================== */
     227                 : /************************************************************************/
     228                 : 
     229                 : 
     230                 : /************************************************************************/
     231                 : /*                               Close()                                */
     232                 : /************************************************************************/
     233                 : 
     234             504 : int VSIMemHandle::Close()
     235                 : 
     236                 : {
     237             504 :     if( --(poFile->nRefCount) == 0 )
     238               2 :         delete poFile;
     239                 : 
     240             504 :     poFile = NULL;
     241                 : 
     242             504 :     return 0;
     243                 : }
     244                 : 
     245                 : /************************************************************************/
     246                 : /*                                Seek()                                */
     247                 : /************************************************************************/
     248                 : 
     249            5089 : int VSIMemHandle::Seek( vsi_l_offset nOffset, int nWhence )
     250                 : 
     251                 : {
     252            5089 :     if( nWhence == SEEK_CUR )
     253              51 :         this->nOffset += nOffset;
     254            5038 :     else if( nWhence == SEEK_SET )
     255            4842 :         this->nOffset = nOffset;
     256             196 :     else if( nWhence == SEEK_END )
     257             196 :         this->nOffset = poFile->nLength + nOffset;
     258                 :     else
     259                 :     {
     260               0 :         errno = EINVAL;
     261               0 :         return -1;
     262                 :     }
     263                 : 
     264                 :     if( this->nOffset < 0 )
     265                 :     {
     266                 :         this->nOffset = 0;
     267                 :         return -1;
     268                 :     }
     269                 :     
     270            5089 :     if( this->nOffset > poFile->nLength )
     271                 :     {
     272              40 :         if( !bUpdate ) // Read-only files cannot be extended by seek.
     273                 :         {
     274                 :             CPLDebug( "VSIMemHandle", 
     275                 :                       "Attempt to extend read-only file '%s' to length %d from %d, .", 
     276                 :                       poFile->osFilename.c_str(), 
     277               0 :                       (int) this->nOffset, (int) poFile->nLength );
     278                 : 
     279               0 :             this->nOffset = poFile->nLength;
     280               0 :             errno = EACCES;
     281               0 :             return -1;
     282                 :         }
     283                 :         else // Writeable files are zero-extended by seek past end.
     284                 :         {
     285              40 :             if( !poFile->SetLength( this->nOffset ) )
     286               0 :                 return -1;
     287                 :         }
     288                 :     }
     289                 : 
     290            5089 :     return 0;
     291                 : }
     292                 : 
     293                 : /************************************************************************/
     294                 : /*                                Tell()                                */
     295                 : /************************************************************************/
     296                 : 
     297            2482 : vsi_l_offset VSIMemHandle::Tell()
     298                 : 
     299                 : {
     300            2482 :     return nOffset;
     301                 : }
     302                 : 
     303                 : /************************************************************************/
     304                 : /*                                Read()                                */
     305                 : /************************************************************************/
     306                 : 
     307           25980 : size_t VSIMemHandle::Read( void * pBuffer, size_t nSize, size_t nCount )
     308                 : 
     309                 : {
     310                 :     // FIXME: Integer overflow check should be placed here:
     311           25980 :     size_t nBytesToRead = nSize * nCount; 
     312                 : 
     313           25980 :     if( nBytesToRead + nOffset > poFile->nLength )
     314                 :     {
     315             449 :         nBytesToRead = (size_t)(poFile->nLength - nOffset);
     316             449 :         nCount = nBytesToRead / nSize;
     317                 :     }
     318                 : 
     319           25980 :     memcpy( pBuffer, poFile->pabyData + nOffset, (size_t)nBytesToRead );
     320           25980 :     nOffset += nBytesToRead;
     321                 : 
     322           25980 :     return nCount;
     323                 : }
     324                 : 
     325                 : /************************************************************************/
     326                 : /*                               Write()                                */
     327                 : /************************************************************************/
     328                 : 
     329            5650 : size_t VSIMemHandle::Write( const void * pBuffer, size_t nSize, size_t nCount )
     330                 : 
     331                 : {
     332            5650 :     if( !bUpdate )
     333                 :     {
     334               0 :         errno = EACCES;
     335               0 :         return 0;
     336                 :     }
     337                 : 
     338                 :     // FIXME: Integer overflow check should be placed here:
     339            5650 :     size_t nBytesToWrite = nSize * nCount; 
     340                 : 
     341            5650 :     if( nBytesToWrite + nOffset > poFile->nLength )
     342                 :     {
     343            4818 :         if( !poFile->SetLength( nBytesToWrite + nOffset ) )
     344               0 :             return 0;
     345                 :     }
     346                 : 
     347            5650 :     memcpy( poFile->pabyData + nOffset, pBuffer, nBytesToWrite );
     348            5650 :     nOffset += nBytesToWrite;
     349                 : 
     350            5650 :     return nCount;
     351                 : }
     352                 : 
     353                 : /************************************************************************/
     354                 : /*                                Eof()                                 */
     355                 : /************************************************************************/
     356                 : 
     357            3706 : int VSIMemHandle::Eof()
     358                 : 
     359                 : {
     360            3706 :     return nOffset == poFile->nLength;
     361                 : }
     362                 : 
     363                 : /************************************************************************/
     364                 : /* ==================================================================== */
     365                 : /*                       VSIMemFilesystemHandler                        */
     366                 : /* ==================================================================== */
     367                 : /************************************************************************/
     368                 : 
     369                 : /************************************************************************/
     370                 : /*                      VSIMemFilesystemHandler()                       */
     371                 : /************************************************************************/
     372                 : 
     373             379 : VSIMemFilesystemHandler::VSIMemFilesystemHandler()
     374                 : 
     375                 : {
     376             379 :     hMutex = NULL;
     377             379 : }
     378                 : 
     379                 : /************************************************************************/
     380                 : /*                      ~VSIMemFilesystemHandler()                      */
     381                 : /************************************************************************/
     382                 : 
     383             726 : VSIMemFilesystemHandler::~VSIMemFilesystemHandler()
     384                 : 
     385                 : {
     386             363 :     std::map<CPLString,VSIMemFile*>::const_iterator iter;
     387                 : 
     388             363 :     for( iter = oFileList.begin(); iter != oFileList.end(); iter++ )
     389                 :     {
     390               0 :         iter->second->nRefCount--;
     391               0 :         delete iter->second;
     392                 :     }
     393                 : 
     394             363 :     if( hMutex != NULL )
     395               0 :         CPLDestroyMutex( hMutex );
     396             363 :     hMutex = NULL;
     397             726 : }
     398                 : 
     399                 : /************************************************************************/
     400                 : /*                                Open()                                */
     401                 : /************************************************************************/
     402                 : 
     403                 : VSIVirtualHandle *
     404             837 : VSIMemFilesystemHandler::Open( const char *pszFilename, 
     405                 :                                const char *pszAccess )
     406                 : 
     407                 : {
     408             837 :     CPLMutexHolder oHolder( &hMutex );
     409                 :     VSIMemFile *poFile;
     410             837 :     CPLString osFilename = pszFilename;
     411             837 :     NormalizePath( osFilename );
     412                 : 
     413                 : /* -------------------------------------------------------------------- */
     414                 : /*      Get the filename we are opening, create if needed.              */
     415                 : /* -------------------------------------------------------------------- */
     416             837 :     if( oFileList.find(osFilename) == oFileList.end() )
     417             401 :         poFile = NULL;
     418                 :     else
     419             436 :         poFile = oFileList[osFilename];
     420                 : 
     421             837 :     if( strstr(pszAccess,"w") == NULL && poFile == NULL )
     422                 :     {
     423             333 :         errno = ENOENT;
     424             333 :         return NULL;
     425                 :     }
     426                 : 
     427             504 :     if( strstr(pszAccess,"w") )
     428                 :     {
     429             102 :         if( poFile )
     430              34 :             poFile->SetLength( 0 );
     431                 :         else
     432                 :         {
     433              68 :             poFile = new VSIMemFile;
     434              68 :             poFile->osFilename = osFilename;
     435              68 :             oFileList[poFile->osFilename] = poFile;
     436              68 :             poFile->nRefCount++; // for file list
     437                 :         }
     438                 :     }
     439                 : 
     440             504 :     if( poFile->bIsDirectory )
     441                 :     {
     442               0 :         errno = EISDIR;
     443               0 :         return NULL;
     444                 :     }
     445                 : 
     446                 : /* -------------------------------------------------------------------- */
     447                 : /*      Setup the file handle on this file.                             */
     448                 : /* -------------------------------------------------------------------- */
     449             504 :     VSIMemHandle *poHandle = new VSIMemHandle;
     450                 : 
     451             504 :     poHandle->poFile = poFile;
     452             504 :     poHandle->nOffset = 0;
     453            1070 :     if( strstr(pszAccess,"w") || strstr(pszAccess,"+") 
     454                 :         || strstr(pszAccess,"a") )
     455             164 :         poHandle->bUpdate = TRUE;
     456                 :     else
     457             340 :         poHandle->bUpdate = FALSE;
     458                 : 
     459             504 :     poFile->nRefCount++;
     460                 : 
     461             504 :     if( strstr(pszAccess,"a") )
     462               0 :         poHandle->nOffset = poFile->nLength;
     463                 : 
     464             504 :     return poHandle;
     465                 : }
     466                 : 
     467                 : /************************************************************************/
     468                 : /*                                Stat()                                */
     469                 : /************************************************************************/
     470                 : 
     471             651 : int VSIMemFilesystemHandler::Stat( const char * pszFilename, 
     472                 :                                    VSIStatBufL * pStatBuf )
     473                 :     
     474                 : {
     475             651 :     CPLMutexHolder oHolder( &hMutex );
     476                 : 
     477             651 :     CPLString osFilename = pszFilename;
     478             651 :     NormalizePath( osFilename );
     479                 : 
     480             651 :     if( oFileList.find(osFilename) == oFileList.end() )
     481                 :     {
     482             492 :         errno = ENOENT;
     483             492 :         return -1;
     484                 :     }
     485                 : 
     486             159 :     VSIMemFile *poFile = oFileList[osFilename];
     487                 : 
     488             159 :     memset( pStatBuf, 0, sizeof(VSIStatBufL) );
     489                 : 
     490             159 :     if( poFile->bIsDirectory )
     491                 :     {
     492               0 :         pStatBuf->st_size = 0;
     493               0 :         pStatBuf->st_mode = S_IFDIR;
     494                 :     }
     495                 :     else
     496                 :     {
     497             159 :         pStatBuf->st_size = (long)poFile->nLength;
     498             159 :         pStatBuf->st_mode = S_IFREG;
     499                 :     }
     500                 : 
     501             159 :     return 0;
     502                 : }
     503                 : 
     504                 : /************************************************************************/
     505                 : /*                               Unlink()                               */
     506                 : /************************************************************************/
     507                 : 
     508              95 : int VSIMemFilesystemHandler::Unlink( const char * pszFilename )
     509                 : 
     510                 : {
     511              95 :     CPLMutexHolder oHolder( &hMutex );
     512                 : 
     513              95 :     CPLString osFilename = pszFilename;
     514              95 :     NormalizePath( osFilename );
     515                 : 
     516                 :     VSIMemFile *poFile;
     517                 : 
     518              95 :     if( oFileList.find(osFilename) == oFileList.end() )
     519                 :     {
     520               0 :         errno = ENOENT;
     521               0 :         return -1;
     522                 :     }
     523                 :     else
     524                 :     {
     525              95 :         poFile = oFileList[osFilename];
     526                 : 
     527              95 :         if( --(poFile->nRefCount) == 0 )
     528              93 :             delete poFile;
     529                 : 
     530              95 :         oFileList.erase( oFileList.find(osFilename) );
     531                 : 
     532              95 :         return 0;
     533               0 :     }
     534                 : }
     535                 : 
     536                 : /************************************************************************/
     537                 : /*                               Mkdir()                                */
     538                 : /************************************************************************/
     539                 : 
     540               0 : int VSIMemFilesystemHandler::Mkdir( const char * pszPathname,
     541                 :                                     long nMode )
     542                 : 
     543                 : {
     544               0 :     CPLMutexHolder oHolder( &hMutex );
     545                 : 
     546               0 :     CPLString osPathname = pszPathname;
     547                 : 
     548               0 :     NormalizePath( osPathname );
     549                 : 
     550               0 :     if( oFileList.find(osPathname) != oFileList.end() )
     551                 :     {
     552               0 :         errno = EEXIST;
     553               0 :         return -1;
     554                 :     }
     555                 : 
     556               0 :     VSIMemFile *poFile = new VSIMemFile;
     557                 : 
     558               0 :     poFile->osFilename = osPathname;
     559               0 :     poFile->bIsDirectory = TRUE;
     560               0 :     oFileList[osPathname] = poFile;
     561               0 :     poFile->nRefCount++; /* referenced by file list */
     562                 : 
     563               0 :     return 0;
     564                 : }
     565                 : 
     566                 : /************************************************************************/
     567                 : /*                               Rmdir()                                */
     568                 : /************************************************************************/
     569                 : 
     570               0 : int VSIMemFilesystemHandler::Rmdir( const char * pszPathname )
     571                 : 
     572                 : {
     573               0 :     CPLMutexHolder oHolder( &hMutex );
     574                 : 
     575               0 :     return Unlink( pszPathname );
     576                 : }
     577                 : 
     578                 : /************************************************************************/
     579                 : /*                              ReadDir()                               */
     580                 : /************************************************************************/
     581                 : 
     582               6 : char **VSIMemFilesystemHandler::ReadDir( const char *pszPath )
     583                 : 
     584                 : {
     585               6 :     CPLMutexHolder oHolder( &hMutex );
     586                 : 
     587               6 :     CPLString osPath = pszPath;
     588                 : 
     589               6 :     NormalizePath( osPath );
     590                 : 
     591               6 :     std::map<CPLString,VSIMemFile*>::const_iterator iter;
     592               6 :     char **papszDir = NULL;
     593               6 :     int nPathLen = strlen(osPath);
     594                 : 
     595               6 :     if( osPath[nPathLen-1] == '/' )
     596               0 :         nPathLen--;
     597                 : 
     598                 :     /* In case of really big number of files in the directory, CSLAddString */
     599                 :     /* can be slow (see #2158). We then directly build the list. */
     600               6 :     int nItems=0;
     601               6 :     int nAllocatedItems=0;
     602                 : 
     603              36 :     for( iter = oFileList.begin(); iter != oFileList.end(); iter++ )
     604                 :     {
     605              30 :         const char *pszFilePath = iter->second->osFilename.c_str();
     606              44 :         if( EQUALN(osPath,pszFilePath,nPathLen)
     607              14 :             && pszFilePath[nPathLen] == '/' 
     608                 :             && strstr(pszFilePath+nPathLen+1,"/") == NULL )
     609                 :         {
     610              14 :             if (nItems == 0)
     611                 :             {
     612               6 :                 papszDir = (char**) CPLCalloc(2,sizeof(char*));
     613               6 :                 nAllocatedItems = 1;
     614                 :             }
     615               8 :             else if (nItems >= nAllocatedItems)
     616                 :             {
     617               6 :                 nAllocatedItems = nAllocatedItems * 2;
     618                 :                 papszDir = (char**)CPLRealloc(papszDir, 
     619               6 :                                               (nAllocatedItems+2)*sizeof(char*));
     620                 :             }
     621                 : 
     622              14 :             papszDir[nItems] = CPLStrdup(pszFilePath+nPathLen+1);
     623              14 :             papszDir[nItems+1] = NULL;
     624                 : 
     625              14 :             nItems++;
     626                 :         }
     627                 :     }
     628                 : 
     629               6 :     return papszDir;
     630                 : }
     631                 : 
     632                 : /************************************************************************/
     633                 : /*      NormalizePath()         */
     634                 : /************************************************************************/
     635                 : 
     636            1589 : void VSIMemFilesystemHandler::NormalizePath( CPLString &oPath )
     637                 : 
     638                 : {
     639            1589 :     int  i, nSize = oPath.size();
     640                 : 
     641           38916 :     for( i = 0; i < nSize; i++ )
     642                 :     {
     643           37327 :         if( oPath[i] == '\\' )
     644               0 :             oPath[i] = '/';
     645                 :     }
     646                 : 
     647            1589 : }
     648                 : 
     649                 : /************************************************************************/
     650                 : /*                     VSIInstallLargeFileHandler()                     */
     651                 : /************************************************************************/
     652                 : 
     653                 : /**
     654                 :  * \brief Install "memory" file system handler. 
     655                 :  *
     656                 :  * A special file handler is installed that allows block of memory to be
     657                 :  * treated as files.   All portions of the file system underneath the base
     658                 :  * path "/vsimem/" will be handled by this driver.  
     659                 :  *
     660                 :  * Normal VSI*L functions can be used freely to create and destroy memory
     661                 :  * arrays treating them as if they were real file system objects.  Some
     662                 :  * additional methods exist to efficient create memory file system objects
     663                 :  * without duplicating original copies of the data or to "steal" the block
     664                 :  * of memory associated with a memory file. 
     665                 :  *
     666                 :  * At this time the memory handler does not properly handle directory
     667                 :  * semantics for the memory portion of the filesystem.  The VSIReadDir()
     668                 :  * function is not supported though this will be corrected in the future. 
     669                 :  *
     670                 :  * Calling this function repeatedly should do no harm, though it is not
     671                 :  * necessary.  It is already called the first time a virtualizable 
     672                 :  * file access function (ie. VSIFOpenL(), VSIMkDir(), etc) is called. 
     673                 :  *
     674                 :  * This code example demonstrates using GDAL to translate from one memory
     675                 :  * buffer to another.
     676                 :  *
     677                 :  * \code
     678                 :  * GByte *ConvertBufferFormat( GByte *pabyInData, vsi_l_offset nInDataLength, 
     679                 :  *                             vsi_l_offset *pnOutDataLength )
     680                 :  * {
     681                 :  *     // create memory file system object from buffer.
     682                 :  *     VSIFCloseL( VSIFileFromMemBuffer( "/vsimem/work.dat", pabyInData,
     683                 :  *                                       nInDataLength, FALSE ) );
     684                 :  *
     685                 :  *     // Open memory buffer for read.
     686                 :  *     GDALDatasetH hDS = GDALOpen( "/vsimem/work.dat", GA_ReadOnly );
     687                 :  * 
     688                 :  *     // Get output format driver. 
     689                 :  *     GDALDriverH hDriver = GDALGetDriverByName( "GTiff" );
     690                 :  *     GDALDatasetH hOutDS;
     691                 :  *
     692                 :  *     hOutDS = GDALCreateCopy( hDriver, "/vsimem/out.tif", hDS, TRUE, NULL, 
     693                 :  *                              NULL, NULL );
     694                 :  * 
     695                 :  *     // close source file, and "unlink" it.  
     696                 :  *     GDALClose( hDS );
     697                 :  *     VSIUnlink( "/vsimem/work.dat" );
     698                 :  *
     699                 :  *     // seize the buffer associated with the output file.
     700                 :  *
     701                 :  *     return VSIGetMemFileBuffer( "/vsimem/out.tif", pnOutDataLength, TRUE );
     702                 :  * }
     703                 :  * \endcode
     704                 :  */
     705                 : 
     706             379 : void VSIInstallMemFileHandler()
     707                 : {
     708             379 :     VSIFileManager::InstallHandler( "/vsimem/", new VSIMemFilesystemHandler );
     709             379 : }
     710                 : 
     711                 : /************************************************************************/
     712                 : /*                        VSIFileFromMemBuffer()                        */
     713                 : /************************************************************************/
     714                 : 
     715                 : /**
     716                 :  * \brief Create memory "file" from a buffer.
     717                 :  *
     718                 :  * A virtual memory file is created from the passed buffer with the indicated
     719                 :  * filename.  Under normal conditions the filename would need to be absolute
     720                 :  * and within the /vsimem/ portion of the filesystem.  
     721                 :  *
     722                 :  * If bTakeOwnership is TRUE, then the memory file system handler will take
     723                 :  * ownership of the buffer, freeing it when the file is deleted.  Otherwise
     724                 :  * it remains the responsibility of the caller, but should not be freed as
     725                 :  * long as it might be accessed as a file.  In no circumstances does this
     726                 :  * function take a copy of the pabyData contents. 
     727                 :  *
     728                 :  * @param pszFilename the filename to be created.
     729                 :  * @param pabyData the data buffer for the file. 
     730                 :  * @param nDataLength the length of buffer in bytes.
     731                 :  * @param bTakeOwnership TRUE to transfer "ownership" of buffer or FALSE. 
     732                 :  *
     733                 :  * @return open file handle on created file (see VSIFOpenL()). 
     734                 :  */
     735                 : 
     736              48 : FILE *VSIFileFromMemBuffer( const char *pszFilename, 
     737                 :                           GByte *pabyData, 
     738                 :                           vsi_l_offset nDataLength,
     739                 :                           int bTakeOwnership )
     740                 : 
     741                 : {
     742              48 :     if( VSIFileManager::GetHandler("") 
     743                 :         == VSIFileManager::GetHandler("/vsimem/") )
     744               0 :         VSIInstallMemFileHandler();
     745                 : 
     746                 :     VSIMemFilesystemHandler *poHandler = (VSIMemFilesystemHandler *) 
     747              48 :         VSIFileManager::GetHandler("/vsimem/");
     748                 : 
     749              48 :     VSIMemFile *poFile = new VSIMemFile;
     750                 : 
     751              96 :     poFile->osFilename = pszFilename;
     752              48 :     poFile->bOwnData = bTakeOwnership;
     753              48 :     poFile->pabyData = pabyData;
     754              48 :     poFile->nLength = nDataLength;
     755              48 :     poFile->nAllocLength = nDataLength;
     756                 : 
     757                 :     {
     758              48 :         CPLMutexHolder oHolder( &poHandler->hMutex );
     759              96 :         poHandler->oFileList[poFile->osFilename] = poFile;
     760              48 :         poFile->nRefCount++;
     761                 :     }
     762                 : 
     763              48 :     return (FILE *) poHandler->Open( pszFilename, "r+" );
     764                 : }
     765                 : 
     766                 : /************************************************************************/
     767                 : /*                        VSIGetMemFileBuffer()                         */
     768                 : /************************************************************************/
     769                 : 
     770                 : /**
     771                 :  * \brief Fetch buffer underlying memory file. 
     772                 :  *
     773                 :  * This function returns a pointer to the memory buffer underlying a 
     774                 :  * virtual "in memory" file.  If bUnlinkAndSeize is TRUE the filesystem
     775                 :  * object will be deleted, and ownership of the buffer will pass to the 
     776                 :  * caller otherwise the underlying file will remain in existance. 
     777                 :  *
     778                 :  * @param pszFilename the name of the file to grab the buffer of.
     779                 :  * @param pnDataLength (file) length returned in this variable.
     780                 :  * @param bUnlinkAndSeize TRUE to remove the file, or FALSE to leave unaltered.
     781                 :  *
     782                 :  * @return pointer to memory buffer or NULL on failure.
     783                 :  */
     784                 : 
     785              17 : GByte *VSIGetMemFileBuffer( const char *pszFilename, 
     786                 :                             vsi_l_offset *pnDataLength,
     787                 :                             int bUnlinkAndSeize )
     788                 : 
     789                 : {
     790                 :     VSIMemFilesystemHandler *poHandler = (VSIMemFilesystemHandler *) 
     791              17 :         VSIFileManager::GetHandler("/vsimem/");
     792                 : 
     793              17 :     CPLMutexHolder oHolder( &poHandler->hMutex );
     794                 : 
     795              17 :     if( poHandler->oFileList.find(pszFilename) == poHandler->oFileList.end() )
     796               0 :         return NULL;
     797                 : 
     798              17 :     VSIMemFile *poFile = poHandler->oFileList[pszFilename];
     799                 :     GByte *pabyData;
     800                 : 
     801              17 :     pabyData = poFile->pabyData;
     802              17 :     if( pnDataLength != NULL )
     803              17 :         *pnDataLength = poFile->nLength;
     804                 :     
     805              17 :     if( bUnlinkAndSeize )
     806                 :     {
     807              17 :         if( !poFile->bOwnData )
     808                 :             CPLDebug( "VSIMemFile", 
     809               0 :                       "File doesn't own data in VSIGetMemFileBuffer!" );
     810                 :         else
     811              17 :             poFile->bOwnData = FALSE;
     812                 : 
     813              17 :         poHandler->oFileList.erase( poHandler->oFileList.find(pszFilename) );
     814              17 :         --(poFile->nRefCount);
     815              17 :         delete poFile;
     816                 :     }
     817                 : 
     818              17 :     return pabyData;
     819                 : }
     820                 :                             

Generated by: LCOV version 1.7