1
/**********************************************************************
2
* $Id: cpl_vsil_stdin.cpp 21689 2011-02-12 12:18:14Z rouault $
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>
8
**********************************************************************
9
* Copyright (c) 2010, Even Rouault
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:
18
* The above copyright notice and this permission notice shall be included
19
* in all copies or substantial portions of the Software.
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
****************************************************************************/
31
#include "cpl_error.h"
32
#include "cpl_vsi_virtual.h"
33
#include "cpl_multiproc.h"
41
CPL_CVSID("$Id: cpl_vsil_stdin.cpp 21689 2011-02-12 12:18:14Z rouault $");
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)
48
static void* hStdinMutex;
49
static GByte* pabyBuffer;
50
static GUInt32 nBufferLen;
51
static GUIntBig nRealPos;
53
/************************************************************************/
55
/************************************************************************/
57
static void VSIStdinInit()
59
if (pabyBuffer == NULL)
61
CPLMutexHolder oHolder(&hStdinMutex);
62
if (pabyBuffer == NULL)
65
setmode( fileno( stdin ), O_BINARY );
67
pabyBuffer = (GByte*)CPLMalloc(BUFFER_SIZE);
68
nRealPos = nBufferLen = fread(pabyBuffer, 1, BUFFER_SIZE, stdin);
73
/************************************************************************/
74
/* ==================================================================== */
75
/* VSIStdinFilesystemHandler */
76
/* ==================================================================== */
77
/************************************************************************/
79
class VSIStdinFilesystemHandler : public VSIFilesystemHandler
82
VSIStdinFilesystemHandler();
83
virtual ~VSIStdinFilesystemHandler();
85
virtual VSIVirtualHandle *Open( const char *pszFilename,
86
const char *pszAccess);
87
virtual int Stat( const char *pszFilename,
88
VSIStatBufL *pStatBuf, int nFlags );
91
/************************************************************************/
92
/* ==================================================================== */
94
/* ==================================================================== */
95
/************************************************************************/
97
class VSIStdinHandle : public VSIVirtualHandle
104
virtual ~VSIStdinHandle();
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 );
114
/************************************************************************/
115
/* VSIStdinHandle() */
116
/************************************************************************/
118
VSIStdinHandle::VSIStdinHandle()
123
/************************************************************************/
124
/* ~VSIStdinHandle() */
125
/************************************************************************/
127
VSIStdinHandle::~VSIStdinHandle()
131
/************************************************************************/
133
/************************************************************************/
135
int VSIStdinHandle::Seek( vsi_l_offset nOffset, int nWhence )
140
if (nWhence == SEEK_END)
144
CPLError(CE_Failure, CPLE_NotSupported,
145
"Seek(xx != 0, SEEK_END) unsupported on /vsistdin");
149
if (nBufferLen < BUFFER_SIZE)
151
nCurOff = nBufferLen;
155
CPLError(CE_Failure, CPLE_NotSupported,
156
"Seek(SEEK_END) unsupported on /vsistdin when stdin > 1 MB");
160
if (nWhence == SEEK_CUR)
163
if (nRealPos > nBufferLen && nOffset < nRealPos)
165
CPLError(CE_Failure, CPLE_NotSupported,
166
"backward Seek() unsupported on /vsistdin above first MB");
170
if (nOffset < nBufferLen)
176
if (nOffset == nCurOff)
179
CPLDebug("VSI", "Forward seek from " CPL_FRMT_GUIB " to " CPL_FRMT_GUIB,
186
int nToRead = (int) MIN(8192, nOffset - nCurOff);
187
int nRead = fread(abyTemp, 1, nToRead, stdin);
199
/************************************************************************/
201
/************************************************************************/
203
vsi_l_offset VSIStdinHandle::Tell()
208
/************************************************************************/
210
/************************************************************************/
212
size_t VSIStdinHandle::Read( void * pBuffer, size_t nSize, size_t nCount )
217
if (nCurOff < nBufferLen)
219
if (nCurOff + nSize * nCount < nBufferLen)
221
memcpy(pBuffer, pabyBuffer + nCurOff, nSize * nCount);
222
nCurOff += nSize * nCount;
226
memcpy(pBuffer, pabyBuffer + nCurOff, (size_t)(nBufferLen - nCurOff));
228
int nRead = fread((GByte*)pBuffer + nBufferLen - nCurOff, 1,
229
(size_t)(nSize*nCount - (nBufferLen-nCurOff)), stdin);
231
int nRet = (int) ((nRead + nBufferLen - nCurOff) / nSize);
233
nRealPos = nCurOff = nBufferLen + nRead;
238
int nRet = fread(pBuffer, nSize, nCount, stdin);
242
nCurOff += nRet * nSize;
248
/************************************************************************/
250
/************************************************************************/
252
size_t VSIStdinHandle::Write( const void * pBuffer, size_t nSize,
256
CPLError(CE_Failure, CPLE_NotSupported,
257
"Write() unsupported on /vsistdin");
261
/************************************************************************/
263
/************************************************************************/
265
int VSIStdinHandle::Eof()
268
if (nCurOff < nBufferLen)
273
/************************************************************************/
275
/************************************************************************/
277
int VSIStdinHandle::Close()
283
/************************************************************************/
284
/* ==================================================================== */
285
/* VSIStdinFilesystemHandler */
286
/* ==================================================================== */
287
/************************************************************************/
289
/************************************************************************/
290
/* VSIStdinFilesystemHandler() */
291
/************************************************************************/
293
VSIStdinFilesystemHandler::VSIStdinFilesystemHandler()
301
/************************************************************************/
302
/* ~VSIStdinFilesystemHandler() */
303
/************************************************************************/
305
VSIStdinFilesystemHandler::~VSIStdinFilesystemHandler()
307
if( hStdinMutex != NULL )
308
CPLDestroyMutex( hStdinMutex );
315
/************************************************************************/
317
/************************************************************************/
320
VSIStdinFilesystemHandler::Open( const char *pszFilename,
321
const char *pszAccess )
324
if (strcmp(pszFilename, "/vsistdin/") != 0)
327
if ( strchr(pszAccess, 'w') != NULL ||
328
strchr(pszAccess, '+') != NULL )
330
CPLError(CE_Failure, CPLE_NotSupported,
331
"Write or update mode not supported on /vsistdin");
335
return new VSIStdinHandle;
338
/************************************************************************/
340
/************************************************************************/
342
int VSIStdinFilesystemHandler::Stat( const char * pszFilename,
343
VSIStatBufL * pStatBuf,
347
memset( pStatBuf, 0, sizeof(VSIStatBufL) );
349
if (strcmp(pszFilename, "/vsistdin/") != 0)
354
pStatBuf->st_size = nBufferLen;
355
pStatBuf->st_mode = S_IFREG;
359
/************************************************************************/
360
/* VSIInstallStdinHandler() */
361
/************************************************************************/
364
* \brief Install /vsistdin/ file system handler
366
* A special file handler is installed that allows reading from the standard
369
* The file operations available are of course limited to Read() and
370
* forward Seek() (full seek in the first MB of a file).
374
void VSIInstallStdinHandler()
377
VSIFileManager::InstallHandler( "/vsistdin/", new VSIStdinFilesystemHandler );