mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-01 14:22:41 -06:00
323 lines
12 KiB
C++
323 lines
12 KiB
C++
/******************************************************************************
|
|
* $Id: cpl_vsil_buffered_reader.cpp 28493 2015-02-16 09:49:16Z rouault $
|
|
*
|
|
* Project: VSI Virtual File System
|
|
* Purpose: Implementation of buffered reader IO functions.
|
|
* Author: Even Rouault, even.rouault at mines-paris.org
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2010-2011, 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.
|
|
****************************************************************************/
|
|
|
|
/* The intent of this class is to be a wrapper around an underlying virtual */
|
|
/* handle and add very basic caching of last read bytes, so that a backward */
|
|
/* seek of a few bytes doesn't require a seek on the underlying virtual handle. */
|
|
/* This enable us to improve dramatically the performance of CPLReadLine2L() on */
|
|
/* a gzip file */
|
|
|
|
#include "cpl_vsi_virtual.h"
|
|
|
|
#include "cpl_port.h"
|
|
|
|
#define MAX_BUFFER_SIZE 65536
|
|
|
|
CPL_CVSID("$Id: cpl_vsil_buffered_reader.cpp 28493 2015-02-16 09:49:16Z rouault $");
|
|
|
|
class VSIBufferedReaderHandle : public VSIVirtualHandle
|
|
{
|
|
VSIVirtualHandle* poBaseHandle;
|
|
GByte* pabyBuffer;
|
|
GUIntBig nBufferOffset;
|
|
int nBufferSize;
|
|
GUIntBig nCurOffset;
|
|
int bNeedBaseHandleSeek;
|
|
int bEOF;
|
|
vsi_l_offset nSheatFileSize;
|
|
|
|
int SeekBaseTo(vsi_l_offset nTargetOffset);
|
|
|
|
public:
|
|
|
|
VSIBufferedReaderHandle(VSIVirtualHandle* poBaseHandle);
|
|
VSIBufferedReaderHandle(VSIVirtualHandle* poBaseHandle,
|
|
const GByte* pabyBeginningContent,
|
|
vsi_l_offset nSheatFileSizeIn);
|
|
~VSIBufferedReaderHandle();
|
|
|
|
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 Flush();
|
|
virtual int Close();
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* VSICreateBufferedReaderHandle() */
|
|
/************************************************************************/
|
|
|
|
VSIVirtualHandle* VSICreateBufferedReaderHandle(VSIVirtualHandle* poBaseHandle)
|
|
{
|
|
return new VSIBufferedReaderHandle(poBaseHandle);
|
|
}
|
|
|
|
VSIVirtualHandle* VSICreateBufferedReaderHandle(VSIVirtualHandle* poBaseHandle,
|
|
const GByte* pabyBeginningContent,
|
|
vsi_l_offset nSheatFileSizeIn)
|
|
{
|
|
return new VSIBufferedReaderHandle(poBaseHandle,
|
|
pabyBeginningContent,
|
|
nSheatFileSizeIn);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* VSIBufferedReaderHandle() */
|
|
/************************************************************************/
|
|
|
|
VSIBufferedReaderHandle::VSIBufferedReaderHandle(VSIVirtualHandle* poBaseHandle)
|
|
{
|
|
this->poBaseHandle = poBaseHandle;
|
|
pabyBuffer = (GByte*)CPLMalloc(MAX_BUFFER_SIZE);
|
|
nBufferOffset = 0;
|
|
nBufferSize = 0;
|
|
nCurOffset = 0;
|
|
bNeedBaseHandleSeek = FALSE;
|
|
bEOF = FALSE;
|
|
nSheatFileSize = 0;
|
|
}
|
|
|
|
VSIBufferedReaderHandle::VSIBufferedReaderHandle(VSIVirtualHandle* poBaseHandle,
|
|
const GByte* pabyBeginningContent,
|
|
vsi_l_offset nSheatFileSizeIn)
|
|
{
|
|
this->poBaseHandle = poBaseHandle;
|
|
nBufferOffset = 0;
|
|
nBufferSize = (int)poBaseHandle->Tell();
|
|
pabyBuffer = (GByte*)CPLMalloc(MAX(MAX_BUFFER_SIZE,nBufferSize));
|
|
memcpy(pabyBuffer, pabyBeginningContent, nBufferSize);
|
|
nCurOffset = 0;
|
|
bNeedBaseHandleSeek = TRUE;
|
|
bEOF = FALSE;
|
|
nSheatFileSize = nSheatFileSizeIn;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~VSIBufferedReaderHandle() */
|
|
/************************************************************************/
|
|
|
|
VSIBufferedReaderHandle::~VSIBufferedReaderHandle()
|
|
{
|
|
delete poBaseHandle;
|
|
CPLFree(pabyBuffer);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Seek() */
|
|
/************************************************************************/
|
|
|
|
int VSIBufferedReaderHandle::Seek( vsi_l_offset nOffset, int nWhence )
|
|
{
|
|
//CPLDebug( "BUFFERED", "Seek(%d,%d)", (int)nOffset, (int)nWhence);
|
|
bEOF = FALSE;
|
|
if (nWhence == SEEK_CUR)
|
|
nCurOffset += nOffset;
|
|
else if (nWhence == SEEK_END)
|
|
{
|
|
if( nSheatFileSize )
|
|
nCurOffset = nSheatFileSize;
|
|
else
|
|
{
|
|
poBaseHandle->Seek(nOffset, nWhence);
|
|
nCurOffset = poBaseHandle->Tell();
|
|
bNeedBaseHandleSeek = TRUE;
|
|
}
|
|
}
|
|
else
|
|
nCurOffset = nOffset;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Tell() */
|
|
/************************************************************************/
|
|
|
|
vsi_l_offset VSIBufferedReaderHandle::Tell()
|
|
{
|
|
//CPLDebug( "BUFFERED", "Tell() = %d", (int)nCurOffset);
|
|
return nCurOffset;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SeekBaseTo() */
|
|
/************************************************************************/
|
|
|
|
int VSIBufferedReaderHandle::SeekBaseTo(vsi_l_offset nTargetOffset)
|
|
{
|
|
if( poBaseHandle->Seek(nTargetOffset, SEEK_SET) == 0 )
|
|
return TRUE;
|
|
|
|
nCurOffset = poBaseHandle->Tell();
|
|
if( nCurOffset > nTargetOffset )
|
|
return FALSE;
|
|
char abyTemp[8192];
|
|
while(TRUE)
|
|
{
|
|
int nToRead = (int) MIN(8192, nTargetOffset - nCurOffset);
|
|
int nRead = (int)poBaseHandle->Read(abyTemp, 1, nToRead );
|
|
nCurOffset += nRead;
|
|
|
|
if (nRead < nToRead)
|
|
{
|
|
bEOF = TRUE;
|
|
return FALSE;
|
|
}
|
|
if (nToRead < 8192)
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Read() */
|
|
/************************************************************************/
|
|
|
|
size_t VSIBufferedReaderHandle::Read( void *pBuffer, size_t nSize, size_t nMemb )
|
|
{
|
|
const size_t nTotalToRead = nSize * nMemb;
|
|
//CPLDebug( "BUFFERED", "Read(%d)", (int)nTotalToRead);
|
|
|
|
if (nSize == 0)
|
|
return 0;
|
|
|
|
if (nBufferSize != 0 &&
|
|
nCurOffset >= nBufferOffset && nCurOffset <= nBufferOffset + nBufferSize)
|
|
{
|
|
/* We try to read from an offset located within the buffer */
|
|
const int nReadInBuffer = (int) MIN(nTotalToRead, nBufferOffset + nBufferSize - nCurOffset);
|
|
memcpy(pBuffer, pabyBuffer + nCurOffset - nBufferOffset, nReadInBuffer);
|
|
const int nToReadInFile = nTotalToRead - nReadInBuffer;
|
|
if (nToReadInFile > 0)
|
|
{
|
|
/* The beginning of the the data to read is located in the buffer */
|
|
/* but the end must be read from the file */
|
|
if (bNeedBaseHandleSeek)
|
|
{
|
|
if( !SeekBaseTo(nBufferOffset + nBufferSize) )
|
|
{
|
|
nCurOffset += nReadInBuffer;
|
|
return nReadInBuffer / nSize;
|
|
}
|
|
}
|
|
bNeedBaseHandleSeek = FALSE;
|
|
//CPLAssert(poBaseHandle->Tell() == nBufferOffset + nBufferSize);
|
|
|
|
const int nReadInFile = poBaseHandle->Read((GByte*)pBuffer + nReadInBuffer, 1, nToReadInFile);
|
|
const int nRead = nReadInBuffer + nReadInFile;
|
|
|
|
nBufferSize = MIN(nRead, MAX_BUFFER_SIZE);
|
|
nBufferOffset = nCurOffset + nRead - nBufferSize;
|
|
memcpy(pabyBuffer, (GByte*)pBuffer + nRead - nBufferSize, nBufferSize);
|
|
|
|
nCurOffset += nRead;
|
|
//CPLAssert(poBaseHandle->Tell() == nBufferOffset + nBufferSize);
|
|
//CPLAssert(poBaseHandle->Tell() == nCurOffset);
|
|
|
|
bEOF = poBaseHandle->Eof();
|
|
|
|
return nRead / nSize;
|
|
}
|
|
else
|
|
{
|
|
/* The data to read is completely located within the buffer */
|
|
nCurOffset += nTotalToRead;
|
|
return nTotalToRead / nSize;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* We try either to read before or after the buffer, so a seek is necessary */
|
|
if( !SeekBaseTo(nCurOffset) )
|
|
return 0;
|
|
bNeedBaseHandleSeek = FALSE;
|
|
const int nReadInFile = poBaseHandle->Read(pBuffer, 1, nTotalToRead);
|
|
nBufferSize = MIN(nReadInFile, MAX_BUFFER_SIZE);
|
|
nBufferOffset = nCurOffset + nReadInFile - nBufferSize;
|
|
memcpy(pabyBuffer, (GByte*)pBuffer + nReadInFile - nBufferSize, nBufferSize);
|
|
|
|
nCurOffset += nReadInFile;
|
|
//CPLAssert(poBaseHandle->Tell() == nBufferOffset + nBufferSize);
|
|
//CPLAssert(poBaseHandle->Tell() == nCurOffset);
|
|
|
|
bEOF = poBaseHandle->Eof();
|
|
|
|
return nReadInFile / nSize;
|
|
}
|
|
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Write() */
|
|
/************************************************************************/
|
|
|
|
size_t VSIBufferedReaderHandle::Write( CPL_UNUSED const void *pBuffer,
|
|
CPL_UNUSED size_t nSize,
|
|
CPL_UNUSED size_t nMemb )
|
|
{
|
|
CPLError(CE_Failure, CPLE_NotSupported,
|
|
"VSIFWriteL is not supported on buffer reader streams\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* Eof() */
|
|
/************************************************************************/
|
|
|
|
int VSIBufferedReaderHandle::Eof()
|
|
{
|
|
return bEOF;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Flush() */
|
|
/************************************************************************/
|
|
|
|
int VSIBufferedReaderHandle::Flush()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Close() */
|
|
/************************************************************************/
|
|
|
|
int VSIBufferedReaderHandle::Close()
|
|
{
|
|
if (poBaseHandle)
|
|
{
|
|
poBaseHandle->Close();
|
|
delete poBaseHandle;
|
|
poBaseHandle = NULL;
|
|
}
|
|
return 0;
|
|
}
|