LCOV - code coverage report
Current view: directory - port - cpl_vsi_mem.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 269 231 85.9 %
Date: 2011-12-18 Functions: 32 24 75.0 %

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

Generated by: LCOV version 1.7