LCOV - code coverage report
Current view: directory - port - cpl_vsi_mem.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 272 234 86.0 %
Date: 2012-04-28 Functions: 32 24 75.0 %

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

Generated by: LCOV version 1.7