1 : /******************************************************************************
2 : * $Id: cpl_vsil_subfile.cpp 21533 2011-01-19 18:13:08Z warmerdam $
3 : *
4 : * Project: VSI Virtual File System
5 : * Purpose: Implementation of subfile 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 : #include "cpl_vsi_virtual.h"
31 : #include "cpl_string.h"
32 : #include "cpl_multiproc.h"
33 : #include <map>
34 :
35 : #if defined(WIN32CE)
36 : # include <wce_errno.h>
37 : #endif
38 :
39 : CPL_CVSID("$Id: cpl_vsil_subfile.cpp 21533 2011-01-19 18:13:08Z warmerdam $");
40 :
41 : /************************************************************************/
42 : /* ==================================================================== */
43 : /* VSISubFileHandle */
44 : /* ==================================================================== */
45 : /************************************************************************/
46 :
47 : class VSISubFileHandle : public VSIVirtualHandle
48 204 : {
49 : public:
50 : VSILFILE *fp;
51 : vsi_l_offset nSubregionOffset;
52 : vsi_l_offset nSubregionSize;
53 :
54 : virtual int Seek( vsi_l_offset nOffset, int nWhence );
55 : virtual vsi_l_offset Tell();
56 : virtual size_t Read( void *pBuffer, size_t nSize, size_t nMemb );
57 : virtual size_t Write( const void *pBuffer, size_t nSize, size_t nMemb );
58 : virtual int Eof();
59 : virtual int Close();
60 : };
61 :
62 : /************************************************************************/
63 : /* ==================================================================== */
64 : /* VSISubFileFilesystemHandler */
65 : /* ==================================================================== */
66 : /************************************************************************/
67 :
68 : class VSISubFileFilesystemHandler : public VSIFilesystemHandler
69 : {
70 : public:
71 : VSISubFileFilesystemHandler();
72 : virtual ~VSISubFileFilesystemHandler();
73 :
74 : int DecomposePath( const char *pszPath,
75 : CPLString &osFilename,
76 : vsi_l_offset &nSubFileOffset,
77 : vsi_l_offset &nSubFileSize );
78 :
79 : virtual VSIVirtualHandle *Open( const char *pszFilename,
80 : const char *pszAccess);
81 : virtual int Stat( const char *pszFilename, VSIStatBufL *pStatBuf, int nFlags );
82 : virtual int Unlink( const char *pszFilename );
83 : virtual int Mkdir( const char *pszDirname, long nMode );
84 : virtual int Rmdir( const char *pszDirname );
85 : virtual char **ReadDir( const char *pszDirname );
86 : };
87 :
88 : /************************************************************************/
89 : /* ==================================================================== */
90 : /* VSISubFileHandle */
91 : /* ==================================================================== */
92 : /************************************************************************/
93 :
94 : /************************************************************************/
95 : /* Close() */
96 : /************************************************************************/
97 :
98 102 : int VSISubFileHandle::Close()
99 :
100 : {
101 102 : VSIFCloseL( fp );
102 102 : fp = NULL;
103 :
104 102 : return 0;
105 : }
106 :
107 : /************************************************************************/
108 : /* Seek() */
109 : /************************************************************************/
110 :
111 1088 : int VSISubFileHandle::Seek( vsi_l_offset nOffset, int nWhence )
112 :
113 : {
114 1088 : if( nWhence == SEEK_SET )
115 1028 : nOffset += nSubregionOffset;
116 60 : else if( nWhence == SEEK_CUR )
117 : {
118 : // handle normally.
119 : }
120 60 : else if( nWhence == SEEK_END )
121 : {
122 60 : if( nSubregionSize != 0 )
123 : {
124 54 : nOffset = nSubregionOffset + nSubregionSize;
125 54 : nWhence = SEEK_SET;
126 : }
127 : }
128 : else
129 : {
130 0 : errno = EINVAL;
131 0 : return -1;
132 : }
133 :
134 1088 : return VSIFSeekL( fp, nOffset, nWhence );
135 : }
136 :
137 : /************************************************************************/
138 : /* Tell() */
139 : /************************************************************************/
140 :
141 3250 : vsi_l_offset VSISubFileHandle::Tell()
142 :
143 : {
144 3250 : return VSIFTellL( fp ) - nSubregionOffset;
145 : }
146 :
147 : /************************************************************************/
148 : /* Read() */
149 : /************************************************************************/
150 :
151 7910 : size_t VSISubFileHandle::Read( void * pBuffer, size_t nSize, size_t nCount )
152 :
153 : {
154 7910 : if (nSubregionSize == 0)
155 211 : return VSIFReadL( pBuffer, nSize, nCount, fp );
156 :
157 7699 : if (nSize == 0)
158 0 : return 0;
159 :
160 7699 : vsi_l_offset nCurOffset = VSIFTellL(fp);
161 7699 : if (nCurOffset >= nSubregionOffset + nSubregionSize)
162 7 : return 0;
163 :
164 7692 : size_t nByteToRead = nSize * nCount;
165 7692 : if (nCurOffset + nByteToRead > nSubregionOffset + nSubregionSize)
166 : {
167 23 : int nRead = (int)VSIFReadL( pBuffer, 1, (size_t)(nSubregionOffset + nSubregionSize - nCurOffset), fp);
168 23 : return nRead / nSize;
169 : }
170 : else
171 7669 : return VSIFReadL( pBuffer, nSize, nCount, fp );
172 : }
173 :
174 : /************************************************************************/
175 : /* Write() */
176 : /************************************************************************/
177 :
178 1585 : size_t VSISubFileHandle::Write( const void * pBuffer, size_t nSize, size_t nCount )
179 :
180 : {
181 1585 : if (nSubregionSize == 0)
182 1585 : return VSIFWriteL( pBuffer, nSize, nCount, fp );
183 :
184 0 : if (nSize == 0)
185 0 : return 0;
186 :
187 0 : vsi_l_offset nCurOffset = VSIFTellL(fp);
188 0 : if (nCurOffset >= nSubregionOffset + nSubregionSize)
189 0 : return 0;
190 :
191 0 : size_t nByteToWrite = nSize * nCount;
192 0 : if (nCurOffset + nByteToWrite > nSubregionOffset + nSubregionSize)
193 : {
194 0 : int nWritten = (int)VSIFWriteL( pBuffer, 1, (size_t)(nSubregionOffset + nSubregionSize - nCurOffset), fp);
195 0 : return nWritten / nSize;
196 : }
197 : else
198 0 : return VSIFWriteL( pBuffer, nSize, nCount, fp );
199 : }
200 :
201 : /************************************************************************/
202 : /* Eof() */
203 : /************************************************************************/
204 :
205 2 : int VSISubFileHandle::Eof()
206 :
207 : {
208 2 : if (nSubregionSize != 0)
209 2 : return VSIFTellL( fp ) >= nSubregionOffset + nSubregionSize;
210 : else
211 0 : return VSIFEofL( fp );
212 : }
213 :
214 : /************************************************************************/
215 : /* ==================================================================== */
216 : /* VSISubFileFilesystemHandler */
217 : /* ==================================================================== */
218 : /************************************************************************/
219 :
220 : /************************************************************************/
221 : /* VSISubFileFilesystemHandler() */
222 : /************************************************************************/
223 :
224 712 : VSISubFileFilesystemHandler::VSISubFileFilesystemHandler()
225 :
226 : {
227 712 : }
228 :
229 : /************************************************************************/
230 : /* ~VSISubFileFilesystemHandler() */
231 : /************************************************************************/
232 :
233 687 : VSISubFileFilesystemHandler::~VSISubFileFilesystemHandler()
234 :
235 : {
236 687 : }
237 :
238 : /************************************************************************/
239 : /* DecomposePath() */
240 : /* */
241 : /* Parse a path like /vsisubfile/1000_2000,data/abc.tif into an */
242 : /* offset (1000), a size (2000) and a path (data/abc.tif). */
243 : /************************************************************************/
244 :
245 : int
246 510 : VSISubFileFilesystemHandler::DecomposePath( const char *pszPath,
247 : CPLString &osFilename,
248 : vsi_l_offset &nSubFileOffset,
249 : vsi_l_offset &nSubFileSize )
250 :
251 : {
252 : int i;
253 :
254 510 : osFilename = "";
255 510 : nSubFileOffset = 0;
256 510 : nSubFileSize = 0;
257 :
258 510 : if( strncmp(pszPath,"/vsisubfile/",12) != 0 )
259 0 : return FALSE;
260 :
261 510 : nSubFileOffset = CPLScanUIntBig(pszPath+12, strlen(pszPath + 12));
262 4808 : for( i = 12; pszPath[i] != '\0'; i++ )
263 : {
264 5318 : if( pszPath[i] == '_' && nSubFileSize == 0 )
265 : {
266 : /* -1 is sometimes passed to mean that we don't know the file size */
267 : /* for example when creating a JPEG2000 datastream in a NITF file */
268 : /* Transform it into 0 for correct behaviour of Read(), Write() and Eof() */
269 510 : if (pszPath[i + 1] == '-')
270 66 : nSubFileSize = 0;
271 : else
272 444 : nSubFileSize = CPLScanUIntBig(pszPath + i + 1, strlen(pszPath + i + 1));
273 : }
274 4298 : else if( pszPath[i] == ',' )
275 : {
276 510 : osFilename = pszPath + i + 1;
277 510 : return TRUE;
278 : }
279 3788 : else if( pszPath[i] == '/' )
280 : {
281 : // missing comma!
282 0 : return FALSE;
283 : }
284 : }
285 :
286 0 : return FALSE;
287 : }
288 :
289 :
290 : /************************************************************************/
291 : /* Open() */
292 : /************************************************************************/
293 :
294 : VSIVirtualHandle *
295 163 : VSISubFileFilesystemHandler::Open( const char *pszFilename,
296 : const char *pszAccess )
297 :
298 : {
299 163 : CPLString osSubFilePath;
300 : vsi_l_offset nOff, nSize;
301 :
302 163 : if( !DecomposePath( pszFilename, osSubFilePath, nOff, nSize ) )
303 : {
304 0 : errno = ENOENT;
305 0 : return NULL;
306 : }
307 :
308 : /* -------------------------------------------------------------------- */
309 : /* We can't open the containing file with "w" access, so if tht */
310 : /* is requested use "r+" instead to update in place. */
311 : /* -------------------------------------------------------------------- */
312 163 : if( pszAccess[0] == 'w' )
313 4 : pszAccess = "r+";
314 :
315 : /* -------------------------------------------------------------------- */
316 : /* Open the underlying file. */
317 : /* -------------------------------------------------------------------- */
318 163 : VSILFILE *fp = VSIFOpenL( osSubFilePath, pszAccess );
319 :
320 163 : if( fp == NULL )
321 61 : return NULL;
322 :
323 : /* -------------------------------------------------------------------- */
324 : /* Setup the file handle on this file. */
325 : /* -------------------------------------------------------------------- */
326 102 : VSISubFileHandle *poHandle = new VSISubFileHandle;
327 :
328 102 : poHandle->fp = fp;
329 102 : poHandle->nSubregionOffset = nOff;
330 102 : poHandle->nSubregionSize = nSize;
331 :
332 102 : VSIFSeekL( fp, nOff, SEEK_SET );
333 :
334 102 : return poHandle;
335 : }
336 :
337 : /************************************************************************/
338 : /* Stat() */
339 : /************************************************************************/
340 :
341 347 : int VSISubFileFilesystemHandler::Stat( const char * pszFilename,
342 : VSIStatBufL * psStatBuf,
343 : int nFlags )
344 :
345 : {
346 347 : CPLString osSubFilePath;
347 : vsi_l_offset nOff, nSize;
348 :
349 347 : memset( psStatBuf, 0, sizeof(VSIStatBufL) );
350 :
351 347 : if( !DecomposePath( pszFilename, osSubFilePath, nOff, nSize ) )
352 : {
353 0 : errno = ENOENT;
354 0 : return -1;
355 : }
356 :
357 347 : int nResult = VSIStatExL( osSubFilePath, psStatBuf, nFlags );
358 :
359 347 : if( nResult == 0 )
360 : {
361 32 : if( nSize != 0 )
362 25 : psStatBuf->st_size = (long)nSize;
363 : else
364 7 : psStatBuf->st_size -= (long)nOff;
365 : }
366 :
367 347 : return nResult;
368 : }
369 :
370 : /************************************************************************/
371 : /* Unlink() */
372 : /************************************************************************/
373 :
374 0 : int VSISubFileFilesystemHandler::Unlink( const char * pszFilename )
375 :
376 : {
377 0 : errno = EACCES;
378 0 : return -1;
379 : }
380 :
381 : /************************************************************************/
382 : /* Mkdir() */
383 : /************************************************************************/
384 :
385 0 : int VSISubFileFilesystemHandler::Mkdir( const char * pszPathname,
386 : long nMode )
387 :
388 : {
389 0 : errno = EACCES;
390 0 : return -1;
391 : }
392 :
393 : /************************************************************************/
394 : /* Rmdir() */
395 : /************************************************************************/
396 :
397 0 : int VSISubFileFilesystemHandler::Rmdir( const char * pszPathname )
398 :
399 : {
400 0 : errno = EACCES;
401 0 : return -1;
402 : }
403 :
404 : /************************************************************************/
405 : /* ReadDir() */
406 : /************************************************************************/
407 :
408 29 : char **VSISubFileFilesystemHandler::ReadDir( const char *pszPath )
409 :
410 : {
411 29 : errno = EACCES;
412 29 : return NULL;
413 : }
414 :
415 : /************************************************************************/
416 : /* VSIInstallSubFileFilesystemHandler() */
417 : /************************************************************************/
418 :
419 : /**
420 : * Install /vsisubfile/ virtual file handler.
421 : *
422 : * This virtual file system handler allows access to subregions of
423 : * files, treating them as a file on their own to the virtual file
424 : * system functions (VSIFOpenL(), etc).
425 : *
426 : * A special form of the filename is used to indicate a subportion
427 : * of another file:
428 : *
429 : * /vsisubfile/<offset>[_<size>],<filename>
430 : *
431 : * The size parameter is optional. Without it the remainder of the
432 : * file from the start offset as treated as part of the subfile. Otherwise
433 : * only <size> bytes from <offset> are treated as part of the subfile.
434 : * The <filename> portion may be a relative or absolute path using normal
435 : * rules. The <offset> and <size> values are in bytes.
436 : *
437 : * eg.
438 : * /vsisubfile/1000_3000,/data/abc.ntf
439 : * /vsisubfile/5000,../xyz/raw.dat
440 : *
441 : * Unlike the /vsimem/ or conventional file system handlers, there
442 : * is no meaningful support for filesystem operations for creating new
443 : * files, traversing directories, and deleting files within the /vsisubfile/
444 : * area. Only the VSIStatL(), VSIFOpenL() and operations based on the file
445 : * handle returned by VSIFOpenL() operate properly.
446 : */
447 :
448 712 : void VSIInstallSubFileHandler()
449 : {
450 : VSIFileManager::InstallHandler( "/vsisubfile/",
451 712 : new VSISubFileFilesystemHandler );
452 712 : }
453 :
|