1 : /******************************************************************************
2 : * $Id: cpl_vsil_subfile.cpp 18063 2009-11-21 21:11:49Z 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 18063 2009-11-21 21:11:49Z warmerdam $");
40 :
41 : /************************************************************************/
42 : /* ==================================================================== */
43 : /* VSISubFileHandle */
44 : /* ==================================================================== */
45 : /************************************************************************/
46 :
47 : class VSISubFileHandle : public VSIVirtualHandle
48 207 : {
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 69 : int VSISubFileHandle::Close()
100 :
101 : {
102 69 : VSIFCloseL( fp );
103 69 : fp = NULL;
104 :
105 69 : return 0;
106 : }
107 :
108 : /************************************************************************/
109 : /* Seek() */
110 : /************************************************************************/
111 :
112 1073 : int VSISubFileHandle::Seek( vsi_l_offset nOffset, int nWhence )
113 :
114 : {
115 1073 : if( nWhence == SEEK_SET )
116 1027 : nOffset += nSubregionOffset;
117 46 : else if( nWhence == SEEK_CUR )
118 : {
119 : // handle normally.
120 : }
121 46 : else if( nWhence == SEEK_END )
122 : {
123 46 : if( nSubregionSize != 0 )
124 : {
125 46 : nOffset = nSubregionOffset + nSubregionSize;
126 46 : nWhence = SEEK_SET;
127 : }
128 : }
129 : else
130 : {
131 0 : errno = EINVAL;
132 0 : return -1;
133 : }
134 :
135 1073 : return VSIFSeekL( fp, nOffset, nWhence );
136 : }
137 :
138 : /************************************************************************/
139 : /* Tell() */
140 : /************************************************************************/
141 :
142 3645 : vsi_l_offset VSISubFileHandle::Tell()
143 :
144 : {
145 3645 : return VSIFTellL( fp ) - nSubregionOffset;
146 : }
147 :
148 : /************************************************************************/
149 : /* Read() */
150 : /************************************************************************/
151 :
152 8078 : size_t VSISubFileHandle::Read( void * pBuffer, size_t nSize, size_t nCount )
153 :
154 : {
155 8078 : return VSIFReadL( pBuffer, nSize, nCount, fp );
156 : }
157 :
158 : /************************************************************************/
159 : /* Write() */
160 : /************************************************************************/
161 :
162 2 : size_t VSISubFileHandle::Write( const void * pBuffer, size_t nSize, size_t nCount )
163 :
164 : {
165 2 : return VSIFWriteL( pBuffer, nSize, nCount, fp );
166 : }
167 :
168 : /************************************************************************/
169 : /* Eof() */
170 : /************************************************************************/
171 :
172 0 : int VSISubFileHandle::Eof()
173 :
174 : {
175 0 : return VSIFEofL( fp );
176 : }
177 :
178 : /************************************************************************/
179 : /* ==================================================================== */
180 : /* VSISubFileFilesystemHandler */
181 : /* ==================================================================== */
182 : /************************************************************************/
183 :
184 : /************************************************************************/
185 : /* VSISubFileFilesystemHandler() */
186 : /************************************************************************/
187 :
188 379 : VSISubFileFilesystemHandler::VSISubFileFilesystemHandler()
189 :
190 : {
191 379 : }
192 :
193 : /************************************************************************/
194 : /* ~VSISubFileFilesystemHandler() */
195 : /************************************************************************/
196 :
197 726 : VSISubFileFilesystemHandler::~VSISubFileFilesystemHandler()
198 :
199 : {
200 726 : }
201 :
202 : /************************************************************************/
203 : /* DecomposePath() */
204 : /* */
205 : /* Parse a path like /vsisubfile/1000_2000,data/abc.tif into an */
206 : /* offset (1000), a size (2000) and a path (data/abc.tif). */
207 : /************************************************************************/
208 :
209 : int
210 562 : VSISubFileFilesystemHandler::DecomposePath( const char *pszPath,
211 : CPLString &osFilename,
212 : vsi_l_offset &nSubFileOffset,
213 : vsi_l_offset &nSubFileSize )
214 :
215 : {
216 : int i;
217 :
218 562 : osFilename = "";
219 562 : nSubFileOffset = 0;
220 562 : nSubFileSize = 0;
221 :
222 562 : if( strncmp(pszPath,"/vsisubfile/",12) != 0 )
223 0 : return FALSE;
224 :
225 562 : nSubFileOffset = CPLScanUIntBig(pszPath+12, strlen(pszPath + 12));
226 5504 : for( i = 12; pszPath[i] != '\0'; i++ )
227 : {
228 6066 : if( pszPath[i] == '_' && nSubFileSize == 0 )
229 562 : nSubFileSize = CPLScanUIntBig(pszPath + i + 1, strlen(pszPath + i + 1));
230 4942 : else if( pszPath[i] == ',' )
231 : {
232 562 : osFilename = pszPath + i + 1;
233 562 : return TRUE;
234 : }
235 4380 : else if( pszPath[i] == '/' )
236 : {
237 : // missing comma!
238 0 : return FALSE;
239 : }
240 : }
241 :
242 0 : return FALSE;
243 : }
244 :
245 :
246 : /************************************************************************/
247 : /* Open() */
248 : /************************************************************************/
249 :
250 : VSIVirtualHandle *
251 273 : VSISubFileFilesystemHandler::Open( const char *pszFilename,
252 : const char *pszAccess )
253 :
254 : {
255 273 : CPLString osSubFilePath;
256 : vsi_l_offset nOff, nSize;
257 :
258 273 : if( !DecomposePath( pszFilename, osSubFilePath, nOff, nSize ) )
259 : {
260 0 : errno = ENOENT;
261 0 : return NULL;
262 : }
263 :
264 : /* -------------------------------------------------------------------- */
265 : /* Open the underlying file. */
266 : /* -------------------------------------------------------------------- */
267 273 : FILE *fp = VSIFOpenL( osSubFilePath, pszAccess );
268 :
269 273 : if( fp == NULL )
270 204 : return NULL;
271 :
272 : /* -------------------------------------------------------------------- */
273 : /* Setup the file handle on this file. */
274 : /* -------------------------------------------------------------------- */
275 69 : VSISubFileHandle *poHandle = new VSISubFileHandle;
276 :
277 69 : poHandle->fp = fp;
278 69 : poHandle->nSubregionOffset = nOff;
279 69 : poHandle->nSubregionSize = nSize;
280 :
281 69 : VSIFSeekL( fp, nOff, SEEK_SET );
282 :
283 69 : return poHandle;
284 : }
285 :
286 : /************************************************************************/
287 : /* Stat() */
288 : /************************************************************************/
289 :
290 289 : int VSISubFileFilesystemHandler::Stat( const char * pszFilename,
291 : VSIStatBufL * psStatBuf )
292 :
293 : {
294 289 : CPLString osSubFilePath;
295 : vsi_l_offset nOff, nSize;
296 :
297 289 : if( !DecomposePath( pszFilename, osSubFilePath, nOff, nSize ) )
298 : {
299 0 : errno = ENOENT;
300 0 : return -1;
301 : }
302 :
303 289 : int nResult = VSIStatL( osSubFilePath, psStatBuf );
304 :
305 289 : if( nResult == 0 )
306 : {
307 36 : if( nSize != 0 )
308 36 : psStatBuf->st_size = (long)nSize;
309 : else
310 0 : psStatBuf->st_size -= (long)nOff;
311 : }
312 :
313 289 : return nResult;
314 : }
315 :
316 : /************************************************************************/
317 : /* Unlink() */
318 : /************************************************************************/
319 :
320 0 : int VSISubFileFilesystemHandler::Unlink( const char * pszFilename )
321 :
322 : {
323 0 : errno = EACCES;
324 0 : return -1;
325 : }
326 :
327 : /************************************************************************/
328 : /* Mkdir() */
329 : /************************************************************************/
330 :
331 0 : int VSISubFileFilesystemHandler::Mkdir( const char * pszPathname,
332 : long nMode )
333 :
334 : {
335 0 : errno = EACCES;
336 0 : return -1;
337 : }
338 :
339 : /************************************************************************/
340 : /* Rmdir() */
341 : /************************************************************************/
342 :
343 0 : int VSISubFileFilesystemHandler::Rmdir( const char * pszPathname )
344 :
345 : {
346 0 : errno = EACCES;
347 0 : return -1;
348 : }
349 :
350 : /************************************************************************/
351 : /* ReadDir() */
352 : /************************************************************************/
353 :
354 23 : char **VSISubFileFilesystemHandler::ReadDir( const char *pszPath )
355 :
356 : {
357 23 : errno = EACCES;
358 23 : return NULL;
359 : }
360 :
361 : /************************************************************************/
362 : /* VSIInstallSubFileFilesystemHandler() */
363 : /************************************************************************/
364 :
365 : /**
366 : * Install /vsisubfile/ virtual file handler.
367 : *
368 : * This virtual file system handler allows access to subregions of
369 : * files, treating them as a file on their own to the virtual file
370 : * system functions (VSIFOpenL(), etc).
371 : *
372 : * A special form of the filename is used to indicate a subportion
373 : * of another file:
374 : *
375 : * /vsisubfile/<offset>[_<size>],<filename>
376 : *
377 : * The size parameter is optional. Without it the remainder of the
378 : * file from the start offset as treated as part of the subfile. Otherwise
379 : * only <size> bytes from <offset> are treated as part of the subfile.
380 : * The <filename> portion may be a relative or absolute path using normal
381 : * rules. The <offset> and <size> values are in bytes.
382 : *
383 : * eg.
384 : * /vsisubfile/1000_3000,/data/abc.ntf
385 : * /vsisubfile/5000,../xyz/raw.dat
386 : *
387 : * Unlike the /vsimem/ or conventional file system handlers, there
388 : * is no meaningful support for filesystem operations for creating new
389 : * files, traversing directories, and deleting files within the /vsisubfile/
390 : * area. Only the VSIStatL(), VSIFOpenL() and operations based on the file
391 : * handle returned by VSIFOpenL() operate properly.
392 : */
393 :
394 379 : void VSIInstallSubFileHandler()
395 : {
396 : VSIFileManager::InstallHandler( "/vsisubfile/",
397 379 : new VSISubFileFilesystemHandler );
398 379 : }
399 :
|