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