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 392 : {
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 196 : int VSISubFileHandle::Close()
99 :
100 : {
101 196 : VSIFCloseL( fp );
102 196 : fp = NULL;
103 :
104 196 : return 0;
105 : }
106 :
107 : /************************************************************************/
108 : /* Seek() */
109 : /************************************************************************/
110 :
111 2112 : int VSISubFileHandle::Seek( vsi_l_offset nOffset, int nWhence )
112 :
113 : {
114 2112 : if( nWhence == SEEK_SET )
115 2004 : nOffset += nSubregionOffset;
116 108 : else if( nWhence == SEEK_CUR )
117 : {
118 : // handle normally.
119 : }
120 108 : else if( nWhence == SEEK_END )
121 : {
122 108 : if( nSubregionSize != 0 )
123 : {
124 96 : nOffset = nSubregionOffset + nSubregionSize;
125 96 : nWhence = SEEK_SET;
126 : }
127 : }
128 : else
129 : {
130 0 : errno = EINVAL;
131 0 : return -1;
132 : }
133 :
134 2112 : return VSIFSeekL( fp, nOffset, nWhence );
135 : }
136 :
137 : /************************************************************************/
138 : /* Tell() */
139 : /************************************************************************/
140 :
141 6440 : vsi_l_offset VSISubFileHandle::Tell()
142 :
143 : {
144 6440 : return VSIFTellL( fp ) - nSubregionOffset;
145 : }
146 :
147 : /************************************************************************/
148 : /* Read() */
149 : /************************************************************************/
150 :
151 15756 : size_t VSISubFileHandle::Read( void * pBuffer, size_t nSize, size_t nCount )
152 :
153 : {
154 15756 : if (nSubregionSize == 0)
155 422 : return VSIFReadL( pBuffer, nSize, nCount, fp );
156 :
157 15334 : if (nSize == 0)
158 0 : return 0;
159 :
160 15334 : vsi_l_offset nCurOffset = VSIFTellL(fp);
161 15334 : if (nCurOffset >= nSubregionOffset + nSubregionSize)
162 14 : return 0;
163 :
164 15320 : size_t nByteToRead = nSize * nCount;
165 15320 : if (nCurOffset + nByteToRead > nSubregionOffset + nSubregionSize)
166 : {
167 46 : int nRead = (int)VSIFReadL( pBuffer, 1, (size_t)(nSubregionOffset + nSubregionSize - nCurOffset), fp);
168 46 : return nRead / nSize;
169 : }
170 : else
171 15274 : return VSIFReadL( pBuffer, nSize, nCount, fp );
172 : }
173 :
174 : /************************************************************************/
175 : /* Write() */
176 : /************************************************************************/
177 :
178 3170 : size_t VSISubFileHandle::Write( const void * pBuffer, size_t nSize, size_t nCount )
179 :
180 : {
181 3170 : if (nSubregionSize == 0)
182 3170 : 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 4 : int VSISubFileHandle::Eof()
206 :
207 : {
208 4 : if (nSubregionSize != 0)
209 4 : 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 1341 : VSISubFileFilesystemHandler::VSISubFileFilesystemHandler()
225 :
226 : {
227 1341 : }
228 :
229 : /************************************************************************/
230 : /* ~VSISubFileFilesystemHandler() */
231 : /************************************************************************/
232 :
233 1297 : VSISubFileFilesystemHandler::~VSISubFileFilesystemHandler()
234 :
235 : {
236 1297 : }
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 760 : 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 760 : osFilename = "";
255 760 : nSubFileOffset = 0;
256 760 : nSubFileSize = 0;
257 :
258 760 : if( strncmp(pszPath,"/vsisubfile/",12) != 0 )
259 0 : return FALSE;
260 :
261 760 : nSubFileOffset = CPLScanUIntBig(pszPath+12, strlen(pszPath + 12));
262 7212 : for( i = 12; pszPath[i] != '\0'; i++ )
263 : {
264 7972 : 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 760 : if (pszPath[i + 1] == '-')
270 96 : nSubFileSize = 0;
271 : else
272 664 : nSubFileSize = CPLScanUIntBig(pszPath + i + 1, strlen(pszPath + i + 1));
273 : }
274 6452 : else if( pszPath[i] == ',' )
275 : {
276 760 : osFilename = pszPath + i + 1;
277 760 : return TRUE;
278 : }
279 5692 : 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 318 : VSISubFileFilesystemHandler::Open( const char *pszFilename,
296 : const char *pszAccess )
297 :
298 : {
299 318 : CPLString osSubFilePath;
300 : vsi_l_offset nOff, nSize;
301 :
302 318 : 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 318 : if( pszAccess[0] == 'w' )
313 8 : pszAccess = "r+";
314 :
315 : /* -------------------------------------------------------------------- */
316 : /* Open the underlying file. */
317 : /* -------------------------------------------------------------------- */
318 318 : VSILFILE *fp = VSIFOpenL( osSubFilePath, pszAccess );
319 :
320 318 : if( fp == NULL )
321 122 : return NULL;
322 :
323 : /* -------------------------------------------------------------------- */
324 : /* Setup the file handle on this file. */
325 : /* -------------------------------------------------------------------- */
326 196 : VSISubFileHandle *poHandle = new VSISubFileHandle;
327 :
328 196 : poHandle->fp = fp;
329 196 : poHandle->nSubregionOffset = nOff;
330 196 : poHandle->nSubregionSize = nSize;
331 :
332 196 : VSIFSeekL( fp, nOff, SEEK_SET );
333 :
334 196 : return poHandle;
335 : }
336 :
337 : /************************************************************************/
338 : /* Stat() */
339 : /************************************************************************/
340 :
341 442 : int VSISubFileFilesystemHandler::Stat( const char * pszFilename,
342 : VSIStatBufL * psStatBuf,
343 : int nFlags )
344 :
345 : {
346 442 : CPLString osSubFilePath;
347 : vsi_l_offset nOff, nSize;
348 :
349 442 : memset( psStatBuf, 0, sizeof(VSIStatBufL) );
350 :
351 442 : if( !DecomposePath( pszFilename, osSubFilePath, nOff, nSize ) )
352 : {
353 0 : errno = ENOENT;
354 0 : return -1;
355 : }
356 :
357 442 : int nResult = VSIStatExL( osSubFilePath, psStatBuf, nFlags );
358 :
359 442 : if( nResult == 0 )
360 : {
361 64 : if( nSize != 0 )
362 50 : psStatBuf->st_size = (long)nSize;
363 : else
364 14 : psStatBuf->st_size -= (long)nOff;
365 : }
366 :
367 442 : 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 58 : char **VSISubFileFilesystemHandler::ReadDir( const char *pszPath )
409 :
410 : {
411 58 : errno = EACCES;
412 58 : 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 1341 : void VSIInstallSubFileHandler()
449 : {
450 : VSIFileManager::InstallHandler( "/vsisubfile/",
451 1341 : new VSISubFileFilesystemHandler );
452 1341 : }
453 :
|