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