LCOV - code coverage report
Current view: top level - port - cpl_vsil_buffered_reader.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 98 124 79.0 %
Date: 2024-11-21 22:18:42 Functions: 14 16 87.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  VSI Virtual File System
       4             :  * Purpose:  Implementation of buffered reader IO functions.
       5             :  * Author:   Even Rouault, even.rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2010-2011, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : //! @cond Doxygen_Suppress
      14             : 
      15             : // The intent of this class is to be a wrapper around an underlying virtual
      16             : // handle and add very basic caching of last read bytes, so that a backward
      17             : // seek of a few bytes doesn't require a seek on the underlying virtual handle.
      18             : // This enable us to improve dramatically the performance of CPLReadLine2L() on
      19             : // a gzip file.
      20             : 
      21             : #include "cpl_port.h"
      22             : #include "cpl_vsi_virtual.h"
      23             : 
      24             : #include <cstddef>
      25             : #include <cstring>
      26             : #if HAVE_FCNTL_H
      27             : #include <fcntl.h>
      28             : #endif
      29             : 
      30             : #include <algorithm>
      31             : #include <vector>
      32             : 
      33             : #include "cpl_conv.h"
      34             : #include "cpl_error.h"
      35             : #include "cpl_vsi.h"
      36             : 
      37             : constexpr int MAX_BUFFER_SIZE = 65536;
      38             : 
      39             : class VSIBufferedReaderHandle final : public VSIVirtualHandle
      40             : {
      41             :     CPL_DISALLOW_COPY_ASSIGN(VSIBufferedReaderHandle)
      42             : 
      43             :     VSIVirtualHandle *m_poBaseHandle = nullptr;
      44             :     GByte *pabyBuffer = nullptr;
      45             :     GUIntBig nBufferOffset = 0;
      46             :     int nBufferSize = 0;
      47             :     GUIntBig nCurOffset = 0;
      48             :     bool bNeedBaseHandleSeek = false;
      49             :     bool bEOF = false;
      50             :     bool bError = false;
      51             :     vsi_l_offset nCheatFileSize = 0;
      52             : 
      53             :     int SeekBaseTo(vsi_l_offset nTargetOffset);
      54             : 
      55             :   public:
      56             :     explicit VSIBufferedReaderHandle(VSIVirtualHandle *poBaseHandle);
      57             :     VSIBufferedReaderHandle(VSIVirtualHandle *poBaseHandle,
      58             :                             const GByte *pabyBeginningContent,
      59             :                             vsi_l_offset nCheatFileSizeIn);
      60             :     // TODO(schwehr): Add override when support dropped for VS2008.
      61             :     ~VSIBufferedReaderHandle() override;
      62             : 
      63             :     int Seek(vsi_l_offset nOffset, int nWhence) override;
      64             :     vsi_l_offset Tell() override;
      65             :     size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
      66             :     size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
      67             :     int Eof() override;
      68             :     int Error() override;
      69             :     void ClearErr() override;
      70             :     int Flush() override;
      71             :     int Close() override;
      72             : };
      73             : 
      74             : //! @endcond
      75             : 
      76             : /************************************************************************/
      77             : /*                    VSICreateBufferedReaderHandle()                   */
      78             : /************************************************************************/
      79             : 
      80        5198 : VSIVirtualHandle *VSICreateBufferedReaderHandle(VSIVirtualHandle *poBaseHandle)
      81             : {
      82        5198 :     return new VSIBufferedReaderHandle(poBaseHandle);
      83             : }
      84             : 
      85             : VSIVirtualHandle *
      86           7 : VSICreateBufferedReaderHandle(VSIVirtualHandle *poBaseHandle,
      87             :                               const GByte *pabyBeginningContent,
      88             :                               vsi_l_offset nCheatFileSizeIn)
      89             : {
      90             :     return new VSIBufferedReaderHandle(poBaseHandle, pabyBeginningContent,
      91           7 :                                        nCheatFileSizeIn);
      92             : }
      93             : 
      94             : //! @cond Doxygen_Suppress
      95             : 
      96             : /************************************************************************/
      97             : /*                        VSIBufferedReaderHandle()                     */
      98             : /************************************************************************/
      99             : 
     100        5198 : VSIBufferedReaderHandle::VSIBufferedReaderHandle(VSIVirtualHandle *poBaseHandle)
     101             :     : m_poBaseHandle(poBaseHandle),
     102        5198 :       pabyBuffer(static_cast<GByte *>(CPLMalloc(MAX_BUFFER_SIZE)))
     103             : {
     104        5198 : }
     105             : 
     106           7 : VSIBufferedReaderHandle::VSIBufferedReaderHandle(
     107             :     VSIVirtualHandle *poBaseHandle, const GByte *pabyBeginningContent,
     108           7 :     vsi_l_offset nCheatFileSizeIn)
     109             :     : m_poBaseHandle(poBaseHandle),
     110          14 :       pabyBuffer(static_cast<GByte *>(CPLMalloc(
     111           7 :           std::max(MAX_BUFFER_SIZE, static_cast<int>(poBaseHandle->Tell()))))),
     112          14 :       nBufferOffset(0), nBufferSize(static_cast<int>(poBaseHandle->Tell())),
     113             :       nCurOffset(0), bNeedBaseHandleSeek(true), bEOF(false),
     114          14 :       nCheatFileSize(nCheatFileSizeIn)
     115             : {
     116           7 :     memcpy(pabyBuffer, pabyBeginningContent, nBufferSize);
     117           7 : }
     118             : 
     119             : /************************************************************************/
     120             : /*                        ~VSIBufferedReaderHandle()                    */
     121             : /************************************************************************/
     122             : 
     123       10410 : VSIBufferedReaderHandle::~VSIBufferedReaderHandle()
     124             : {
     125        5205 :     delete m_poBaseHandle;
     126        5205 :     CPLFree(pabyBuffer);
     127       10410 : }
     128             : 
     129             : /************************************************************************/
     130             : /*                               Seek()                                 */
     131             : /************************************************************************/
     132             : 
     133      226065 : int VSIBufferedReaderHandle::Seek(vsi_l_offset nOffset, int nWhence)
     134             : {
     135             : #ifdef DEBUG_VERBOSE
     136             :     CPLDebug("BUFFERED", "Seek(%d,%d)", static_cast<int>(nOffset),
     137             :              static_cast<int>(nWhence));
     138             : #endif
     139      226065 :     bEOF = false;
     140      226065 :     int ret = 0;
     141      226065 :     if (nWhence == SEEK_CUR)
     142             :     {
     143        1448 :         nCurOffset += nOffset;
     144             :     }
     145      224617 :     else if (nWhence == SEEK_END)
     146             :     {
     147        2029 :         if (nCheatFileSize)
     148             :         {
     149           2 :             nCurOffset = nCheatFileSize;
     150             :         }
     151             :         else
     152             :         {
     153        2027 :             ret = m_poBaseHandle->Seek(nOffset, nWhence);
     154        2027 :             nCurOffset = m_poBaseHandle->Tell();
     155        2027 :             bNeedBaseHandleSeek = true;
     156             :         }
     157             :     }
     158             :     else
     159             :     {
     160      222588 :         nCurOffset = nOffset;
     161             :     }
     162             : 
     163      226065 :     return ret;
     164             : }
     165             : 
     166             : /************************************************************************/
     167             : /*                               Tell()                                 */
     168             : /************************************************************************/
     169             : 
     170      111127 : vsi_l_offset VSIBufferedReaderHandle::Tell()
     171             : {
     172             : #ifdef DEBUG_VERBOSE
     173             :     CPLDebug("BUFFERED", "Tell() = %d", static_cast<int>(nCurOffset));
     174             : #endif
     175      111127 :     return nCurOffset;
     176             : }
     177             : 
     178             : /************************************************************************/
     179             : /*                           SeekBaseTo()                               */
     180             : /************************************************************************/
     181             : 
     182       32761 : int VSIBufferedReaderHandle::SeekBaseTo(vsi_l_offset nTargetOffset)
     183             : {
     184       32761 :     if (m_poBaseHandle->Seek(nTargetOffset, SEEK_SET) == 0)
     185       32761 :         return TRUE;
     186             : 
     187           0 :     nCurOffset = m_poBaseHandle->Tell();
     188           0 :     if (nCurOffset > nTargetOffset)
     189           0 :         return FALSE;
     190             : 
     191           0 :     const vsi_l_offset nMaxOffset = 8192;
     192             : 
     193           0 :     std::vector<char> oTemp(nMaxOffset, 0);
     194           0 :     char *pabyTemp = &oTemp[0];
     195             : 
     196             :     while (true)
     197             :     {
     198             :         const size_t nToRead = static_cast<size_t>(
     199           0 :             std::min(nMaxOffset, nTargetOffset - nCurOffset));
     200           0 :         const size_t nRead = m_poBaseHandle->Read(pabyTemp, 1, nToRead);
     201             : 
     202           0 :         nCurOffset += nRead;
     203             : 
     204           0 :         if (nRead < nToRead)
     205             :         {
     206           0 :             bEOF = CPL_TO_BOOL(m_poBaseHandle->Eof());
     207           0 :             bError = CPL_TO_BOOL(m_poBaseHandle->Error());
     208           0 :             return FALSE;
     209             :         }
     210           0 :         if (nToRead < nMaxOffset)
     211           0 :             break;
     212           0 :     }
     213           0 :     return TRUE;
     214             : }
     215             : 
     216             : /************************************************************************/
     217             : /*                               Read()                                 */
     218             : /************************************************************************/
     219             : 
     220      319431 : size_t VSIBufferedReaderHandle::Read(void *pBuffer, size_t nSize, size_t nMemb)
     221             : {
     222      319431 :     const size_t nTotalToRead = nSize * nMemb;
     223             : #ifdef DEBUG_VERBOSE
     224             :     CPLDebug("BUFFERED", "Read(%d)", static_cast<int>(nTotalToRead));
     225             : #endif
     226             : 
     227      319431 :     if (nSize == 0)
     228           0 :         return 0;
     229             : 
     230      319431 :     if (nBufferSize != 0 && nCurOffset >= nBufferOffset &&
     231      295413 :         nCurOffset <= nBufferOffset + nBufferSize)
     232             :     {
     233             :         // We try to read from an offset located within the buffer.
     234             :         const size_t nReadInBuffer = static_cast<size_t>(std::min(
     235             :             nTotalToRead,
     236      286769 :             static_cast<size_t>(nBufferOffset + nBufferSize - nCurOffset)));
     237      286769 :         memcpy(pBuffer, pabyBuffer + nCurOffset - nBufferOffset, nReadInBuffer);
     238      286769 :         const size_t nToReadInFile = nTotalToRead - nReadInBuffer;
     239      286769 :         if (nToReadInFile > 0)
     240             :         {
     241             :             // The beginning of the data to read is located in the buffer
     242             :             // but the end must be read from the file.
     243      279739 :             if (bNeedBaseHandleSeek)
     244             :             {
     245          99 :                 if (!SeekBaseTo(nBufferOffset + nBufferSize))
     246             :                 {
     247           0 :                     nCurOffset += nReadInBuffer;
     248           0 :                     return nReadInBuffer / nSize;
     249             :                 }
     250             :             }
     251      279739 :             bNeedBaseHandleSeek = false;
     252             : #ifdef DEBUG_VERBOSE
     253             :             CPLAssert(m_poBaseHandle->Tell() == nBufferOffset + nBufferSize);
     254             : #endif
     255             : 
     256      559478 :             const size_t nReadInFile = m_poBaseHandle->Read(
     257             :                 static_cast<GByte *>(pBuffer) + nReadInBuffer, 1,
     258      279739 :                 nToReadInFile);
     259      279739 :             if (nReadInFile < nToReadInFile)
     260             :             {
     261        5078 :                 if (m_poBaseHandle->Eof())
     262        5076 :                     bEOF = true;
     263             :                 else
     264             :                 {
     265           2 :                     CPLAssert(m_poBaseHandle->Error());
     266           2 :                     bError = true;
     267             :                 }
     268             :             }
     269      279739 :             const size_t nRead = nReadInBuffer + nReadInFile;
     270             : 
     271      279739 :             nBufferSize = static_cast<int>(
     272      279739 :                 std::min(nRead, static_cast<size_t>(MAX_BUFFER_SIZE)));
     273      279739 :             nBufferOffset = nCurOffset + nRead - nBufferSize;
     274      279739 :             memcpy(pabyBuffer,
     275      279739 :                    static_cast<GByte *>(pBuffer) + nRead - nBufferSize,
     276      279739 :                    nBufferSize);
     277             : 
     278      279739 :             nCurOffset += nRead;
     279             : #ifdef DEBUG_VERBOSE
     280             :             CPLAssert(m_poBaseHandle->Tell() == nBufferOffset + nBufferSize);
     281             :             CPLAssert(m_poBaseHandle->Tell() == nCurOffset);
     282             : #endif
     283             : 
     284      279739 :             return nRead / nSize;
     285             :         }
     286             :         else
     287             :         {
     288             :             // The data to read is completely located within the buffer.
     289        7030 :             nCurOffset += nTotalToRead;
     290        7030 :             return nTotalToRead / nSize;
     291             :         }
     292             :     }
     293             :     else
     294             :     {
     295             :         // We try either to read before or after the buffer, so a seek is
     296             :         // necessary.
     297       32662 :         if (!SeekBaseTo(nCurOffset))
     298           0 :             return 0;
     299       32662 :         bNeedBaseHandleSeek = false;
     300             :         const size_t nReadInFile =
     301       32662 :             m_poBaseHandle->Read(pBuffer, 1, nTotalToRead);
     302       32662 :         if (nReadInFile < nTotalToRead)
     303             :         {
     304        3587 :             if (m_poBaseHandle->Eof())
     305        3586 :                 bEOF = true;
     306             :             else
     307             :             {
     308           1 :                 CPLAssert(m_poBaseHandle->Error());
     309           1 :                 bError = true;
     310             :             }
     311             :         }
     312       32662 :         nBufferSize = static_cast<int>(
     313       32662 :             std::min(nReadInFile, static_cast<size_t>(MAX_BUFFER_SIZE)));
     314       32662 :         nBufferOffset = nCurOffset + nReadInFile - nBufferSize;
     315       32662 :         memcpy(pabyBuffer,
     316       32662 :                static_cast<GByte *>(pBuffer) + nReadInFile - nBufferSize,
     317       32662 :                nBufferSize);
     318             : 
     319       32662 :         nCurOffset += nReadInFile;
     320             : #ifdef DEBUG_VERBOSE
     321             :         CPLAssert(m_poBaseHandle->Tell() == nBufferOffset + nBufferSize);
     322             :         CPLAssert(m_poBaseHandle->Tell() == nCurOffset);
     323             : #endif
     324             : 
     325       32662 :         return nReadInFile / nSize;
     326             :     }
     327             : }
     328             : 
     329             : /************************************************************************/
     330             : /*                              Write()                                 */
     331             : /************************************************************************/
     332             : 
     333           0 : size_t VSIBufferedReaderHandle::Write(const void * /* pBuffer */,
     334             :                                       size_t /* nSize */, size_t /* nMemb */)
     335             : {
     336           0 :     CPLError(CE_Failure, CPLE_NotSupported,
     337             :              "VSIFWriteL is not supported on buffer reader streams");
     338           0 :     return 0;
     339             : }
     340             : 
     341             : /************************************************************************/
     342             : /*                             ClearErr()                               */
     343             : /************************************************************************/
     344             : 
     345          60 : void VSIBufferedReaderHandle::ClearErr()
     346             : 
     347             : {
     348          60 :     m_poBaseHandle->ClearErr();
     349          60 :     bEOF = false;
     350          60 :     bError = false;
     351          60 : }
     352             : 
     353             : /************************************************************************/
     354             : /*                               Eof()                                  */
     355             : /************************************************************************/
     356             : 
     357         356 : int VSIBufferedReaderHandle::Eof()
     358             : {
     359         356 :     return bEOF;
     360             : }
     361             : 
     362             : /************************************************************************/
     363             : /*                              Error()                                 */
     364             : /************************************************************************/
     365             : 
     366        3122 : int VSIBufferedReaderHandle::Error()
     367             : {
     368        3122 :     return bError;
     369             : }
     370             : 
     371             : /************************************************************************/
     372             : /*                              Flush()                                 */
     373             : /************************************************************************/
     374             : 
     375           0 : int VSIBufferedReaderHandle::Flush()
     376             : {
     377           0 :     return 0;
     378             : }
     379             : 
     380             : /************************************************************************/
     381             : /*                              Close()                                 */
     382             : /************************************************************************/
     383             : 
     384        5202 : int VSIBufferedReaderHandle::Close()
     385             : {
     386        5202 :     if (m_poBaseHandle)
     387             :     {
     388        5202 :         m_poBaseHandle->Close();
     389        5202 :         delete m_poBaseHandle;
     390        5202 :         m_poBaseHandle = nullptr;
     391             :     }
     392        5202 :     return 0;
     393             : }
     394             : 
     395             : //! @endcond

Generated by: LCOV version 1.14