LCOV - code coverage report
Current view: top level - port - cpl_vsil_stdin.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 198 235 84.3 %
Date: 2024-04-28 21:03:45 Functions: 18 21 85.7 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Project:  CPL - Common Portability Library
       4             :  * Purpose:  Implement VSI large file api for stdin
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  **********************************************************************
       8             :  * Copyright (c) 2010-2012, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      21             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : //! @cond Doxygen_Suppress
      30             : 
      31             : #include "cpl_port.h"
      32             : #include "cpl_vsi.h"
      33             : 
      34             : #include <cstddef>
      35             : #include <cstdio>
      36             : #include <cstdlib>
      37             : #include <cstring>
      38             : #if HAVE_FCNTL_H
      39             : #include <fcntl.h>
      40             : #endif
      41             : #if HAVE_SYS_STAT_H
      42             : #include <sys/stat.h>
      43             : #endif
      44             : 
      45             : #include <algorithm>
      46             : #include <limits>
      47             : 
      48             : #include "cpl_conv.h"
      49             : #include "cpl_error.h"
      50             : #include "cpl_vsi_virtual.h"
      51             : 
      52             : #ifdef _WIN32
      53             : #include <io.h>
      54             : #include <fcntl.h>
      55             : #endif
      56             : 
      57             : static std::string gosStdinFilename{};
      58             : static FILE *gStdinFile = stdin;
      59             : static GByte *gpabyBuffer = nullptr;
      60             : static size_t gnBufferLimit = 0;  // maximum that can be allocated
      61             : static size_t gnBufferAlloc = 0;  // current allocation
      62             : static size_t gnBufferLen = 0;    // number of valid bytes in gpabyBuffer
      63             : static uint64_t gnRealPos = 0;    // current offset on stdin
      64             : static bool gbHasSoughtToEnd = false;
      65             : static uint64_t gnFileSize = 0;
      66             : 
      67             : /************************************************************************/
      68             : /*                           VSIStdinInit()                             */
      69             : /************************************************************************/
      70             : 
      71         798 : static void VSIStdinInit()
      72             : {
      73         798 :     if (gpabyBuffer == nullptr)
      74             :     {
      75             : #ifdef _WIN32
      76             :         setmode(fileno(stdin), O_BINARY);
      77             : #endif
      78           4 :         constexpr size_t MAX_INITIAL_ALLOC = 1024 * 1024;
      79           4 :         gnBufferAlloc = std::min(gnBufferAlloc, MAX_INITIAL_ALLOC);
      80           4 :         gpabyBuffer = static_cast<GByte *>(CPLMalloc(gnBufferAlloc));
      81             :     }
      82         798 : }
      83             : 
      84             : /************************************************************************/
      85             : /* ==================================================================== */
      86             : /*                       VSIStdinFilesystemHandler                     */
      87             : /* ==================================================================== */
      88             : /************************************************************************/
      89             : 
      90             : class VSIStdinFilesystemHandler final : public VSIFilesystemHandler
      91             : {
      92             :     CPL_DISALLOW_COPY_ASSIGN(VSIStdinFilesystemHandler)
      93             : 
      94             :   public:
      95             :     VSIStdinFilesystemHandler();
      96             :     ~VSIStdinFilesystemHandler() override;
      97             : 
      98             :     VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess,
      99             :                            bool bSetError,
     100             :                            CSLConstList /* papszOptions */) override;
     101             :     int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
     102             :              int nFlags) override;
     103             : 
     104           0 :     bool SupportsSequentialWrite(const char * /* pszPath */,
     105             :                                  bool /* bAllowLocalTempFile */) override
     106             :     {
     107           0 :         return false;
     108             :     }
     109             : 
     110           0 :     bool SupportsRandomWrite(const char * /* pszPath */,
     111             :                              bool /* bAllowLocalTempFile */) override
     112             :     {
     113           0 :         return false;
     114             :     }
     115             : };
     116             : 
     117             : /************************************************************************/
     118             : /* ==================================================================== */
     119             : /*                        VSIStdinHandle                               */
     120             : /* ==================================================================== */
     121             : /************************************************************************/
     122             : 
     123             : class VSIStdinHandle final : public VSIVirtualHandle
     124             : {
     125             :   private:
     126             :     CPL_DISALLOW_COPY_ASSIGN(VSIStdinHandle)
     127             : 
     128             :     bool m_bEOF = false;
     129             :     uint64_t m_nCurOff = 0;
     130             :     size_t ReadAndCache(void *pBuffer, size_t nToRead);
     131             : 
     132             :   public:
     133           9 :     VSIStdinHandle() = default;
     134             : 
     135          18 :     ~VSIStdinHandle() override
     136           9 :     {
     137           9 :         VSIStdinHandle::Close();
     138          18 :     }
     139             : 
     140             :     int Seek(vsi_l_offset nOffset, int nWhence) override;
     141             :     vsi_l_offset Tell() override;
     142             :     size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
     143             :     size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
     144             :     int Eof() override;
     145             :     int Close() override;
     146             : };
     147             : 
     148             : /************************************************************************/
     149             : /*                              ReadAndCache()                          */
     150             : /************************************************************************/
     151             : 
     152        8464 : size_t VSIStdinHandle::ReadAndCache(void *pUserBuffer, size_t nToRead)
     153             : {
     154        8464 :     CPLAssert(m_nCurOff == gnRealPos);
     155             : 
     156        8464 :     const size_t nRead = fread(pUserBuffer, 1, nToRead, gStdinFile);
     157             : 
     158        8464 :     if (gnRealPos < gnBufferLimit)
     159             :     {
     160        6669 :         bool bCopyInBuffer = true;
     161             :         const size_t nToCopy = static_cast<size_t>(
     162        6669 :             std::min(gnBufferLimit - gnRealPos, static_cast<uint64_t>(nRead)));
     163        6669 :         if (gnRealPos + nToCopy > gnBufferAlloc)
     164             :         {
     165          55 :             auto newAlloc = gnRealPos + nToCopy;
     166          55 :             if (newAlloc < gnBufferLimit - newAlloc / 3)
     167          52 :                 newAlloc += newAlloc / 3;
     168             :             else
     169           3 :                 newAlloc = gnBufferLimit;
     170          55 :             GByte *newBuffer = static_cast<GByte *>(VSI_REALLOC_VERBOSE(
     171             :                 gpabyBuffer, static_cast<size_t>(newAlloc)));
     172          55 :             if (newBuffer == nullptr)
     173             :             {
     174           0 :                 bCopyInBuffer = false;
     175             :             }
     176             :             else
     177             :             {
     178          55 :                 gpabyBuffer = newBuffer;
     179          55 :                 gnBufferAlloc = static_cast<size_t>(newAlloc);
     180             :             }
     181             :         }
     182        6669 :         if (bCopyInBuffer)
     183             :         {
     184        6669 :             memcpy(gpabyBuffer + static_cast<size_t>(gnRealPos), pUserBuffer,
     185             :                    nToCopy);
     186        6669 :             gnBufferLen += nToCopy;
     187             :         }
     188             :     }
     189             : 
     190        8464 :     m_nCurOff += nRead;
     191        8464 :     gnRealPos = m_nCurOff;
     192             : 
     193        8464 :     if (nRead < nToRead)
     194             :     {
     195          10 :         gnFileSize = gnRealPos;
     196          10 :         gbHasSoughtToEnd = true;
     197             :     }
     198             : 
     199        8464 :     return nRead;
     200             : }
     201             : 
     202             : /************************************************************************/
     203             : /*                                Seek()                                */
     204             : /************************************************************************/
     205             : 
     206          18 : int VSIStdinHandle::Seek(vsi_l_offset nOffset, int nWhence)
     207             : 
     208             : {
     209          18 :     m_bEOF = false;
     210             : 
     211          18 :     if (nWhence == SEEK_SET && nOffset == m_nCurOff)
     212           3 :         return 0;
     213             : 
     214          15 :     VSIStdinInit();
     215             : 
     216          15 :     if (nWhence == SEEK_END)
     217             :     {
     218           6 :         if (nOffset != 0)
     219             :         {
     220           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     221             :                      "Seek(xx != 0, SEEK_END) unsupported on /vsistdin");
     222           0 :             return -1;
     223             :         }
     224             : 
     225           6 :         if (gbHasSoughtToEnd)
     226             :         {
     227           0 :             m_nCurOff = gnFileSize;
     228           0 :             return 0;
     229             :         }
     230             : 
     231           6 :         nOffset = static_cast<vsi_l_offset>(-1);
     232             :     }
     233           9 :     else if (nWhence == SEEK_CUR)
     234             :     {
     235           0 :         nOffset += m_nCurOff;
     236             :     }
     237             : 
     238          15 :     if (nWhence != SEEK_END && gnRealPos >= gnBufferLimit &&
     239           3 :         nOffset >= gnBufferLimit)
     240             :     {
     241           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     242             :                  "Backward Seek() unsupported on /vsistdin beyond "
     243             :                  "maximum buffer limit (" CPL_FRMT_GUIB " bytes).\n"
     244             :                  "This limit can be extended by setting the "
     245             :                  "CPL_VSISTDIN_BUFFER_LIMIT "
     246             :                  "configuration option to a number of bytes, or by using the "
     247             :                  "'/vsistdin?buffer_limit=number_of_bytes' filename.\n"
     248             :                  "A limit of -1 means unlimited.",
     249             :                  static_cast<GUIntBig>(gnBufferLimit));
     250           0 :         return -1;
     251             :     }
     252             : 
     253          15 :     if (nOffset < gnBufferLen)
     254             :     {
     255           7 :         m_nCurOff = nOffset;
     256           7 :         return 0;
     257             :     }
     258             : 
     259           8 :     if (nOffset == m_nCurOff)
     260           0 :         return 0;
     261             : 
     262           8 :     CPLDebug("VSI", "Forward seek from " CPL_FRMT_GUIB " to " CPL_FRMT_GUIB,
     263           8 :              static_cast<GUIntBig>(m_nCurOff), nOffset);
     264             : 
     265           8 :     char abyTemp[8192] = {};
     266           8 :     m_nCurOff = gnRealPos;
     267             :     while (true)
     268             :     {
     269             :         const size_t nToRead = static_cast<size_t>(
     270       15374 :             std::min(static_cast<uint64_t>(sizeof(abyTemp)),
     271        7687 :                      static_cast<uint64_t>(nOffset - m_nCurOff)));
     272        7687 :         const size_t nRead = ReadAndCache(abyTemp, nToRead);
     273             : 
     274        7687 :         if (nRead < nToRead)
     275             :         {
     276           6 :             return nWhence == SEEK_END ? 0 : -1;
     277             :         }
     278        7681 :         if (nToRead < sizeof(abyTemp))
     279           2 :             break;
     280        7679 :     }
     281             : 
     282           2 :     return 0;
     283             : }
     284             : 
     285             : /************************************************************************/
     286             : /*                                Tell()                                */
     287             : /************************************************************************/
     288             : 
     289          23 : vsi_l_offset VSIStdinHandle::Tell()
     290             : {
     291          23 :     return m_nCurOff;
     292             : }
     293             : 
     294             : /************************************************************************/
     295             : /*                                Read()                                */
     296             : /************************************************************************/
     297             : 
     298         783 : size_t VSIStdinHandle::Read(void *pBuffer, size_t nSize, size_t nCount)
     299             : 
     300             : {
     301         783 :     VSIStdinInit();
     302             : 
     303         783 :     const size_t nBytesToRead = nSize * nCount;
     304         783 :     if (nBytesToRead == 0)
     305           0 :         return 0;
     306             : 
     307         783 :     if (m_nCurOff < gnRealPos && gnRealPos >= gnBufferLimit &&
     308           5 :         m_nCurOff + nBytesToRead > gnBufferLimit)
     309             :     {
     310           1 :         CPLError(CE_Failure, CPLE_NotSupported,
     311             :                  "Backward Seek() unsupported on /vsistdin beyond "
     312             :                  "maximum buffer limit (" CPL_FRMT_GUIB " bytes).\n"
     313             :                  "This limit can be extended by setting the "
     314             :                  "CPL_VSISTDIN_BUFFER_LIMIT "
     315             :                  "configuration option to a number of bytes, or by using the "
     316             :                  "'/vsistdin?buffer_limit=number_of_bytes' filename.\n"
     317             :                  "A limit of -1 means unlimited.",
     318             :                  static_cast<GUIntBig>(gnBufferLimit));
     319           1 :         return 0;
     320             :     }
     321             : 
     322         782 :     if (m_nCurOff < gnBufferLen)
     323             :     {
     324           7 :         const size_t nAlreadyCached =
     325           7 :             static_cast<size_t>(gnBufferLen - m_nCurOff);
     326           7 :         if (nBytesToRead <= nAlreadyCached)
     327             :         {
     328           5 :             memcpy(pBuffer, gpabyBuffer + static_cast<size_t>(m_nCurOff),
     329             :                    nBytesToRead);
     330           5 :             m_nCurOff += nBytesToRead;
     331           5 :             return nCount;
     332             :         }
     333             : 
     334           2 :         memcpy(pBuffer, gpabyBuffer + static_cast<size_t>(m_nCurOff),
     335             :                nAlreadyCached);
     336           2 :         m_nCurOff += nAlreadyCached;
     337             : 
     338             :         const size_t nRead =
     339           2 :             ReadAndCache(static_cast<GByte *>(pBuffer) + nAlreadyCached,
     340             :                          nBytesToRead - nAlreadyCached);
     341           2 :         m_bEOF = nRead < nBytesToRead - nAlreadyCached;
     342             : 
     343           2 :         return (nRead + nAlreadyCached) / nSize;
     344             :     }
     345             : 
     346         775 :     const size_t nRead = ReadAndCache(pBuffer, nBytesToRead);
     347         775 :     m_bEOF = nRead < nBytesToRead;
     348         775 :     return nRead / nSize;
     349             : }
     350             : 
     351             : /************************************************************************/
     352             : /*                               Write()                                */
     353             : /************************************************************************/
     354             : 
     355           0 : size_t VSIStdinHandle::Write(const void * /* pBuffer */, size_t /* nSize */,
     356             :                              size_t /* nCount */)
     357             : {
     358           0 :     CPLError(CE_Failure, CPLE_NotSupported, "Write() unsupported on /vsistdin");
     359           0 :     return 0;
     360             : }
     361             : 
     362             : /************************************************************************/
     363             : /*                                Eof()                                 */
     364             : /************************************************************************/
     365             : 
     366         514 : int VSIStdinHandle::Eof()
     367             : 
     368             : {
     369         514 :     return m_bEOF;
     370             : }
     371             : 
     372             : /************************************************************************/
     373             : /*                               Close()                                */
     374             : /************************************************************************/
     375             : 
     376          16 : int VSIStdinHandle::Close()
     377             : 
     378             : {
     379          22 :     if (!gosStdinFilename.empty() &&
     380           6 :         CPLTestBool(CPLGetConfigOption("CPL_VSISTDIN_FILE_CLOSE", "NO")))
     381             :     {
     382           6 :         if (gStdinFile != stdin)
     383           6 :             fclose(gStdinFile);
     384           6 :         gStdinFile = stdin;
     385           6 :         gosStdinFilename.clear();
     386           6 :         gnRealPos = ftell(stdin);
     387           6 :         gnBufferLen = 0;
     388           6 :         gbHasSoughtToEnd = false;
     389           6 :         gnFileSize = 0;
     390             :     }
     391          16 :     return 0;
     392             : }
     393             : 
     394             : /************************************************************************/
     395             : /* ==================================================================== */
     396             : /*                       VSIStdinFilesystemHandler                     */
     397             : /* ==================================================================== */
     398             : /************************************************************************/
     399             : 
     400             : /************************************************************************/
     401             : /*                        VSIStdinFilesystemHandler()                   */
     402             : /************************************************************************/
     403             : 
     404        1225 : VSIStdinFilesystemHandler::VSIStdinFilesystemHandler()
     405             : {
     406        1225 : }
     407             : 
     408             : /************************************************************************/
     409             : /*                       ~VSIStdinFilesystemHandler()                   */
     410             : /************************************************************************/
     411             : 
     412        1698 : VSIStdinFilesystemHandler::~VSIStdinFilesystemHandler()
     413             : {
     414         849 :     if (gStdinFile != stdin)
     415           0 :         fclose(gStdinFile);
     416         849 :     gStdinFile = stdin;
     417         849 :     CPLFree(gpabyBuffer);
     418         849 :     gpabyBuffer = nullptr;
     419         849 :     gnBufferLimit = 0;
     420         849 :     gnBufferAlloc = 0;
     421         849 :     gnBufferLen = 0;
     422         849 :     gnRealPos = 0;
     423         849 :     gosStdinFilename.clear();
     424        1698 : }
     425             : 
     426             : /************************************************************************/
     427             : /*                           GetBufferLimit()                           */
     428             : /************************************************************************/
     429             : 
     430          20 : static size_t GetBufferLimit(const char *pszBufferLimit)
     431             : {
     432             :     uint64_t nVal =
     433          20 :         static_cast<uint64_t>(std::strtoull(pszBufferLimit, nullptr, 10));
     434             : 
     435             :     // -1 because on 64-bit builds with size_t==uint64_t, a static analyzer
     436             :     // could complain that the ending nVal > MAX_BUFFER_LIMIT test is always
     437             :     // false
     438          20 :     constexpr size_t MAX_BUFFER_LIMIT = std::numeric_limits<size_t>::max() - 1;
     439          20 :     if (strstr(pszBufferLimit, "MB") != nullptr)
     440             :     {
     441           1 :         constexpr size_t ONE_MB = 1024 * 1024;
     442           1 :         if (nVal > MAX_BUFFER_LIMIT / ONE_MB)
     443             :         {
     444           0 :             nVal = MAX_BUFFER_LIMIT;
     445             :         }
     446             :         else
     447             :         {
     448           1 :             nVal *= ONE_MB;
     449             :         }
     450             :     }
     451          19 :     else if (strstr(pszBufferLimit, "GB") != nullptr)
     452             :     {
     453           1 :         constexpr size_t ONE_GB = 1024 * 1024 * 1024;
     454           1 :         if (nVal > MAX_BUFFER_LIMIT / ONE_GB)
     455             :         {
     456           0 :             nVal = MAX_BUFFER_LIMIT;
     457             :         }
     458             :         else
     459             :         {
     460           1 :             nVal *= ONE_GB;
     461             :         }
     462             :     }
     463          20 :     if (nVal > MAX_BUFFER_LIMIT)
     464             :     {
     465           5 :         nVal = MAX_BUFFER_LIMIT;
     466             :     }
     467          20 :     return static_cast<size_t>(nVal);
     468             : }
     469             : 
     470             : /************************************************************************/
     471             : /*                           ParseFilename()                            */
     472             : /************************************************************************/
     473             : 
     474         120 : static bool ParseFilename(const char *pszFilename)
     475             : {
     476         120 :     if (!(EQUAL(pszFilename, "/vsistdin/") ||
     477         116 :           ((STARTS_WITH(pszFilename, "/vsistdin/?") ||
     478         116 :             STARTS_WITH(pszFilename, "/vsistdin?")) &&
     479           8 :            strchr(pszFilename, '.') == nullptr)))
     480             :     {
     481         108 :         return false;
     482             :     }
     483             : 
     484          12 :     if (!CPLTestBool(CPLGetConfigOption("CPL_ALLOW_VSISTDIN", "YES")))
     485             :     {
     486           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     487             :                  "/vsistdin/ disabled. Set CPL_ALLOW_VSISTDIN to YES to "
     488             :                  "enable it");
     489           0 :         return false;
     490             :     }
     491             : 
     492             :     const char *pszBufferLimit =
     493          12 :         CPLGetConfigOption("CPL_VSISTDIN_BUFFER_LIMIT", "1048576");
     494          12 :     size_t nBufferLimit = GetBufferLimit(pszBufferLimit);
     495             : 
     496          12 :     pszFilename += strlen("/vsistdin/");
     497          12 :     if (*pszFilename == '?')
     498           0 :         pszFilename++;
     499          12 :     char **papszTokens = CSLTokenizeString2(pszFilename, "&", 0);
     500          20 :     for (int i = 0; papszTokens[i] != nullptr; i++)
     501             :     {
     502             :         char *pszUnescaped =
     503           8 :             CPLUnescapeString(papszTokens[i], nullptr, CPLES_URL);
     504           8 :         CPLFree(papszTokens[i]);
     505           8 :         papszTokens[i] = pszUnescaped;
     506             :     }
     507             : 
     508          20 :     for (int i = 0; papszTokens[i]; i++)
     509             :     {
     510           8 :         char *pszKey = nullptr;
     511           8 :         const char *pszValue = CPLParseNameValue(papszTokens[i], &pszKey);
     512           8 :         if (pszKey && pszValue)
     513             :         {
     514           8 :             if (EQUAL(pszKey, "buffer_limit"))
     515             :             {
     516           8 :                 nBufferLimit = GetBufferLimit(pszValue);
     517             :             }
     518             :             else
     519             :             {
     520           0 :                 CPLError(CE_Warning, CPLE_NotSupported,
     521             :                          "Unsupported option: %s", pszKey);
     522             :             }
     523             :         }
     524           8 :         CPLFree(pszKey);
     525             :     }
     526             : 
     527          12 :     CSLDestroy(papszTokens);
     528             : 
     529             :     // For testing purposes
     530             :     const char *pszStdinFilename =
     531          12 :         CPLGetConfigOption("CPL_VSISTDIN_FILE", "stdin");
     532          12 :     if (EQUAL(pszStdinFilename, "stdin"))
     533             :     {
     534           4 :         if (!gosStdinFilename.empty())
     535             :         {
     536           0 :             if (gStdinFile != stdin)
     537           0 :                 fclose(gStdinFile);
     538           0 :             gStdinFile = stdin;
     539           0 :             gosStdinFilename.clear();
     540           0 :             gnRealPos = ftell(stdin);
     541           0 :             gnBufferLen = 0;
     542           0 :             gbHasSoughtToEnd = false;
     543           0 :             gnFileSize = 0;
     544             :         }
     545             :     }
     546             :     else
     547             :     {
     548           8 :         bool bReset = false;
     549           8 :         if (gosStdinFilename != pszStdinFilename)
     550             :         {
     551           6 :             if (gStdinFile != stdin)
     552           0 :                 fclose(gStdinFile);
     553           6 :             gStdinFile = fopen(pszStdinFilename, "rb");
     554           6 :             if (gStdinFile == nullptr)
     555             :             {
     556           0 :                 gStdinFile = stdin;
     557           0 :                 return false;
     558             :             }
     559           6 :             gosStdinFilename = pszStdinFilename;
     560           6 :             bReset = true;
     561             :         }
     562             :         else
     563             :         {
     564           2 :             bReset = CPLTestBool(
     565             :                 CPLGetConfigOption("CPL_VSISTDIN_RESET_POSITION", "NO"));
     566             :         }
     567           8 :         if (bReset)
     568             :         {
     569           8 :             gnBufferLimit = 0;
     570           8 :             gnBufferLen = 0;
     571           8 :             gnRealPos = 0;
     572           8 :             gbHasSoughtToEnd = false;
     573           8 :             gnFileSize = 0;
     574             :         }
     575             :     }
     576             : 
     577          12 :     gnBufferLimit = std::max(gnBufferLimit, nBufferLimit);
     578             : 
     579          12 :     return true;
     580             : }
     581             : 
     582             : /************************************************************************/
     583             : /*                                Open()                                */
     584             : /************************************************************************/
     585             : 
     586             : VSIVirtualHandle *
     587          33 : VSIStdinFilesystemHandler::Open(const char *pszFilename, const char *pszAccess,
     588             :                                 bool /* bSetError */,
     589             :                                 CSLConstList /* papszOptions */)
     590             : 
     591             : {
     592          33 :     if (!ParseFilename(pszFilename))
     593             :     {
     594          23 :         return nullptr;
     595             :     }
     596             : 
     597          10 :     if (strchr(pszAccess, 'w') != nullptr || strchr(pszAccess, '+') != nullptr)
     598             :     {
     599           1 :         CPLError(CE_Failure, CPLE_NotSupported,
     600             :                  "Write or update mode not supported on /vsistdin");
     601           1 :         return nullptr;
     602             :     }
     603             : 
     604           9 :     return new VSIStdinHandle();
     605             : }
     606             : 
     607             : /************************************************************************/
     608             : /*                                Stat()                                */
     609             : /************************************************************************/
     610             : 
     611          87 : int VSIStdinFilesystemHandler::Stat(const char *pszFilename,
     612             :                                     VSIStatBufL *pStatBuf, int nFlags)
     613             : 
     614             : {
     615          87 :     memset(pStatBuf, 0, sizeof(VSIStatBufL));
     616             : 
     617          87 :     if (!ParseFilename(pszFilename))
     618             :     {
     619          85 :         return -1;
     620             :     }
     621             : 
     622           2 :     if (nFlags & VSI_STAT_SIZE_FLAG)
     623             :     {
     624           2 :         if (gbHasSoughtToEnd)
     625           0 :             pStatBuf->st_size = gnFileSize;
     626             :         else
     627             :         {
     628           2 :             auto handle = Open(pszFilename, "rb", false, nullptr);
     629           2 :             if (handle == nullptr)
     630           0 :                 return -1;
     631           2 :             handle->Seek(0, SEEK_END);
     632           2 :             pStatBuf->st_size = handle->Tell();
     633           2 :             delete handle;
     634             :         }
     635             :     }
     636             : 
     637           2 :     pStatBuf->st_mode = S_IFREG;
     638           2 :     return 0;
     639             : }
     640             : 
     641             : //! @endcond
     642             : 
     643             : /************************************************************************/
     644             : /*                       VSIInstallStdinHandler()                       */
     645             : /************************************************************************/
     646             : 
     647             : /*!
     648             :  \brief Install /vsistdin/ file system handler
     649             : 
     650             :  A special file handler is installed that allows reading from the standard
     651             :  input stream.
     652             : 
     653             :  The file operations available are of course limited to Read() and
     654             :  forward Seek() (full seek in the first MB of a file by default).
     655             : 
     656             :  Starting with GDAL 3.6, this limit can be configured either by setting
     657             :  the CPL_VSISTDIN_BUFFER_LIMIT configuration option to a number of bytes
     658             :  (can be -1 for unlimited), or using the "/vsistdin?buffer_limit=value"
     659             :  filename.
     660             : 
     661             :  \verbatim embed:rst
     662             :  See :ref:`/vsistdin/ documentation <vsistdin>`
     663             :  \endverbatim
     664             : 
     665             :  @since GDAL 1.8.0
     666             :  */
     667        1225 : void VSIInstallStdinHandler()
     668             : 
     669             : {
     670        1225 :     auto poHandler = new VSIStdinFilesystemHandler;
     671        1225 :     VSIFileManager::InstallHandler("/vsistdin/", poHandler);
     672        1225 :     VSIFileManager::InstallHandler("/vsistdin?", poHandler);
     673        1225 : }

Generated by: LCOV version 1.14