1 : /**********************************************************************
2 : * $Id: cpl_vsil_stdin.cpp 20025 2010-07-11 17:13:02Z rouault $
3 : *
4 : * Project: CPL - Common Portability Library
5 : * Purpose: Implement VSI large file api for stdin
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : **********************************************************************
9 : * Copyright (c) 2010, Even Rouault
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 OR
22 : * 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_port.h"
31 : #include "cpl_error.h"
32 : #include "cpl_vsi_virtual.h"
33 : #include "cpl_multiproc.h"
34 :
35 : #include <stdio.h>
36 : #ifdef WIN32
37 : #include <io.h>
38 : #include <fcntl.h>
39 : #endif
40 :
41 : CPL_CVSID("$Id: cpl_vsil_stdin.cpp 20025 2010-07-11 17:13:02Z rouault $");
42 :
43 : /* We buffer the first 1MB of standard input to enable drivers */
44 : /* to autodetect data. In the first MB, backward and forward seeking */
45 : /* is allowed, after only forward seeking will work */
46 : #define BUFFER_SIZE (1024 * 1024)
47 :
48 : static void* hStdinMutex;
49 : static GByte* pabyBuffer;
50 : static GUInt32 nBufferLen;
51 : static GUIntBig nRealPos;
52 :
53 : /************************************************************************/
54 : /* VSIStdinInit() */
55 : /************************************************************************/
56 :
57 0 : static void VSIStdinInit()
58 : {
59 0 : if (pabyBuffer == NULL)
60 : {
61 0 : CPLMutexHolder oHolder(&hStdinMutex);
62 0 : if (pabyBuffer == NULL)
63 : {
64 : #ifdef WIN32
65 : setmode( fileno( stdin ), O_BINARY );
66 : #endif
67 0 : pabyBuffer = (GByte*)CPLMalloc(BUFFER_SIZE);
68 0 : nRealPos = nBufferLen = fread(pabyBuffer, 1, BUFFER_SIZE, stdin);
69 0 : }
70 : }
71 0 : }
72 :
73 : /************************************************************************/
74 : /* ==================================================================== */
75 : /* VSIStdinFilesystemHandler */
76 : /* ==================================================================== */
77 : /************************************************************************/
78 :
79 : class VSIStdinFilesystemHandler : public VSIFilesystemHandler
80 : {
81 : public:
82 : VSIStdinFilesystemHandler();
83 : virtual ~VSIStdinFilesystemHandler();
84 :
85 : virtual VSIVirtualHandle *Open( const char *pszFilename,
86 : const char *pszAccess);
87 : virtual int Stat( const char *pszFilename,
88 : VSIStatBufL *pStatBuf );
89 : };
90 :
91 : /************************************************************************/
92 : /* ==================================================================== */
93 : /* VSIStdinHandle */
94 : /* ==================================================================== */
95 : /************************************************************************/
96 :
97 : class VSIStdinHandle : public VSIVirtualHandle
98 : {
99 : private:
100 : GUIntBig nCurOff;
101 :
102 : public:
103 : VSIStdinHandle();
104 : virtual ~VSIStdinHandle();
105 :
106 : virtual int Seek( vsi_l_offset nOffset, int nWhence );
107 : virtual vsi_l_offset Tell();
108 : virtual size_t Read( void *pBuffer, size_t nSize, size_t nMemb );
109 : virtual size_t Write( const void *pBuffer, size_t nSize, size_t nMemb );
110 : virtual int Eof();
111 : virtual int Close();
112 : };
113 :
114 : /************************************************************************/
115 : /* VSIStdinHandle() */
116 : /************************************************************************/
117 :
118 0 : VSIStdinHandle::VSIStdinHandle()
119 : {
120 0 : nCurOff = 0;
121 0 : }
122 :
123 : /************************************************************************/
124 : /* ~VSIStdinHandle() */
125 : /************************************************************************/
126 :
127 0 : VSIStdinHandle::~VSIStdinHandle()
128 : {
129 0 : }
130 :
131 : /************************************************************************/
132 : /* Seek() */
133 : /************************************************************************/
134 :
135 0 : int VSIStdinHandle::Seek( vsi_l_offset nOffset, int nWhence )
136 :
137 : {
138 0 : VSIStdinInit();
139 :
140 0 : if (nWhence == SEEK_END)
141 : {
142 0 : if (nOffset != 0)
143 : {
144 : CPLError(CE_Failure, CPLE_NotSupported,
145 0 : "Seek(xx != 0, SEEK_END) unsupported on /vsistdin");
146 0 : return -1;
147 : }
148 :
149 0 : if (nBufferLen < BUFFER_SIZE)
150 : {
151 0 : nCurOff = nBufferLen;
152 0 : return 0;
153 : }
154 :
155 : CPLError(CE_Failure, CPLE_NotSupported,
156 0 : "Seek(SEEK_END) unsupported on /vsistdin when stdin > 1 MB");
157 0 : return -1;
158 : }
159 :
160 0 : if (nWhence == SEEK_CUR)
161 0 : nOffset += nCurOff;
162 :
163 0 : if (nRealPos > nBufferLen && nOffset < nRealPos)
164 : {
165 : CPLError(CE_Failure, CPLE_NotSupported,
166 0 : "backward Seek() unsupported on /vsistdin above first MB");
167 0 : return -1;
168 : }
169 :
170 0 : if (nOffset < nBufferLen)
171 : {
172 0 : nCurOff = nOffset;
173 0 : return 0;
174 : }
175 :
176 0 : if (nOffset == nCurOff)
177 0 : return 0;
178 :
179 : CPLDebug("VSI", "Forward seek from " CPL_FRMT_GUIB " to " CPL_FRMT_GUIB,
180 0 : nCurOff, nOffset);
181 :
182 : char abyTemp[8192];
183 0 : nCurOff = nRealPos;
184 0 : while(TRUE)
185 : {
186 0 : int nToRead = MIN(8192, nOffset - nCurOff);
187 0 : int nRead = fread(abyTemp, 1, nToRead, stdin);
188 0 : if (nRead < nToRead)
189 0 : return -1;
190 0 : nCurOff += nRead;
191 0 : nRealPos = nCurOff;
192 0 : if (nToRead < 8192)
193 0 : break;
194 : }
195 :
196 0 : return 0;
197 : }
198 :
199 : /************************************************************************/
200 : /* Tell() */
201 : /************************************************************************/
202 :
203 0 : vsi_l_offset VSIStdinHandle::Tell()
204 : {
205 0 : return nCurOff;
206 : }
207 :
208 : /************************************************************************/
209 : /* Read() */
210 : /************************************************************************/
211 :
212 0 : size_t VSIStdinHandle::Read( void * pBuffer, size_t nSize, size_t nCount )
213 :
214 : {
215 0 : VSIStdinInit();
216 :
217 0 : if (nCurOff < nBufferLen)
218 : {
219 0 : if (nCurOff + nSize * nCount < nBufferLen)
220 : {
221 0 : memcpy(pBuffer, pabyBuffer + nCurOff, nSize * nCount);
222 0 : nCurOff += nSize * nCount;
223 0 : return nCount;
224 : }
225 :
226 0 : memcpy(pBuffer, pabyBuffer + nCurOff, nBufferLen - nCurOff);
227 :
228 : int nRead = fread((GByte*)pBuffer + nBufferLen - nCurOff, 1,
229 0 : nSize * nCount - (nBufferLen - nCurOff), stdin);
230 :
231 0 : int nRet = (nRead + nBufferLen - nCurOff) / nSize;
232 :
233 0 : nRealPos = nCurOff = nBufferLen + nRead;
234 :
235 0 : return nRet;
236 : }
237 :
238 0 : int nRet = fread(pBuffer, nSize, nCount, stdin);
239 0 : if (nRet < 0)
240 0 : return nRet;
241 :
242 0 : nCurOff += nRet * nSize;
243 0 : nRealPos = nCurOff;
244 :
245 0 : return nRet;
246 : }
247 :
248 : /************************************************************************/
249 : /* Write() */
250 : /************************************************************************/
251 :
252 : size_t VSIStdinHandle::Write( const void * pBuffer, size_t nSize,
253 0 : size_t nCount )
254 :
255 : {
256 : CPLError(CE_Failure, CPLE_NotSupported,
257 0 : "Write() unsupported on /vsistdin");
258 0 : return 0;
259 : }
260 :
261 : /************************************************************************/
262 : /* Eof() */
263 : /************************************************************************/
264 :
265 0 : int VSIStdinHandle::Eof()
266 :
267 : {
268 0 : if (nCurOff < nBufferLen)
269 0 : return FALSE;
270 0 : return feof(stdin);
271 : }
272 :
273 : /************************************************************************/
274 : /* Close() */
275 : /************************************************************************/
276 :
277 0 : int VSIStdinHandle::Close()
278 :
279 : {
280 0 : return 0;
281 : }
282 :
283 : /************************************************************************/
284 : /* ==================================================================== */
285 : /* VSIStdinFilesystemHandler */
286 : /* ==================================================================== */
287 : /************************************************************************/
288 :
289 : /************************************************************************/
290 : /* VSIStdinFilesystemHandler() */
291 : /************************************************************************/
292 :
293 447 : VSIStdinFilesystemHandler::VSIStdinFilesystemHandler()
294 : {
295 447 : hStdinMutex = NULL;
296 447 : pabyBuffer = NULL;
297 447 : nBufferLen = 0;
298 447 : nRealPos = 0;
299 447 : }
300 :
301 : /************************************************************************/
302 : /* ~VSIStdinFilesystemHandler() */
303 : /************************************************************************/
304 :
305 432 : VSIStdinFilesystemHandler::~VSIStdinFilesystemHandler()
306 : {
307 432 : if( hStdinMutex != NULL )
308 0 : CPLDestroyMutex( hStdinMutex );
309 432 : hStdinMutex = NULL;
310 :
311 432 : CPLFree(pabyBuffer);
312 432 : pabyBuffer = NULL;
313 432 : }
314 :
315 : /************************************************************************/
316 : /* Open() */
317 : /************************************************************************/
318 :
319 : VSIVirtualHandle *
320 : VSIStdinFilesystemHandler::Open( const char *pszFilename,
321 0 : const char *pszAccess )
322 :
323 : {
324 0 : if (strcmp(pszFilename, "/vsistdin/") != 0)
325 0 : return NULL;
326 :
327 0 : if ( strchr(pszAccess, 'w') != NULL ||
328 : strchr(pszAccess, '+') != NULL )
329 : {
330 : CPLError(CE_Failure, CPLE_NotSupported,
331 0 : "Write or update mode not supported on /vsistdin");
332 0 : return NULL;
333 : }
334 :
335 0 : return new VSIStdinHandle;
336 : }
337 :
338 : /************************************************************************/
339 : /* Stat() */
340 : /************************************************************************/
341 :
342 : int VSIStdinFilesystemHandler::Stat( const char * pszFilename,
343 0 : VSIStatBufL * pStatBuf )
344 :
345 : {
346 0 : memset( pStatBuf, 0, sizeof(VSIStatBufL) );
347 :
348 0 : if (strcmp(pszFilename, "/vsistdin/") != 0)
349 0 : return -1;
350 :
351 0 : VSIStdinInit();
352 :
353 0 : pStatBuf->st_size = nBufferLen;
354 0 : pStatBuf->st_mode = S_IFREG;
355 0 : return 0;
356 : }
357 :
358 : /************************************************************************/
359 : /* VSIInstallStdinHandler() */
360 : /************************************************************************/
361 :
362 447 : void VSIInstallStdinHandler()
363 :
364 : {
365 447 : VSIFileManager::InstallHandler( "/vsistdin/", new VSIStdinFilesystemHandler );
366 447 : }
|