mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-13 14:22:33 -06:00
394 lines
13 KiB
C++
394 lines
13 KiB
C++
/**********************************************************************
|
|
* $Id: cpl_vsil_stdin.cpp 27745 2014-09-27 16:38:57Z goatbar $
|
|
*
|
|
* Project: CPL - Common Portability Library
|
|
* Purpose: Implement VSI large file api for stdin
|
|
* Author: Even Rouault, <even dot rouault at mines dash paris dot org>
|
|
*
|
|
**********************************************************************
|
|
* Copyright (c) 2010-2012, Even Rouault <even dot rouault at mines-paris dot org>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#include "cpl_port.h"
|
|
#include "cpl_error.h"
|
|
#include "cpl_vsi_virtual.h"
|
|
|
|
#include <stdio.h>
|
|
#ifdef WIN32
|
|
#include <io.h>
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
CPL_CVSID("$Id: cpl_vsil_stdin.cpp 27745 2014-09-27 16:38:57Z goatbar $");
|
|
|
|
/* We buffer the first 1MB of standard input to enable drivers */
|
|
/* to autodetect data. In the first MB, backward and forward seeking */
|
|
/* is allowed, after only forward seeking will work */
|
|
#define BUFFER_SIZE (1024 * 1024)
|
|
|
|
static GByte* pabyBuffer;
|
|
static GUInt32 nBufferLen;
|
|
static GUIntBig nRealPos;
|
|
|
|
/************************************************************************/
|
|
/* VSIStdinInit() */
|
|
/************************************************************************/
|
|
|
|
static void VSIStdinInit()
|
|
{
|
|
if (pabyBuffer == NULL)
|
|
{
|
|
#ifdef WIN32
|
|
setmode( fileno( stdin ), O_BINARY );
|
|
#endif
|
|
pabyBuffer = (GByte*)CPLMalloc(BUFFER_SIZE);
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* VSIStdinFilesystemHandler */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
class VSIStdinFilesystemHandler : public VSIFilesystemHandler
|
|
{
|
|
public:
|
|
VSIStdinFilesystemHandler();
|
|
virtual ~VSIStdinFilesystemHandler();
|
|
|
|
virtual VSIVirtualHandle *Open( const char *pszFilename,
|
|
const char *pszAccess);
|
|
virtual int Stat( const char *pszFilename,
|
|
VSIStatBufL *pStatBuf, int nFlags );
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* VSIStdinHandle */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
class VSIStdinHandle : public VSIVirtualHandle
|
|
{
|
|
private:
|
|
GUIntBig nCurOff;
|
|
int ReadAndCache( void* pBuffer, int nToRead );
|
|
|
|
public:
|
|
VSIStdinHandle();
|
|
virtual ~VSIStdinHandle();
|
|
|
|
virtual int Seek( vsi_l_offset nOffset, int nWhence );
|
|
virtual vsi_l_offset Tell();
|
|
virtual size_t Read( void *pBuffer, size_t nSize, size_t nMemb );
|
|
virtual size_t Write( const void *pBuffer, size_t nSize, size_t nMemb );
|
|
virtual int Eof();
|
|
virtual int Close();
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* VSIStdinHandle() */
|
|
/************************************************************************/
|
|
|
|
VSIStdinHandle::VSIStdinHandle()
|
|
{
|
|
nCurOff = 0;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~VSIStdinHandle() */
|
|
/************************************************************************/
|
|
|
|
VSIStdinHandle::~VSIStdinHandle()
|
|
{
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* ReadAndCache() */
|
|
/************************************************************************/
|
|
|
|
int VSIStdinHandle::ReadAndCache( void* pBuffer, int nToRead )
|
|
{
|
|
CPLAssert(nCurOff == nRealPos);
|
|
|
|
int nRead = fread(pBuffer, 1, nToRead, stdin);
|
|
|
|
if (nRealPos < BUFFER_SIZE)
|
|
{
|
|
int nToCopy = MIN(BUFFER_SIZE - (int)nRealPos, nRead);
|
|
memcpy(pabyBuffer + nRealPos, pBuffer, nToCopy);
|
|
nBufferLen += nToCopy;
|
|
}
|
|
|
|
nCurOff += nRead;
|
|
nRealPos = nCurOff;
|
|
|
|
return nRead;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Seek() */
|
|
/************************************************************************/
|
|
|
|
int VSIStdinHandle::Seek( vsi_l_offset nOffset, int nWhence )
|
|
|
|
{
|
|
if (nWhence == SEEK_SET && nOffset == nCurOff)
|
|
return 0;
|
|
|
|
VSIStdinInit();
|
|
if (nBufferLen == 0)
|
|
nRealPos = nBufferLen = fread(pabyBuffer, 1, BUFFER_SIZE, stdin);
|
|
|
|
if (nWhence == SEEK_END)
|
|
{
|
|
if (nOffset != 0)
|
|
{
|
|
CPLError(CE_Failure, CPLE_NotSupported,
|
|
"Seek(xx != 0, SEEK_END) unsupported on /vsistdin");
|
|
return -1;
|
|
}
|
|
|
|
if (nBufferLen < BUFFER_SIZE)
|
|
{
|
|
nCurOff = nBufferLen;
|
|
return 0;
|
|
}
|
|
|
|
CPLError(CE_Failure, CPLE_NotSupported,
|
|
"Seek(SEEK_END) unsupported on /vsistdin when stdin > 1 MB");
|
|
return -1;
|
|
}
|
|
|
|
if (nWhence == SEEK_CUR)
|
|
nOffset += nCurOff;
|
|
|
|
if (nRealPos > nBufferLen && nOffset < nRealPos)
|
|
{
|
|
CPLError(CE_Failure, CPLE_NotSupported,
|
|
"backward Seek() unsupported on /vsistdin above first MB");
|
|
return -1;
|
|
}
|
|
|
|
if (nOffset < nBufferLen)
|
|
{
|
|
nCurOff = nOffset;
|
|
return 0;
|
|
}
|
|
|
|
if (nOffset == nCurOff)
|
|
return 0;
|
|
|
|
CPLDebug("VSI", "Forward seek from " CPL_FRMT_GUIB " to " CPL_FRMT_GUIB,
|
|
nCurOff, nOffset);
|
|
|
|
char abyTemp[8192];
|
|
nCurOff = nRealPos;
|
|
while(TRUE)
|
|
{
|
|
int nToRead = (int) MIN(8192, nOffset - nCurOff);
|
|
int nRead = ReadAndCache( abyTemp, nToRead );
|
|
|
|
if (nRead < nToRead)
|
|
return -1;
|
|
if (nToRead < 8192)
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Tell() */
|
|
/************************************************************************/
|
|
|
|
vsi_l_offset VSIStdinHandle::Tell()
|
|
{
|
|
return nCurOff;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Read() */
|
|
/************************************************************************/
|
|
|
|
size_t VSIStdinHandle::Read( void * pBuffer, size_t nSize, size_t nCount )
|
|
|
|
{
|
|
VSIStdinInit();
|
|
|
|
if (nCurOff < nBufferLen)
|
|
{
|
|
if (nCurOff + nSize * nCount < nBufferLen)
|
|
{
|
|
memcpy(pBuffer, pabyBuffer + nCurOff, nSize * nCount);
|
|
nCurOff += nSize * nCount;
|
|
return nCount;
|
|
}
|
|
|
|
int nAlreadyCached = (int)(nBufferLen - nCurOff);
|
|
memcpy(pBuffer, pabyBuffer + nCurOff, nAlreadyCached);
|
|
|
|
nCurOff += nAlreadyCached;
|
|
|
|
int nRead = ReadAndCache( (GByte*)pBuffer + nAlreadyCached,
|
|
(int)(nSize*nCount - nAlreadyCached) );
|
|
|
|
return ((nRead + nAlreadyCached) / nSize);
|
|
}
|
|
|
|
int nRead = ReadAndCache( pBuffer, (int)(nSize * nCount) );
|
|
return nRead / nSize;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Write() */
|
|
/************************************************************************/
|
|
|
|
size_t VSIStdinHandle::Write( CPL_UNUSED const void * pBuffer,
|
|
CPL_UNUSED size_t nSize,
|
|
CPL_UNUSED size_t nCount )
|
|
{
|
|
CPLError(CE_Failure, CPLE_NotSupported,
|
|
"Write() unsupported on /vsistdin");
|
|
return 0;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Eof() */
|
|
/************************************************************************/
|
|
|
|
int VSIStdinHandle::Eof()
|
|
|
|
{
|
|
if (nCurOff < nBufferLen)
|
|
return FALSE;
|
|
return feof(stdin);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Close() */
|
|
/************************************************************************/
|
|
|
|
int VSIStdinHandle::Close()
|
|
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* VSIStdinFilesystemHandler */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
/************************************************************************/
|
|
/* VSIStdinFilesystemHandler() */
|
|
/************************************************************************/
|
|
|
|
VSIStdinFilesystemHandler::VSIStdinFilesystemHandler()
|
|
{
|
|
pabyBuffer = NULL;
|
|
nBufferLen = 0;
|
|
nRealPos = 0;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~VSIStdinFilesystemHandler() */
|
|
/************************************************************************/
|
|
|
|
VSIStdinFilesystemHandler::~VSIStdinFilesystemHandler()
|
|
{
|
|
CPLFree(pabyBuffer);
|
|
pabyBuffer = NULL;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Open() */
|
|
/************************************************************************/
|
|
|
|
VSIVirtualHandle *
|
|
VSIStdinFilesystemHandler::Open( const char *pszFilename,
|
|
const char *pszAccess )
|
|
|
|
{
|
|
if (strcmp(pszFilename, "/vsistdin/") != 0)
|
|
return NULL;
|
|
|
|
if ( strchr(pszAccess, 'w') != NULL ||
|
|
strchr(pszAccess, '+') != NULL )
|
|
{
|
|
CPLError(CE_Failure, CPLE_NotSupported,
|
|
"Write or update mode not supported on /vsistdin");
|
|
return NULL;
|
|
}
|
|
|
|
return new VSIStdinHandle;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Stat() */
|
|
/************************************************************************/
|
|
|
|
int VSIStdinFilesystemHandler::Stat( const char * pszFilename,
|
|
VSIStatBufL * pStatBuf,
|
|
int nFlags )
|
|
|
|
{
|
|
memset( pStatBuf, 0, sizeof(VSIStatBufL) );
|
|
|
|
if (strcmp(pszFilename, "/vsistdin/") != 0)
|
|
return -1;
|
|
|
|
if ((nFlags & VSI_STAT_SIZE_FLAG))
|
|
{
|
|
VSIStdinInit();
|
|
if (nBufferLen == 0)
|
|
nRealPos = nBufferLen = fread(pabyBuffer, 1, BUFFER_SIZE, stdin);
|
|
|
|
pStatBuf->st_size = nBufferLen;
|
|
}
|
|
|
|
pStatBuf->st_mode = S_IFREG;
|
|
return 0;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* VSIInstallStdinHandler() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief Install /vsistdin/ file system handler
|
|
*
|
|
* A special file handler is installed that allows reading from the standard
|
|
* input steam.
|
|
*
|
|
* The file operations available are of course limited to Read() and
|
|
* forward Seek() (full seek in the first MB of a file).
|
|
*
|
|
* @since GDAL 1.8.0
|
|
*/
|
|
void VSIInstallStdinHandler()
|
|
|
|
{
|
|
VSIFileManager::InstallHandler( "/vsistdin/", new VSIStdinFilesystemHandler );
|
|
}
|