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

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

Generated by: LCOV version 1.7