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