LCOV - code coverage report
Current view: top level - frmts/gtiff - tifvsi.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 251 266 94.4 %
Date: 2025-09-10 17:48:50 Functions: 25 25 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GeoTIFF Driver
       4             :  * Purpose:  Implement system hook functions for libtiff on top of CPL/VSI,
       5             :  *           including > 2GB support.  Based on tif_unix.c from libtiff
       6             :  *           distribution.
       7             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       8             :  *
       9             :  ******************************************************************************
      10             :  * Copyright (c) 2005, Frank Warmerdam, warmerdam@pobox.com
      11             :  * Copyright (c) 2010-2012, Even Rouault <even dot rouault at spatialys.com>
      12             :  *
      13             :  * SPDX-License-Identifier: MIT
      14             :  ****************************************************************************/
      15             : 
      16             : // TIFF Library UNIX-specific Routines.
      17             : 
      18             : #include "cpl_port.h"
      19             : #include "tifvsi.h"
      20             : 
      21             : #include <assert.h>
      22             : #include <string.h>
      23             : #include <cerrno>
      24             : 
      25             : #include "cpl_conv.h"
      26             : #include "cpl_vsi.h"
      27             : #include "cpl_string.h"
      28             : 
      29             : // We avoid including xtiffio.h since it drags in the libgeotiff version
      30             : // of the VSI functions.
      31             : 
      32             : #ifdef RENAME_INTERNAL_LIBGEOTIFF_SYMBOLS
      33             : #include "gdal_libgeotiff_symbol_rename.h"
      34             : #endif
      35             : 
      36             : #include "xtiffio.h"
      37             : 
      38             : #include <limits>
      39             : 
      40             : #if (TIFFLIB_VERSION > 20220520) || defined(INTERNAL_LIBTIFF)  // > 4.4.0
      41             : #define SUPPORTS_LIBTIFF_OPEN_OPTIONS
      42             : 
      43             : extern int GTiffWarningHandlerExt(TIFF *tif, void *user_data,
      44             :                                   const char *module, const char *fmt,
      45             :                                   va_list ap);
      46             : extern int GTiffErrorHandlerExt(TIFF *tif, void *user_data, const char *module,
      47             :                                 const char *fmt, va_list ap);
      48             : 
      49             : #endif
      50             : 
      51             : constexpr int BUFFER_SIZE = 65536;
      52             : 
      53             : struct GDALTiffHandle;
      54             : 
      55             : struct GDALTiffHandleShared
      56             : {
      57             :     VSILFILE *fpL;
      58             :     bool bReadOnly;
      59             :     bool bLazyStrileLoading;
      60             :     char *pszName;
      61             :     GDALTiffHandle *psActiveHandle;  // only used on the parent
      62             :     int nUserCounter;
      63             :     bool bAtEndOfFile;
      64             :     vsi_l_offset nFileLength;
      65             : };
      66             : 
      67             : struct GDALTiffHandle
      68             : {
      69             :     bool bFree;
      70             : 
      71             :     GDALTiffHandle *psParent;  // nullptr for the parent itself
      72             :     GDALTiffHandleShared *psShared;
      73             : 
      74             :     GByte *abyWriteBuffer;
      75             :     int nWriteBufferSize;
      76             : 
      77             :     // For pseudo-mmap'ed /vsimem/ file
      78             :     vsi_l_offset nDataLength;
      79             :     void *pBase;
      80             : 
      81             :     // If we pre-cached data (typically from /vsicurl/ )
      82             :     int nCachedRanges;
      83             :     void **ppCachedData;
      84             :     vsi_l_offset *panCachedOffsets;
      85             :     size_t *panCachedSizes;
      86             : };
      87             : 
      88             : static bool GTHFlushBuffer(thandle_t th);
      89             : 
      90     3478600 : static void SetActiveGTH(GDALTiffHandle *psGTH)
      91             : {
      92     3478600 :     auto psShared = psGTH->psShared;
      93     3478600 :     if (psShared->psActiveHandle != psGTH)
      94             :     {
      95       17543 :         if (psShared->psActiveHandle != nullptr)
      96             :         {
      97       15742 :             GTHFlushBuffer(static_cast<thandle_t>(psShared->psActiveHandle));
      98             :         }
      99       17544 :         psShared->psActiveHandle = psGTH;
     100             :     }
     101     3478600 : }
     102             : 
     103         251 : void *VSI_TIFFGetCachedRange(thandle_t th, vsi_l_offset nOffset, size_t nSize)
     104             : {
     105         251 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     106         305 :     for (int i = 0; i < psGTH->nCachedRanges; i++)
     107             :     {
     108         305 :         if (nOffset >= psGTH->panCachedOffsets[i] &&
     109         305 :             nOffset + nSize <=
     110         305 :                 psGTH->panCachedOffsets[i] + psGTH->panCachedSizes[i])
     111             :         {
     112         251 :             return static_cast<GByte *>(psGTH->ppCachedData[i]) +
     113         251 :                    (nOffset - psGTH->panCachedOffsets[i]);
     114             :         }
     115          54 :         if (nOffset < psGTH->panCachedOffsets[i])
     116           0 :             break;
     117             :     }
     118           0 :     return nullptr;
     119             : }
     120             : 
     121     2724590 : static tsize_t _tiffReadProc(thandle_t th, tdata_t buf, tsize_t size)
     122             : {
     123     2724590 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     124             :     // SetActiveGTH(psGTH);
     125             : 
     126     2724590 :     if (psGTH->nCachedRanges)
     127             :     {
     128          11 :         const vsi_l_offset nCurOffset = VSIFTellL(psGTH->psShared->fpL);
     129             :         void *data =
     130          11 :             VSI_TIFFGetCachedRange(th, nCurOffset, static_cast<size_t>(size));
     131          11 :         if (data)
     132             :         {
     133          11 :             memcpy(buf, data, size);
     134          11 :             VSIFSeekL(psGTH->psShared->fpL, nCurOffset + size, SEEK_SET);
     135          11 :             return size;
     136             :         }
     137             :     }
     138             : 
     139             : #ifdef DEBUG_VERBOSE_EXTRA
     140             :     CPLDebug("GTiff", "Reading %d bytes at offset " CPL_FRMT_GUIB,
     141             :              static_cast<int>(size), VSIFTellL(psGTH->psShared->fpL));
     142             : #endif
     143     2724580 :     return VSIFReadL(buf, 1, size, psGTH->psShared->fpL);
     144             : }
     145             : 
     146     2732600 : static bool GTHFlushBuffer(thandle_t th)
     147             : {
     148     2732600 :     GDALTiffHandle *psGTH = static_cast<GDALTiffHandle *>(th);
     149     2732600 :     bool bRet = true;
     150     2732600 :     if (psGTH->abyWriteBuffer && psGTH->nWriteBufferSize)
     151             :     {
     152             :         const tsize_t nRet =
     153       22468 :             VSIFWriteL(psGTH->abyWriteBuffer, 1, psGTH->nWriteBufferSize,
     154       11234 :                        psGTH->psShared->fpL);
     155       11234 :         bRet = nRet == psGTH->nWriteBufferSize;
     156       11234 :         if (!bRet)
     157             :         {
     158           0 :             TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
     159             :         }
     160       11234 :         psGTH->nWriteBufferSize = 0;
     161             :     }
     162     2732600 :     return bRet;
     163             : }
     164             : 
     165      455859 : static tsize_t _tiffWriteProc(thandle_t th, tdata_t buf, tsize_t size)
     166             : {
     167      455859 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     168      455859 :     SetActiveGTH(psGTH);
     169             : 
     170             :     // If we have a write buffer and are at end of file, then accumulate
     171             :     // the bytes until the buffer is full.
     172      455828 :     if (psGTH->psShared->bAtEndOfFile && psGTH->abyWriteBuffer)
     173             :     {
     174       92970 :         const GByte *pabyData = reinterpret_cast<GByte *>(buf);
     175       92970 :         tsize_t nRemainingBytes = size;
     176             :         while (true)
     177             :         {
     178       97763 :             if (psGTH->nWriteBufferSize + nRemainingBytes <= BUFFER_SIZE)
     179             :             {
     180       92970 :                 memcpy(psGTH->abyWriteBuffer + psGTH->nWriteBufferSize,
     181             :                        pabyData, nRemainingBytes);
     182       92970 :                 psGTH->nWriteBufferSize += static_cast<int>(nRemainingBytes);
     183       92970 :                 if (psGTH->psShared->bAtEndOfFile)
     184             :                 {
     185       92970 :                     psGTH->psShared->nFileLength += size;
     186             :                 }
     187       92970 :                 return size;
     188             :             }
     189             : 
     190        4793 :             int nAppendable = BUFFER_SIZE - psGTH->nWriteBufferSize;
     191        4793 :             memcpy(psGTH->abyWriteBuffer + psGTH->nWriteBufferSize, pabyData,
     192             :                    nAppendable);
     193        9586 :             const tsize_t nRet = VSIFWriteL(psGTH->abyWriteBuffer, 1,
     194        4793 :                                             BUFFER_SIZE, psGTH->psShared->fpL);
     195        4793 :             psGTH->nWriteBufferSize = 0;
     196        4793 :             if (nRet != BUFFER_SIZE)
     197             :             {
     198           0 :                 TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
     199           0 :                 return 0;
     200             :             }
     201             : 
     202        4793 :             pabyData += nAppendable;
     203        4793 :             nRemainingBytes -= nAppendable;
     204        4793 :         }
     205             :     }
     206             : 
     207      362858 :     const tsize_t nRet = VSIFWriteL(buf, 1, size, psGTH->psShared->fpL);
     208      362881 :     if (nRet < size)
     209             :     {
     210          76 :         TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
     211             :     }
     212             : 
     213      362875 :     if (psGTH->psShared->bAtEndOfFile)
     214             :     {
     215      136292 :         psGTH->psShared->nFileLength += nRet;
     216             :     }
     217      362875 :     return nRet;
     218             : }
     219             : 
     220     2902200 : static toff_t _tiffSeekProc(thandle_t th, toff_t off, int whence)
     221             : {
     222     2902200 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     223     2902200 :     SetActiveGTH(psGTH);
     224             : 
     225             :     // Optimization: if we are already at end, then no need to
     226             :     // issue a VSIFSeekL().
     227     2902070 :     if (whence == SEEK_END)
     228             :     {
     229      261203 :         if (psGTH->psShared->bAtEndOfFile)
     230             :         {
     231      200508 :             return static_cast<toff_t>(psGTH->psShared->nFileLength);
     232             :         }
     233             : 
     234       60695 :         if (VSIFSeekL(psGTH->psShared->fpL, off, whence) != 0)
     235             :         {
     236           0 :             TIFFErrorExt(th, "_tiffSeekProc", "%s", VSIStrerror(errno));
     237           0 :             return static_cast<toff_t>(-1);
     238             :         }
     239       60692 :         psGTH->psShared->bAtEndOfFile = true;
     240       60692 :         psGTH->psShared->nFileLength = VSIFTellL(psGTH->psShared->fpL);
     241       60692 :         return static_cast<toff_t>(psGTH->psShared->nFileLength);
     242             :     }
     243             : 
     244     2640870 :     GTHFlushBuffer(th);
     245     2640890 :     psGTH->psShared->bAtEndOfFile = false;
     246     2640890 :     psGTH->psShared->nFileLength = 0;
     247             : 
     248     2640890 :     if (VSIFSeekL(psGTH->psShared->fpL, off, whence) == 0)
     249             :     {
     250     2641100 :         return static_cast<toff_t>(VSIFTellL(psGTH->psShared->fpL));
     251             :     }
     252             :     else
     253             :     {
     254           0 :         TIFFErrorExt(th, "_tiffSeekProc", "%s", VSIStrerror(errno));
     255           0 :         return static_cast<toff_t>(-1);
     256             :     }
     257             : }
     258             : 
     259       69569 : static void FreeGTH(GDALTiffHandle *psGTH)
     260             : {
     261       69569 :     psGTH->psShared->nUserCounter--;
     262       69569 :     if (psGTH->psParent == nullptr)
     263             :     {
     264       67768 :         assert(psGTH->psShared->nUserCounter == 0);
     265       67768 :         CPLFree(psGTH->psShared->pszName);
     266       67772 :         CPLFree(psGTH->psShared);
     267             :     }
     268             :     else
     269             :     {
     270        1801 :         if (psGTH->psShared->psActiveHandle == psGTH)
     271        1801 :             psGTH->psShared->psActiveHandle = nullptr;
     272             :     }
     273       69571 :     CPLFree(psGTH->abyWriteBuffer);
     274       69571 :     CPLFree(psGTH->ppCachedData);
     275       69572 :     CPLFree(psGTH->panCachedOffsets);
     276       69571 :     CPLFree(psGTH->panCachedSizes);
     277       69569 :     CPLFree(psGTH);
     278       69571 : }
     279             : 
     280       69567 : static int _tiffCloseProc(thandle_t th)
     281             : {
     282       69567 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     283       69567 :     SetActiveGTH(psGTH);
     284       69565 :     GTHFlushBuffer(th);
     285       69566 :     if (psGTH->bFree)
     286       69555 :         FreeGTH(psGTH);
     287       69563 :     return 0;
     288             : }
     289             : 
     290       36650 : static toff_t _tiffSizeProc(thandle_t th)
     291             : {
     292       36650 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     293       36650 :     SetActiveGTH(psGTH);
     294             : 
     295       36604 :     if (psGTH->psShared->bAtEndOfFile)
     296             :     {
     297       10600 :         return static_cast<toff_t>(psGTH->psShared->nFileLength);
     298             :     }
     299             : 
     300       26004 :     const vsi_l_offset old_off = VSIFTellL(psGTH->psShared->fpL);
     301       25929 :     CPL_IGNORE_RET_VAL(VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_END));
     302             : 
     303             :     const toff_t file_size =
     304       25977 :         static_cast<toff_t>(VSIFTellL(psGTH->psShared->fpL));
     305       25960 :     CPL_IGNORE_RET_VAL(VSIFSeekL(psGTH->psShared->fpL, old_off, SEEK_SET));
     306             : 
     307       25895 :     return file_size;
     308             : }
     309             : 
     310       26659 : static int _tiffMapProc(thandle_t th, tdata_t *pbase, toff_t *psize)
     311             : {
     312       26659 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     313             :     // SetActiveGTH(psGTH);
     314             : 
     315       26659 :     if (psGTH->pBase)
     316             :     {
     317           8 :         *pbase = psGTH->pBase;
     318           8 :         *psize = static_cast<toff_t>(psGTH->nDataLength);
     319           8 :         return 1;
     320             :     }
     321       26651 :     return 0;
     322             : }
     323             : 
     324           8 : static void _tiffUnmapProc(thandle_t /* th */, tdata_t /* base */,
     325             :                            toff_t /* size */)
     326             : {
     327           8 : }
     328             : 
     329        6197 : VSILFILE *VSI_TIFFGetVSILFile(thandle_t th)
     330             : {
     331        6197 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     332        6197 :     SetActiveGTH(psGTH);
     333        6197 :     VSI_TIFFFlushBufferedWrite(th);
     334        6197 :     return psGTH->psShared->fpL;
     335             : }
     336             : 
     337        6423 : int VSI_TIFFFlushBufferedWrite(thandle_t th)
     338             : {
     339        6423 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     340        6423 :     SetActiveGTH(psGTH);
     341        6423 :     psGTH->psShared->bAtEndOfFile = false;
     342        6423 :     return GTHFlushBuffer(th);
     343             : }
     344             : 
     345         376 : int VSI_TIFFHasCachedRanges(thandle_t th)
     346             : {
     347         376 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     348         376 :     return psGTH->nCachedRanges != 0;
     349             : }
     350             : 
     351       25213 : toff_t VSI_TIFFSeek(TIFF *tif, toff_t off, int whence)
     352             : {
     353       25213 :     thandle_t th = TIFFClientdata(tif);
     354       25213 :     return _tiffSeekProc(th, off, whence);
     355             : }
     356             : 
     357       50089 : int VSI_TIFFWrite(TIFF *tif, const void *buffer, size_t buffersize)
     358             : {
     359       50089 :     thandle_t th = TIFFClientdata(tif);
     360       50089 :     return static_cast<size_t>(_tiffWriteProc(th, const_cast<tdata_t>(buffer),
     361       50089 :                                               buffersize)) == buffersize;
     362             : }
     363             : 
     364          84 : void VSI_TIFFSetCachedRanges(thandle_t th, int nRanges, void **ppData,
     365             :                              const vsi_l_offset *panOffsets,
     366             :                              const size_t *panSizes)
     367             : {
     368          84 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     369          84 :     psGTH->nCachedRanges = nRanges;
     370          84 :     if (nRanges)
     371             :     {
     372          42 :         psGTH->ppCachedData = static_cast<void **>(
     373          42 :             CPLRealloc(psGTH->ppCachedData, nRanges * sizeof(void *)));
     374          42 :         memcpy(psGTH->ppCachedData, ppData, nRanges * sizeof(void *));
     375             : 
     376          84 :         psGTH->panCachedOffsets = static_cast<vsi_l_offset *>(CPLRealloc(
     377          42 :             psGTH->panCachedOffsets, nRanges * sizeof(vsi_l_offset)));
     378          42 :         memcpy(psGTH->panCachedOffsets, panOffsets,
     379          42 :                nRanges * sizeof(vsi_l_offset));
     380             : 
     381          42 :         psGTH->panCachedSizes = static_cast<size_t *>(
     382          42 :             CPLRealloc(psGTH->panCachedSizes, nRanges * sizeof(size_t)));
     383          42 :         memcpy(psGTH->panCachedSizes, panSizes, nRanges * sizeof(size_t));
     384             :     }
     385          84 : }
     386             : 
     387       69553 : static bool IsReadOnly(const char *mode)
     388             : {
     389       69553 :     bool bReadOnly = true;
     390      283139 :     for (int i = 0; mode[i] != '\0'; i++)
     391             :     {
     392      213586 :         if (mode[i] == 'w' || mode[i] == '+' || mode[i] == 'a')
     393             :         {
     394       81658 :             bReadOnly = false;
     395             :         }
     396             :     }
     397       69553 :     return bReadOnly;
     398             : }
     399             : 
     400       69564 : static void InitializeWriteBuffer(GDALTiffHandle *psGTH, const char *pszMode)
     401             : {
     402             :     // No need to buffer on /vsimem/
     403       69564 :     const bool bReadOnly = IsReadOnly(pszMode);
     404       69499 :     bool bAllocBuffer = !bReadOnly;
     405       69499 :     if (STARTS_WITH(psGTH->psShared->pszName, "/vsimem/"))
     406             :     {
     407       60503 :         if (bReadOnly &&
     408       10724 :             CPLTestBool(CPLGetConfigOption("GTIFF_USE_MMAP", "NO")))
     409             :         {
     410           8 :             psGTH->nDataLength = 0;
     411           8 :             psGTH->pBase = VSIGetMemFileBuffer(psGTH->psShared->pszName,
     412             :                                                &psGTH->nDataLength, FALSE);
     413             :         }
     414       49779 :         bAllocBuffer = false;
     415             :     }
     416             : 
     417       69504 :     psGTH->abyWriteBuffer =
     418       69504 :         bAllocBuffer ? static_cast<GByte *>(VSIMalloc(BUFFER_SIZE)) : nullptr;
     419       69504 :     psGTH->nWriteBufferSize = 0;
     420       69504 : }
     421             : 
     422             : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
     423       69520 : static void VSI_TIFFSetOpenOptions(TIFFOpenOptions *opts)
     424             : {
     425       69520 :     TIFFOpenOptionsSetErrorHandlerExtR(opts, GTiffErrorHandlerExt, nullptr);
     426       69500 :     TIFFOpenOptionsSetWarningHandlerExtR(opts, GTiffWarningHandlerExt, nullptr);
     427             : #if defined(INTERNAL_LIBTIFF) || TIFFLIB_VERSION > 20230908
     428             :     // Read-once and stored in static storage otherwise affects
     429             :     // autotest/benchmark/test_gtiff.py::test_gtiff_byte
     430         670 :     static const GIntBig nMemLimit = []() -> GIntBig
     431             :     {
     432         670 :         if (const char *pszLimit =
     433         670 :                 CPLGetConfigOption("GTIFF_MAX_CUMULATED_MEM_USAGE", nullptr))
     434           0 :             return CPLAtoGIntBig(pszLimit);
     435             :         else
     436             :         {
     437         670 :             const auto nUsableRAM = CPLGetUsablePhysicalRAM();
     438         670 :             if (nUsableRAM > 0)
     439             :             {
     440             :                 // coverity[return_overflow]
     441         670 :                 return nUsableRAM / 10 * 9;
     442             :             }
     443             :             else
     444           0 :                 return 0;
     445             :         }
     446       69470 :     }();
     447       69540 :     if (nMemLimit > 0 && nMemLimit < std::numeric_limits<tmsize_t>::max())
     448             :     {
     449             :         //CPLDebug("GTiff", "TIFFOpenOptionsSetMaxCumulatedMemAlloc(%" PRIu64 ")",
     450             :         //         static_cast<uint64_t>(nMemLimit));
     451       69519 :         TIFFOpenOptionsSetMaxCumulatedMemAlloc(
     452             :             opts, static_cast<tmsize_t>(nMemLimit));
     453             :     }
     454             : #endif
     455       69318 : }
     456             : #endif
     457             : 
     458       69528 : static TIFF *VSI_TIFFOpen_common(GDALTiffHandle *psGTH, const char *pszMode)
     459             : {
     460       69528 :     InitializeWriteBuffer(psGTH, pszMode);
     461             : 
     462             : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
     463       69488 :     XTIFFInitialize();
     464       69497 :     TIFFOpenOptions *opts = TIFFOpenOptionsAlloc();
     465       69450 :     if (opts == nullptr)
     466             :     {
     467           0 :         FreeGTH(psGTH);
     468           0 :         return nullptr;
     469             :     }
     470       69450 :     VSI_TIFFSetOpenOptions(opts);
     471      138872 :     TIFF *tif = TIFFClientOpenExt(
     472       69409 :         psGTH->psShared->pszName, pszMode, reinterpret_cast<thandle_t>(psGTH),
     473             :         _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
     474             :         _tiffSizeProc, _tiffMapProc, _tiffUnmapProc, opts);
     475       69463 :     TIFFOpenOptionsFree(opts);
     476             : #else
     477             :     TIFF *tif = XTIFFClientOpen(
     478             :         psGTH->psShared->pszName, pszMode, reinterpret_cast<thandle_t>(psGTH),
     479             :         _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
     480             :         _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
     481             : #endif
     482       69421 :     if (tif == nullptr)
     483          15 :         FreeGTH(psGTH);
     484             : 
     485       69367 :     return tif;
     486             : }
     487             : 
     488             : // Open a TIFF file for read/writing.
     489       67772 : TIFF *VSI_TIFFOpen(const char *name, const char *mode, VSILFILE *fpL)
     490             : {
     491             : 
     492       67772 :     if (VSIFSeekL(fpL, 0, SEEK_SET) < 0)
     493           0 :         return nullptr;
     494             : 
     495             :     GDALTiffHandle *psGTH =
     496       67768 :         static_cast<GDALTiffHandle *>(CPLCalloc(1, sizeof(GDALTiffHandle)));
     497       67763 :     psGTH->bFree = true;
     498       67763 :     psGTH->psParent = nullptr;
     499       67767 :     psGTH->psShared = static_cast<GDALTiffHandleShared *>(
     500       67763 :         CPLCalloc(1, sizeof(GDALTiffHandleShared)));
     501       67767 :     psGTH->psShared->bReadOnly = (strchr(mode, '+') == nullptr);
     502       67767 :     psGTH->psShared->bLazyStrileLoading = (strchr(mode, 'D') != nullptr);
     503       67767 :     psGTH->psShared->pszName = CPLStrdup(name);
     504       67741 :     psGTH->psShared->fpL = fpL;
     505       67741 :     psGTH->psShared->psActiveHandle = psGTH;
     506       67741 :     psGTH->psShared->nFileLength = 0;
     507       67741 :     psGTH->psShared->bAtEndOfFile = false;
     508       67741 :     psGTH->psShared->nUserCounter = 1;
     509             : 
     510       67741 :     return VSI_TIFFOpen_common(psGTH, mode);
     511             : }
     512             : 
     513        1801 : TIFF *VSI_TIFFOpenChild(TIFF *parent)
     514             : {
     515             :     GDALTiffHandle *psGTHParent =
     516        1801 :         reinterpret_cast<GDALTiffHandle *>(TIFFClientdata(parent));
     517             : 
     518             :     GDALTiffHandle *psGTH =
     519        1801 :         static_cast<GDALTiffHandle *>(CPLCalloc(1, sizeof(GDALTiffHandle)));
     520        1800 :     psGTH->bFree = true;
     521        1800 :     psGTH->psParent = psGTHParent;
     522        1800 :     psGTH->psShared = psGTHParent->psShared;
     523        1800 :     psGTH->psShared->nUserCounter++;
     524             : 
     525        1800 :     SetActiveGTH(psGTH);
     526        1801 :     VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_SET);
     527        1801 :     psGTH->psShared->bAtEndOfFile = false;
     528             : 
     529        1801 :     const char *mode =
     530         895 :         psGTH->psShared->bReadOnly && psGTH->psShared->bLazyStrileLoading
     531        3602 :             ? "rDO"
     532        1812 :         : psGTH->psShared->bReadOnly          ? "r"
     533         906 :         : psGTH->psShared->bLazyStrileLoading ? "r+D"
     534             :                                               : "r+";
     535        1801 :     return VSI_TIFFOpen_common(psGTH, mode);
     536             : }
     537             : 
     538             : // Re-open a TIFF handle (seeking to the appropriate directory is then needed)
     539           9 : TIFF *VSI_TIFFReOpen(TIFF *tif)
     540             : {
     541           9 :     thandle_t th = TIFFClientdata(tif);
     542           9 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     543             : 
     544             :     // Disable freeing of psGTH in _tiffCloseProc(), which could be called
     545             :     // if XTIFFClientOpen() fails, or obviously by XTIFFClose()
     546           9 :     psGTH->bFree = false;
     547             : 
     548           9 :     const char *mode =
     549           0 :         psGTH->psShared->bReadOnly && psGTH->psShared->bLazyStrileLoading
     550          18 :             ? "rDO"
     551          18 :         : psGTH->psShared->bReadOnly          ? "r"
     552           9 :         : psGTH->psShared->bLazyStrileLoading ? "r+D"
     553             :                                               : "r+";
     554             : 
     555           9 :     SetActiveGTH(psGTH);
     556           9 :     VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_SET);
     557           9 :     psGTH->psShared->bAtEndOfFile = false;
     558             : 
     559             : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
     560           9 :     TIFF *newHandle = nullptr;
     561           9 :     TIFFOpenOptions *opts = TIFFOpenOptionsAlloc();
     562           9 :     if (opts != nullptr)
     563             :     {
     564           9 :         VSI_TIFFSetOpenOptions(opts);
     565          18 :         newHandle = TIFFClientOpenExt(
     566           9 :             psGTH->psShared->pszName, mode, reinterpret_cast<thandle_t>(psGTH),
     567             :             _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
     568             :             _tiffSizeProc, _tiffMapProc, _tiffUnmapProc, opts);
     569           9 :         TIFFOpenOptionsFree(opts);
     570             :     }
     571             : #else
     572             :     TIFF *newHandle = XTIFFClientOpen(
     573             :         psGTH->psShared->pszName, mode, reinterpret_cast<thandle_t>(psGTH),
     574             :         _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
     575             :         _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
     576             : #endif
     577           9 :     if (newHandle != nullptr)
     578           9 :         XTIFFClose(tif);
     579             : 
     580           9 :     psGTH->bFree = true;
     581             : 
     582           9 :     return newHandle;
     583             : }

Generated by: LCOV version 1.14