LCOV - code coverage report
Current view: top level - frmts/gtiff - tifvsi.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 255 268 95.1 %
Date: 2026-01-09 20:32:01 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     3523800 : static void SetActiveGTH(GDALTiffHandle *psGTH)
      91             : {
      92     3523800 :     auto psShared = psGTH->psShared;
      93     3523800 :     if (psShared->psActiveHandle != psGTH)
      94             :     {
      95       17435 :         if (psShared->psActiveHandle != nullptr)
      96             :         {
      97       15658 :             GTHFlushBuffer(static_cast<thandle_t>(psShared->psActiveHandle));
      98             :         }
      99       17435 :         psShared->psActiveHandle = psGTH;
     100             :     }
     101     3523800 : }
     102             : 
     103         275 : void *VSI_TIFFGetCachedRange(thandle_t th, vsi_l_offset nOffset, size_t nSize)
     104             : {
     105         275 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     106         329 :     for (int i = 0; i < psGTH->nCachedRanges; i++)
     107             :     {
     108         329 :         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          78 :         if (nOffset < psGTH->panCachedOffsets[i])
     116          24 :             break;
     117             :     }
     118          24 :     return nullptr;
     119             : }
     120             : 
     121     2744680 : static tsize_t _tiffReadProc(thandle_t th, tdata_t buf, tsize_t size)
     122             : {
     123     2744680 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     124             :     // SetActiveGTH(psGTH);
     125             : 
     126     2744680 :     if (psGTH->nCachedRanges)
     127             :     {
     128          35 :         const vsi_l_offset nCurOffset = VSIFTellL(psGTH->psShared->fpL);
     129             :         void *data =
     130          35 :             VSI_TIFFGetCachedRange(th, nCurOffset, static_cast<size_t>(size));
     131          35 :         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     2744660 :     return VSIFReadL(buf, 1, size, psGTH->psShared->fpL);
     144             : }
     145             : 
     146     2749080 : static bool GTHFlushBuffer(thandle_t th)
     147             : {
     148     2749080 :     GDALTiffHandle *psGTH = static_cast<GDALTiffHandle *>(th);
     149     2749080 :     bool bRet = true;
     150     2749080 :     if (psGTH->abyWriteBuffer && psGTH->nWriteBufferSize)
     151             :     {
     152             :         const tsize_t nRet =
     153       22644 :             VSIFWriteL(psGTH->abyWriteBuffer, 1, psGTH->nWriteBufferSize,
     154       11322 :                        psGTH->psShared->fpL);
     155       11322 :         bRet = nRet == psGTH->nWriteBufferSize;
     156       11322 :         if (!bRet)
     157             :         {
     158           0 :             TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
     159             :         }
     160       11322 :         psGTH->nWriteBufferSize = 0;
     161             :     }
     162     2749080 :     return bRet;
     163             : }
     164             : 
     165      470621 : static tsize_t _tiffWriteProc(thandle_t th, tdata_t buf, tsize_t size)
     166             : {
     167      470621 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     168      470621 :     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      470621 :     if (psGTH->psShared->bAtEndOfFile && psGTH->abyWriteBuffer)
     173             :     {
     174       93122 :         const GByte *pabyData = reinterpret_cast<GByte *>(buf);
     175       93122 :         tsize_t nRemainingBytes = size;
     176             :         while (true)
     177             :         {
     178       97915 :             if (psGTH->nWriteBufferSize + nRemainingBytes <= BUFFER_SIZE)
     179             :             {
     180       93122 :                 memcpy(psGTH->abyWriteBuffer + psGTH->nWriteBufferSize,
     181             :                        pabyData, nRemainingBytes);
     182       93122 :                 psGTH->nWriteBufferSize += static_cast<int>(nRemainingBytes);
     183       93122 :                 if (psGTH->psShared->bAtEndOfFile)
     184             :                 {
     185       93122 :                     psGTH->psShared->nFileLength += size;
     186             :                 }
     187       93122 :                 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      377499 :     const tsize_t nRet = VSIFWriteL(buf, 1, size, psGTH->psShared->fpL);
     208      377499 :     if (nRet < size)
     209             :     {
     210          76 :         TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
     211             :     }
     212             : 
     213      377499 :     if (psGTH->psShared->bAtEndOfFile)
     214             :     {
     215      148628 :         psGTH->psShared->nFileLength += nRet;
     216             :     }
     217      377499 :     return nRet;
     218             : }
     219             : 
     220     2930920 : static toff_t _tiffSeekProc(thandle_t th, toff_t off, int whence)
     221             : {
     222     2930920 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     223     2930920 :     SetActiveGTH(psGTH);
     224             : 
     225             :     // Optimization: if we are already at end, then no need to
     226             :     // issue a VSIFSeekL().
     227     2930920 :     if (whence == SEEK_END)
     228             :     {
     229      274248 :         if (psGTH->psShared->bAtEndOfFile)
     230             :         {
     231      212863 :             return static_cast<toff_t>(psGTH->psShared->nFileLength);
     232             :         }
     233             : 
     234       61385 :         if (VSIFSeekL(psGTH->psShared->fpL, static_cast<vsi_l_offset>(off),
     235       61385 :                       whence) != 0)
     236             :         {
     237           0 :             TIFFErrorExt(th, "_tiffSeekProc", "%s", VSIStrerror(errno));
     238           0 :             return static_cast<toff_t>(-1);
     239             :         }
     240       61385 :         psGTH->psShared->bAtEndOfFile = true;
     241       61385 :         psGTH->psShared->nFileLength = VSIFTellL(psGTH->psShared->fpL);
     242       61385 :         return static_cast<toff_t>(psGTH->psShared->nFileLength);
     243             :     }
     244             : 
     245     2656680 :     GTHFlushBuffer(th);
     246     2656680 :     psGTH->psShared->bAtEndOfFile = false;
     247     2656680 :     psGTH->psShared->nFileLength = 0;
     248             : 
     249     2656680 :     if (VSIFSeekL(psGTH->psShared->fpL, static_cast<vsi_l_offset>(off),
     250     2656680 :                   whence) == 0)
     251             :     {
     252     2656680 :         return static_cast<toff_t>(VSIFTellL(psGTH->psShared->fpL));
     253             :     }
     254             :     else
     255             :     {
     256           0 :         TIFFErrorExt(th, "_tiffSeekProc", "%s", VSIStrerror(errno));
     257           0 :         return static_cast<toff_t>(-1);
     258             :     }
     259             : }
     260             : 
     261       70261 : static void FreeGTH(GDALTiffHandle *psGTH)
     262             : {
     263       70261 :     psGTH->psShared->nUserCounter--;
     264       70261 :     if (psGTH->psParent == nullptr)
     265             :     {
     266       68484 :         assert(psGTH->psShared->nUserCounter == 0);
     267       68484 :         CPLFree(psGTH->psShared->pszName);
     268       68484 :         CPLFree(psGTH->psShared);
     269             :     }
     270             :     else
     271             :     {
     272        1777 :         if (psGTH->psShared->psActiveHandle == psGTH)
     273        1777 :             psGTH->psShared->psActiveHandle = nullptr;
     274             :     }
     275       70261 :     CPLFree(psGTH->abyWriteBuffer);
     276       70261 :     CPLFree(psGTH->ppCachedData);
     277       70261 :     CPLFree(psGTH->panCachedOffsets);
     278       70261 :     CPLFree(psGTH->panCachedSizes);
     279       70261 :     CPLFree(psGTH);
     280       70261 : }
     281             : 
     282       70256 : static int _tiffCloseProc(thandle_t th)
     283             : {
     284       70256 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     285       70256 :     SetActiveGTH(psGTH);
     286       70256 :     GTHFlushBuffer(th);
     287       70256 :     if (psGTH->bFree)
     288       70246 :         FreeGTH(psGTH);
     289       70256 :     return 0;
     290             : }
     291             : 
     292       37460 : static toff_t _tiffSizeProc(thandle_t th)
     293             : {
     294       37460 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     295       37460 :     SetActiveGTH(psGTH);
     296             : 
     297       37460 :     if (psGTH->psShared->bAtEndOfFile)
     298             :     {
     299       10818 :         return static_cast<toff_t>(psGTH->psShared->nFileLength);
     300             :     }
     301             : 
     302       26642 :     const vsi_l_offset old_off = VSIFTellL(psGTH->psShared->fpL);
     303       26642 :     CPL_IGNORE_RET_VAL(VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_END));
     304             : 
     305             :     const toff_t file_size =
     306       26642 :         static_cast<toff_t>(VSIFTellL(psGTH->psShared->fpL));
     307       26642 :     CPL_IGNORE_RET_VAL(VSIFSeekL(psGTH->psShared->fpL, old_off, SEEK_SET));
     308             : 
     309       26642 :     return file_size;
     310             : }
     311             : 
     312       27133 : static int _tiffMapProc(thandle_t th, tdata_t *pbase, toff_t *psize)
     313             : {
     314       27133 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     315             :     // SetActiveGTH(psGTH);
     316             : 
     317       27133 :     if (psGTH->pBase)
     318             :     {
     319           8 :         *pbase = psGTH->pBase;
     320           8 :         *psize = static_cast<toff_t>(psGTH->nDataLength);
     321           8 :         return 1;
     322             :     }
     323       27125 :     return 0;
     324             : }
     325             : 
     326           8 : static void _tiffUnmapProc(thandle_t /* th */, tdata_t /* base */,
     327             :                            toff_t /* size */)
     328             : {
     329           8 : }
     330             : 
     331        6265 : VSILFILE *VSI_TIFFGetVSILFile(thandle_t th)
     332             : {
     333        6265 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     334        6265 :     SetActiveGTH(psGTH);
     335        6265 :     VSI_TIFFFlushBufferedWrite(th);
     336        6265 :     return psGTH->psShared->fpL;
     337             : }
     338             : 
     339        6491 : int VSI_TIFFFlushBufferedWrite(thandle_t th)
     340             : {
     341        6491 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     342        6491 :     SetActiveGTH(psGTH);
     343        6491 :     psGTH->psShared->bAtEndOfFile = false;
     344        6491 :     return GTHFlushBuffer(th);
     345             : }
     346             : 
     347         376 : int VSI_TIFFHasCachedRanges(thandle_t th)
     348             : {
     349         376 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     350         376 :     return psGTH->nCachedRanges != 0;
     351             : }
     352             : 
     353       25256 : toff_t VSI_TIFFSeek(TIFF *tif, toff_t off, int whence)
     354             : {
     355       25256 :     thandle_t th = TIFFClientdata(tif);
     356       25256 :     return _tiffSeekProc(th, off, whence);
     357             : }
     358             : 
     359       50209 : int VSI_TIFFWrite(TIFF *tif, const void *buffer, size_t buffersize)
     360             : {
     361       50209 :     thandle_t th = TIFFClientdata(tif);
     362       50209 :     return static_cast<size_t>(_tiffWriteProc(th, const_cast<tdata_t>(buffer),
     363       50209 :                                               buffersize)) == buffersize;
     364             : }
     365             : 
     366          84 : void VSI_TIFFSetCachedRanges(thandle_t th, int nRanges, void **ppData,
     367             :                              const vsi_l_offset *panOffsets,
     368             :                              const size_t *panSizes)
     369             : {
     370          84 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     371          84 :     psGTH->nCachedRanges = nRanges;
     372          84 :     if (nRanges)
     373             :     {
     374          42 :         psGTH->ppCachedData = static_cast<void **>(
     375          42 :             CPLRealloc(psGTH->ppCachedData, nRanges * sizeof(void *)));
     376          42 :         memcpy(psGTH->ppCachedData, ppData, nRanges * sizeof(void *));
     377             : 
     378          84 :         psGTH->panCachedOffsets = static_cast<vsi_l_offset *>(CPLRealloc(
     379          42 :             psGTH->panCachedOffsets, nRanges * sizeof(vsi_l_offset)));
     380          42 :         memcpy(psGTH->panCachedOffsets, panOffsets,
     381          42 :                nRanges * sizeof(vsi_l_offset));
     382             : 
     383          42 :         psGTH->panCachedSizes = static_cast<size_t *>(
     384          42 :             CPLRealloc(psGTH->panCachedSizes, nRanges * sizeof(size_t)));
     385          42 :         memcpy(psGTH->panCachedSizes, panSizes, nRanges * sizeof(size_t));
     386             :     }
     387          84 : }
     388             : 
     389       70262 : static bool IsReadOnly(const char *mode)
     390             : {
     391       70262 :     bool bReadOnly = true;
     392      286314 :     for (int i = 0; mode[i] != '\0'; i++)
     393             :     {
     394      216052 :         if (mode[i] == 'w' || mode[i] == '+' || mode[i] == 'a')
     395             :         {
     396       82205 :             bReadOnly = false;
     397             :         }
     398             :     }
     399       70262 :     return bReadOnly;
     400             : }
     401             : 
     402       70262 : static void InitializeWriteBuffer(GDALTiffHandle *psGTH, const char *pszMode)
     403             : {
     404             :     // No need to buffer on /vsimem/
     405       70262 :     const bool bReadOnly = IsReadOnly(pszMode);
     406       70262 :     bool bAllocBuffer = !bReadOnly;
     407       70262 :     if (STARTS_WITH(psGTH->psShared->pszName, "/vsimem/"))
     408             :     {
     409       60899 :         if (bReadOnly &&
     410       10832 :             CPLTestBool(CPLGetConfigOption("GTIFF_USE_MMAP", "NO")))
     411             :         {
     412           8 :             psGTH->nDataLength = 0;
     413           8 :             psGTH->pBase = VSIGetMemFileBuffer(psGTH->psShared->pszName,
     414             :                                                &psGTH->nDataLength, FALSE);
     415             :         }
     416       50067 :         bAllocBuffer = false;
     417             :     }
     418             : 
     419       70262 :     psGTH->abyWriteBuffer =
     420       70262 :         bAllocBuffer ? static_cast<GByte *>(VSIMalloc(BUFFER_SIZE)) : nullptr;
     421       70262 :     psGTH->nWriteBufferSize = 0;
     422       70262 : }
     423             : 
     424             : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
     425       70272 : static void VSI_TIFFSetOpenOptions(TIFFOpenOptions *opts)
     426             : {
     427       70272 :     TIFFOpenOptionsSetErrorHandlerExtR(opts, GTiffErrorHandlerExt, nullptr);
     428       70272 :     TIFFOpenOptionsSetWarningHandlerExtR(opts, GTiffWarningHandlerExt, nullptr);
     429             : #if defined(INTERNAL_LIBTIFF) || TIFFLIB_VERSION > 20230908
     430             :     // Read-once and stored in static storage otherwise affects
     431             :     // autotest/benchmark/test_gtiff.py::test_gtiff_byte
     432         689 :     static const GIntBig nMemLimit = []() -> GIntBig
     433             :     {
     434         689 :         if (const char *pszLimit =
     435         689 :                 CPLGetConfigOption("GTIFF_MAX_CUMULATED_MEM_USAGE", nullptr))
     436           0 :             return CPLAtoGIntBig(pszLimit);
     437             :         else
     438             :         {
     439         689 :             const auto nUsableRAM = CPLGetUsablePhysicalRAM();
     440         689 :             if (nUsableRAM > 0)
     441             :             {
     442             :                 // coverity[return_overflow]
     443         689 :                 return nUsableRAM / 10 * 9;
     444             :             }
     445             :             else
     446           0 :                 return 0;
     447             :         }
     448       70272 :     }();
     449       70272 :     if (nMemLimit > 0 && nMemLimit < std::numeric_limits<tmsize_t>::max())
     450             :     {
     451             :         //CPLDebug("GTiff", "TIFFOpenOptionsSetMaxCumulatedMemAlloc(%" PRIu64 ")",
     452             :         //         static_cast<uint64_t>(nMemLimit));
     453       70272 :         TIFFOpenOptionsSetMaxCumulatedMemAlloc(
     454             :             opts, static_cast<tmsize_t>(nMemLimit));
     455             :     }
     456             : #endif
     457       70272 : }
     458             : #endif
     459             : 
     460       70262 : static TIFF *VSI_TIFFOpen_common(GDALTiffHandle *psGTH, const char *pszMode)
     461             : {
     462       70262 :     InitializeWriteBuffer(psGTH, pszMode);
     463             : 
     464             : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
     465       70262 :     XTIFFInitialize();
     466       70262 :     TIFFOpenOptions *opts = TIFFOpenOptionsAlloc();
     467       70262 :     if (opts == nullptr)
     468             :     {
     469           0 :         FreeGTH(psGTH);
     470           0 :         return nullptr;
     471             :     }
     472       70262 :     VSI_TIFFSetOpenOptions(opts);
     473      140524 :     TIFF *tif = TIFFClientOpenExt(
     474       70262 :         psGTH->psShared->pszName, pszMode, reinterpret_cast<thandle_t>(psGTH),
     475             :         _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
     476             :         _tiffSizeProc, _tiffMapProc, _tiffUnmapProc, opts);
     477       70262 :     TIFFOpenOptionsFree(opts);
     478             : #else
     479             :     TIFF *tif = XTIFFClientOpen(
     480             :         psGTH->psShared->pszName, pszMode, reinterpret_cast<thandle_t>(psGTH),
     481             :         _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
     482             :         _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
     483             : #endif
     484       70262 :     if (tif == nullptr)
     485          15 :         FreeGTH(psGTH);
     486             : 
     487       70262 :     return tif;
     488             : }
     489             : 
     490             : // Open a TIFF file for read/writing.
     491       68485 : TIFF *VSI_TIFFOpen(const char *name, const char *mode, VSILFILE *fpL)
     492             : {
     493             : 
     494       68485 :     if (VSIFSeekL(fpL, 0, SEEK_SET) < 0)
     495           0 :         return nullptr;
     496             : 
     497             :     GDALTiffHandle *psGTH =
     498       68485 :         static_cast<GDALTiffHandle *>(CPLCalloc(1, sizeof(GDALTiffHandle)));
     499       68485 :     psGTH->bFree = true;
     500       68485 :     psGTH->psParent = nullptr;
     501       68485 :     psGTH->psShared = static_cast<GDALTiffHandleShared *>(
     502       68485 :         CPLCalloc(1, sizeof(GDALTiffHandleShared)));
     503       68485 :     psGTH->psShared->bReadOnly = (strchr(mode, '+') == nullptr);
     504       68485 :     psGTH->psShared->bLazyStrileLoading = (strchr(mode, 'D') != nullptr);
     505       68485 :     psGTH->psShared->pszName = CPLStrdup(name);
     506       68485 :     psGTH->psShared->fpL = fpL;
     507       68485 :     psGTH->psShared->psActiveHandle = psGTH;
     508       68485 :     psGTH->psShared->nFileLength = 0;
     509       68485 :     psGTH->psShared->bAtEndOfFile = false;
     510       68485 :     psGTH->psShared->nUserCounter = 1;
     511             : 
     512       68485 :     return VSI_TIFFOpen_common(psGTH, mode);
     513             : }
     514             : 
     515        1777 : TIFF *VSI_TIFFOpenChild(TIFF *parent)
     516             : {
     517             :     GDALTiffHandle *psGTHParent =
     518        1777 :         reinterpret_cast<GDALTiffHandle *>(TIFFClientdata(parent));
     519             : 
     520             :     GDALTiffHandle *psGTH =
     521        1777 :         static_cast<GDALTiffHandle *>(CPLCalloc(1, sizeof(GDALTiffHandle)));
     522        1777 :     psGTH->bFree = true;
     523        1777 :     psGTH->psParent = psGTHParent;
     524        1777 :     psGTH->psShared = psGTHParent->psShared;
     525        1777 :     psGTH->psShared->nUserCounter++;
     526             : 
     527        1777 :     SetActiveGTH(psGTH);
     528        1777 :     VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_SET);
     529        1777 :     psGTH->psShared->bAtEndOfFile = false;
     530             : 
     531        1777 :     const char *mode =
     532         876 :         psGTH->psShared->bReadOnly && psGTH->psShared->bLazyStrileLoading
     533        3554 :             ? "rDO"
     534        1802 :         : psGTH->psShared->bReadOnly          ? "r"
     535         901 :         : psGTH->psShared->bLazyStrileLoading ? "r+D"
     536             :                                               : "r+";
     537        1777 :     return VSI_TIFFOpen_common(psGTH, mode);
     538             : }
     539             : 
     540             : // Re-open a TIFF handle (seeking to the appropriate directory is then needed)
     541          10 : TIFF *VSI_TIFFReOpen(TIFF *tif)
     542             : {
     543          10 :     thandle_t th = TIFFClientdata(tif);
     544          10 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     545             : 
     546             :     // Disable freeing of psGTH in _tiffCloseProc(), which could be called
     547             :     // if XTIFFClientOpen() fails, or obviously by XTIFFClose()
     548          10 :     psGTH->bFree = false;
     549             : 
     550          10 :     const char *mode =
     551           0 :         psGTH->psShared->bReadOnly && psGTH->psShared->bLazyStrileLoading
     552          20 :             ? "rDO"
     553          20 :         : psGTH->psShared->bReadOnly          ? "r"
     554          10 :         : psGTH->psShared->bLazyStrileLoading ? "r+D"
     555             :                                               : "r+";
     556             : 
     557          10 :     SetActiveGTH(psGTH);
     558          10 :     VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_SET);
     559          10 :     psGTH->psShared->bAtEndOfFile = false;
     560             : 
     561             : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
     562          10 :     TIFF *newHandle = nullptr;
     563          10 :     TIFFOpenOptions *opts = TIFFOpenOptionsAlloc();
     564          10 :     if (opts != nullptr)
     565             :     {
     566          10 :         VSI_TIFFSetOpenOptions(opts);
     567          20 :         newHandle = TIFFClientOpenExt(
     568          10 :             psGTH->psShared->pszName, mode, reinterpret_cast<thandle_t>(psGTH),
     569             :             _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
     570             :             _tiffSizeProc, _tiffMapProc, _tiffUnmapProc, opts);
     571          10 :         TIFFOpenOptionsFree(opts);
     572             :     }
     573             : #else
     574             :     TIFF *newHandle = XTIFFClientOpen(
     575             :         psGTH->psShared->pszName, mode, reinterpret_cast<thandle_t>(psGTH),
     576             :         _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
     577             :         _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
     578             : #endif
     579          10 :     if (newHandle != nullptr)
     580          10 :         XTIFFClose(tif);
     581             : 
     582          10 :     psGTH->bFree = true;
     583             : 
     584          10 :     return newHandle;
     585             : }

Generated by: LCOV version 1.14