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: 2024-11-21 22:18:42 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             : #if HAVE_FCNTL_H
      25             : #include <fcntl.h>
      26             : #endif
      27             : 
      28             : #include "cpl_conv.h"
      29             : #include "cpl_vsi.h"
      30             : #include "cpl_string.h"
      31             : 
      32             : // We avoid including xtiffio.h since it drags in the libgeotiff version
      33             : // of the VSI functions.
      34             : 
      35             : #ifdef RENAME_INTERNAL_LIBGEOTIFF_SYMBOLS
      36             : #include "gdal_libgeotiff_symbol_rename.h"
      37             : #endif
      38             : 
      39             : #include "xtiffio.h"
      40             : 
      41             : #include <limits>
      42             : 
      43             : #if (TIFFLIB_VERSION > 20220520) || defined(INTERNAL_LIBTIFF)  // > 4.4.0
      44             : #define SUPPORTS_LIBTIFF_OPEN_OPTIONS
      45             : 
      46             : extern int GTiffWarningHandlerExt(TIFF *tif, void *user_data,
      47             :                                   const char *module, const char *fmt,
      48             :                                   va_list ap);
      49             : extern int GTiffErrorHandlerExt(TIFF *tif, void *user_data, const char *module,
      50             :                                 const char *fmt, va_list ap);
      51             : 
      52             : #endif
      53             : 
      54             : constexpr int BUFFER_SIZE = 65536;
      55             : 
      56             : struct GDALTiffHandle;
      57             : 
      58             : struct GDALTiffHandleShared
      59             : {
      60             :     VSILFILE *fpL;
      61             :     bool bReadOnly;
      62             :     bool bLazyStrileLoading;
      63             :     char *pszName;
      64             :     GDALTiffHandle *psActiveHandle;  // only used on the parent
      65             :     int nUserCounter;
      66             :     bool bAtEndOfFile;
      67             :     vsi_l_offset nFileLength;
      68             : };
      69             : 
      70             : struct GDALTiffHandle
      71             : {
      72             :     bool bFree;
      73             : 
      74             :     GDALTiffHandle *psParent;  // nullptr for the parent itself
      75             :     GDALTiffHandleShared *psShared;
      76             : 
      77             :     GByte *abyWriteBuffer;
      78             :     int nWriteBufferSize;
      79             : 
      80             :     // For pseudo-mmap'ed /vsimem/ file
      81             :     vsi_l_offset nDataLength;
      82             :     void *pBase;
      83             : 
      84             :     // If we pre-cached data (typically from /vsicurl/ )
      85             :     int nCachedRanges;
      86             :     void **ppCachedData;
      87             :     vsi_l_offset *panCachedOffsets;
      88             :     size_t *panCachedSizes;
      89             : };
      90             : 
      91             : static bool GTHFlushBuffer(thandle_t th);
      92             : 
      93     3269940 : static void SetActiveGTH(GDALTiffHandle *psGTH)
      94             : {
      95     3269940 :     auto psShared = psGTH->psShared;
      96     3269940 :     if (psShared->psActiveHandle != psGTH)
      97             :     {
      98       16298 :         if (psShared->psActiveHandle != nullptr)
      99             :         {
     100       14736 :             GTHFlushBuffer(static_cast<thandle_t>(psShared->psActiveHandle));
     101             :         }
     102       16298 :         psShared->psActiveHandle = psGTH;
     103             :     }
     104     3269940 : }
     105             : 
     106         229 : void *VSI_TIFFGetCachedRange(thandle_t th, vsi_l_offset nOffset, size_t nSize)
     107             : {
     108         229 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     109         283 :     for (int i = 0; i < psGTH->nCachedRanges; i++)
     110             :     {
     111         283 :         if (nOffset >= psGTH->panCachedOffsets[i] &&
     112         283 :             nOffset + nSize <=
     113         283 :                 psGTH->panCachedOffsets[i] + psGTH->panCachedSizes[i])
     114             :         {
     115         229 :             return static_cast<GByte *>(psGTH->ppCachedData[i]) +
     116         229 :                    (nOffset - psGTH->panCachedOffsets[i]);
     117             :         }
     118          54 :         if (nOffset < psGTH->panCachedOffsets[i])
     119           0 :             break;
     120             :     }
     121           0 :     return nullptr;
     122             : }
     123             : 
     124     2608420 : static tsize_t _tiffReadProc(thandle_t th, tdata_t buf, tsize_t size)
     125             : {
     126     2608420 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     127             :     // SetActiveGTH(psGTH);
     128             : 
     129     2608420 :     if (psGTH->nCachedRanges)
     130             :     {
     131          11 :         const vsi_l_offset nCurOffset = VSIFTellL(psGTH->psShared->fpL);
     132             :         void *data =
     133          11 :             VSI_TIFFGetCachedRange(th, nCurOffset, static_cast<size_t>(size));
     134          11 :         if (data)
     135             :         {
     136          11 :             memcpy(buf, data, size);
     137          11 :             VSIFSeekL(psGTH->psShared->fpL, nCurOffset + size, SEEK_SET);
     138          11 :             return size;
     139             :         }
     140             :     }
     141             : 
     142             : #ifdef DEBUG_VERBOSE_EXTRA
     143             :     CPLDebug("GTiff", "Reading %d bytes at offset " CPL_FRMT_GUIB,
     144             :              static_cast<int>(size), VSIFTellL(psGTH->psShared->fpL));
     145             : #endif
     146     2608400 :     return VSIFReadL(buf, 1, size, psGTH->psShared->fpL);
     147             : }
     148             : 
     149     2612810 : static bool GTHFlushBuffer(thandle_t th)
     150             : {
     151     2612810 :     GDALTiffHandle *psGTH = static_cast<GDALTiffHandle *>(th);
     152     2612810 :     bool bRet = true;
     153     2612810 :     if (psGTH->abyWriteBuffer && psGTH->nWriteBufferSize)
     154             :     {
     155             :         const tsize_t nRet =
     156       22150 :             VSIFWriteL(psGTH->abyWriteBuffer, 1, psGTH->nWriteBufferSize,
     157       11075 :                        psGTH->psShared->fpL);
     158       11075 :         bRet = nRet == psGTH->nWriteBufferSize;
     159       11075 :         if (!bRet)
     160             :         {
     161           0 :             TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
     162             :         }
     163       11075 :         psGTH->nWriteBufferSize = 0;
     164             :     }
     165     2612810 :     return bRet;
     166             : }
     167             : 
     168      388569 : static tsize_t _tiffWriteProc(thandle_t th, tdata_t buf, tsize_t size)
     169             : {
     170      388569 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     171      388569 :     SetActiveGTH(psGTH);
     172             : 
     173             :     // If we have a write buffer and are at end of file, then accumulate
     174             :     // the bytes until the buffer is full.
     175      388559 :     if (psGTH->psShared->bAtEndOfFile && psGTH->abyWriteBuffer)
     176             :     {
     177       91691 :         const GByte *pabyData = reinterpret_cast<GByte *>(buf);
     178       91691 :         tsize_t nRemainingBytes = size;
     179             :         while (true)
     180             :         {
     181       96450 :             if (psGTH->nWriteBufferSize + nRemainingBytes <= BUFFER_SIZE)
     182             :             {
     183       91691 :                 memcpy(psGTH->abyWriteBuffer + psGTH->nWriteBufferSize,
     184             :                        pabyData, nRemainingBytes);
     185       91691 :                 psGTH->nWriteBufferSize += static_cast<int>(nRemainingBytes);
     186       91691 :                 if (psGTH->psShared->bAtEndOfFile)
     187             :                 {
     188       91691 :                     psGTH->psShared->nFileLength += size;
     189             :                 }
     190       91691 :                 return size;
     191             :             }
     192             : 
     193        4759 :             int nAppendable = BUFFER_SIZE - psGTH->nWriteBufferSize;
     194        4759 :             memcpy(psGTH->abyWriteBuffer + psGTH->nWriteBufferSize, pabyData,
     195             :                    nAppendable);
     196        9518 :             const tsize_t nRet = VSIFWriteL(psGTH->abyWriteBuffer, 1,
     197        4759 :                                             BUFFER_SIZE, psGTH->psShared->fpL);
     198        4759 :             psGTH->nWriteBufferSize = 0;
     199        4759 :             if (nRet != BUFFER_SIZE)
     200             :             {
     201           0 :                 TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
     202           0 :                 return 0;
     203             :             }
     204             : 
     205        4759 :             pabyData += nAppendable;
     206        4759 :             nRemainingBytes -= nAppendable;
     207        4759 :         }
     208             :     }
     209             : 
     210      296868 :     const tsize_t nRet = VSIFWriteL(buf, 1, size, psGTH->psShared->fpL);
     211      296876 :     if (nRet < size)
     212             :     {
     213          73 :         TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
     214             :     }
     215             : 
     216      296874 :     if (psGTH->psShared->bAtEndOfFile)
     217             :     {
     218      128981 :         psGTH->psShared->nFileLength += nRet;
     219             :     }
     220      296874 :     return nRet;
     221             : }
     222             : 
     223     2776710 : static toff_t _tiffSeekProc(thandle_t th, toff_t off, int whence)
     224             : {
     225     2776710 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     226     2776710 :     SetActiveGTH(psGTH);
     227             : 
     228             :     // Optimization: if we are already at end, then no need to
     229             :     // issue a VSIFSeekL().
     230     2776680 :     if (whence == SEEK_END)
     231             :     {
     232      246528 :         if (psGTH->psShared->bAtEndOfFile)
     233             :         {
     234      192774 :             return static_cast<toff_t>(psGTH->psShared->nFileLength);
     235             :         }
     236             : 
     237       53754 :         if (VSIFSeekL(psGTH->psShared->fpL, off, whence) != 0)
     238             :         {
     239           0 :             TIFFErrorExt(th, "_tiffSeekProc", "%s", VSIStrerror(errno));
     240           0 :             return static_cast<toff_t>(-1);
     241             :         }
     242       53755 :         psGTH->psShared->bAtEndOfFile = true;
     243       53755 :         psGTH->psShared->nFileLength = VSIFTellL(psGTH->psShared->fpL);
     244       53752 :         return static_cast<toff_t>(psGTH->psShared->nFileLength);
     245             :     }
     246             : 
     247     2530150 :     GTHFlushBuffer(th);
     248     2530160 :     psGTH->psShared->bAtEndOfFile = false;
     249     2530160 :     psGTH->psShared->nFileLength = 0;
     250             : 
     251     2530160 :     if (VSIFSeekL(psGTH->psShared->fpL, off, whence) == 0)
     252             :     {
     253     2530260 :         return static_cast<toff_t>(VSIFTellL(psGTH->psShared->fpL));
     254             :     }
     255             :     else
     256             :     {
     257           0 :         TIFFErrorExt(th, "_tiffSeekProc", "%s", VSIStrerror(errno));
     258           0 :         return static_cast<toff_t>(-1);
     259             :     }
     260             : }
     261             : 
     262       61980 : static void FreeGTH(GDALTiffHandle *psGTH)
     263             : {
     264       61980 :     psGTH->psShared->nUserCounter--;
     265       61980 :     if (psGTH->psParent == nullptr)
     266             :     {
     267       60419 :         assert(psGTH->psShared->nUserCounter == 0);
     268       60419 :         CPLFree(psGTH->psShared->pszName);
     269       60422 :         CPLFree(psGTH->psShared);
     270             :     }
     271             :     else
     272             :     {
     273        1561 :         if (psGTH->psShared->psActiveHandle == psGTH)
     274        1562 :             psGTH->psShared->psActiveHandle = nullptr;
     275             :     }
     276       61983 :     CPLFree(psGTH->abyWriteBuffer);
     277       61979 :     CPLFree(psGTH->ppCachedData);
     278       61979 :     CPLFree(psGTH->panCachedOffsets);
     279       61979 :     CPLFree(psGTH->panCachedSizes);
     280       61982 :     CPLFree(psGTH);
     281       61983 : }
     282             : 
     283       61979 : static int _tiffCloseProc(thandle_t th)
     284             : {
     285       61979 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     286       61979 :     SetActiveGTH(psGTH);
     287       61976 :     GTHFlushBuffer(th);
     288       61975 :     if (psGTH->bFree)
     289       61968 :         FreeGTH(psGTH);
     290       61979 :     return 0;
     291             : }
     292             : 
     293       29668 : static toff_t _tiffSizeProc(thandle_t th)
     294             : {
     295       29668 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     296       29668 :     SetActiveGTH(psGTH);
     297             : 
     298       29642 :     if (psGTH->psShared->bAtEndOfFile)
     299             :     {
     300        7744 :         return static_cast<toff_t>(psGTH->psShared->nFileLength);
     301             :     }
     302             : 
     303       21898 :     const vsi_l_offset old_off = VSIFTellL(psGTH->psShared->fpL);
     304       21886 :     CPL_IGNORE_RET_VAL(VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_END));
     305             : 
     306             :     const toff_t file_size =
     307       21836 :         static_cast<toff_t>(VSIFTellL(psGTH->psShared->fpL));
     308       21884 :     CPL_IGNORE_RET_VAL(VSIFSeekL(psGTH->psShared->fpL, old_off, SEEK_SET));
     309             : 
     310       21869 :     return file_size;
     311             : }
     312             : 
     313       22693 : static int _tiffMapProc(thandle_t th, tdata_t *pbase, toff_t *psize)
     314             : {
     315       22693 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     316             :     // SetActiveGTH(psGTH);
     317             : 
     318       22693 :     if (psGTH->pBase)
     319             :     {
     320           8 :         *pbase = psGTH->pBase;
     321           8 :         *psize = static_cast<toff_t>(psGTH->nDataLength);
     322           8 :         return 1;
     323             :     }
     324       22685 :     return 0;
     325             : }
     326             : 
     327           8 : static void _tiffUnmapProc(thandle_t /* th */, tdata_t /* base */,
     328             :                            toff_t /* size */)
     329             : {
     330           8 : }
     331             : 
     332        5681 : VSILFILE *VSI_TIFFGetVSILFile(thandle_t th)
     333             : {
     334        5681 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     335        5681 :     SetActiveGTH(psGTH);
     336        5681 :     VSI_TIFFFlushBufferedWrite(th);
     337        5681 :     return psGTH->psShared->fpL;
     338             : }
     339             : 
     340        5906 : int VSI_TIFFFlushBufferedWrite(thandle_t th)
     341             : {
     342        5906 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     343        5906 :     SetActiveGTH(psGTH);
     344        5906 :     psGTH->psShared->bAtEndOfFile = false;
     345        5906 :     return GTHFlushBuffer(th);
     346             : }
     347             : 
     348         371 : int VSI_TIFFHasCachedRanges(thandle_t th)
     349             : {
     350         371 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     351         371 :     return psGTH->nCachedRanges != 0;
     352             : }
     353             : 
     354       24695 : toff_t VSI_TIFFSeek(TIFF *tif, toff_t off, int whence)
     355             : {
     356       24695 :     thandle_t th = TIFFClientdata(tif);
     357       24695 :     return _tiffSeekProc(th, off, whence);
     358             : }
     359             : 
     360       49042 : int VSI_TIFFWrite(TIFF *tif, const void *buffer, size_t buffersize)
     361             : {
     362       49042 :     thandle_t th = TIFFClientdata(tif);
     363       49042 :     return static_cast<size_t>(_tiffWriteProc(th, const_cast<tdata_t>(buffer),
     364       49042 :                                               buffersize)) == buffersize;
     365             : }
     366             : 
     367          82 : void VSI_TIFFSetCachedRanges(thandle_t th, int nRanges, void **ppData,
     368             :                              const vsi_l_offset *panOffsets,
     369             :                              const size_t *panSizes)
     370             : {
     371          82 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     372          82 :     psGTH->nCachedRanges = nRanges;
     373          82 :     if (nRanges)
     374             :     {
     375          41 :         psGTH->ppCachedData = static_cast<void **>(
     376          41 :             CPLRealloc(psGTH->ppCachedData, nRanges * sizeof(void *)));
     377          41 :         memcpy(psGTH->ppCachedData, ppData, nRanges * sizeof(void *));
     378             : 
     379          82 :         psGTH->panCachedOffsets = static_cast<vsi_l_offset *>(CPLRealloc(
     380          41 :             psGTH->panCachedOffsets, nRanges * sizeof(vsi_l_offset)));
     381          41 :         memcpy(psGTH->panCachedOffsets, panOffsets,
     382          41 :                nRanges * sizeof(vsi_l_offset));
     383             : 
     384          41 :         psGTH->panCachedSizes = static_cast<size_t *>(
     385          41 :             CPLRealloc(psGTH->panCachedSizes, nRanges * sizeof(size_t)));
     386          41 :         memcpy(psGTH->panCachedSizes, panSizes, nRanges * sizeof(size_t));
     387             :     }
     388          82 : }
     389             : 
     390       61983 : static bool IsReadOnly(const char *mode)
     391             : {
     392       61983 :     bool bReadOnly = true;
     393      252048 :     for (int i = 0; mode[i] != '\0'; i++)
     394             :     {
     395      190065 :         if (mode[i] == 'w' || mode[i] == '+' || mode[i] == 'a')
     396             :         {
     397       74864 :             bReadOnly = false;
     398             :         }
     399             :     }
     400       61983 :     return bReadOnly;
     401             : }
     402             : 
     403       61981 : static void InitializeWriteBuffer(GDALTiffHandle *psGTH, const char *pszMode)
     404             : {
     405             :     // No need to buffer on /vsimem/
     406       61981 :     const bool bReadOnly = IsReadOnly(pszMode);
     407       61960 :     bool bAllocBuffer = !bReadOnly;
     408       61960 :     if (STARTS_WITH(psGTH->psShared->pszName, "/vsimem/"))
     409             :     {
     410       51433 :         if (bReadOnly &&
     411        7862 :             CPLTestBool(CPLGetConfigOption("GTIFF_USE_MMAP", "NO")))
     412             :         {
     413           8 :             psGTH->nDataLength = 0;
     414           8 :             psGTH->pBase = VSIGetMemFileBuffer(psGTH->psShared->pszName,
     415             :                                                &psGTH->nDataLength, FALSE);
     416             :         }
     417       43571 :         bAllocBuffer = false;
     418             :     }
     419             : 
     420       61946 :     psGTH->abyWriteBuffer =
     421       61946 :         bAllocBuffer ? static_cast<GByte *>(VSIMalloc(BUFFER_SIZE)) : nullptr;
     422       61946 :     psGTH->nWriteBufferSize = 0;
     423       61946 : }
     424             : 
     425             : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
     426       61966 : static void VSI_TIFFSetOpenOptions(TIFFOpenOptions *opts)
     427             : {
     428       61966 :     TIFFOpenOptionsSetErrorHandlerExtR(opts, GTiffErrorHandlerExt, nullptr);
     429       61940 :     TIFFOpenOptionsSetWarningHandlerExtR(opts, GTiffWarningHandlerExt, nullptr);
     430             : #if defined(INTERNAL_LIBTIFF) || TIFFLIB_VERSION > 20230908
     431             :     // Read-once and stored in static storage otherwise affects
     432             :     // autotest/benchmark/test_gtiff.py::test_gtiff_byte
     433         607 :     static const GIntBig nMemLimit = []() -> GIntBig
     434             :     {
     435         607 :         if (const char *pszLimit =
     436         607 :                 CPLGetConfigOption("GTIFF_MAX_CUMULATED_MEM_USAGE", nullptr))
     437           0 :             return CPLAtoGIntBig(pszLimit);
     438             :         else
     439             :         {
     440         607 :             const auto nUsableRAM = CPLGetUsablePhysicalRAM();
     441         607 :             if (nUsableRAM > 0)
     442             :             {
     443             :                 // coverity[return_overflow]
     444         607 :                 return nUsableRAM / 10 * 9;
     445             :             }
     446             :             else
     447           0 :                 return 0;
     448             :         }
     449       61929 :     }();
     450       61959 :     if (nMemLimit > 0 && nMemLimit < std::numeric_limits<tmsize_t>::max())
     451             :     {
     452             :         //CPLDebug("GTiff", "TIFFOpenOptionsSetMaxCumulatedMemAlloc(%" PRIu64 ")",
     453             :         //         static_cast<uint64_t>(nMemLimit));
     454       61957 :         TIFFOpenOptionsSetMaxCumulatedMemAlloc(
     455             :             opts, static_cast<tmsize_t>(nMemLimit));
     456             :     }
     457             : #endif
     458       61936 : }
     459             : #endif
     460             : 
     461       61957 : static TIFF *VSI_TIFFOpen_common(GDALTiffHandle *psGTH, const char *pszMode)
     462             : {
     463       61957 :     InitializeWriteBuffer(psGTH, pszMode);
     464             : 
     465             : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
     466       61933 :     XTIFFInitialize();
     467       61953 :     TIFFOpenOptions *opts = TIFFOpenOptionsAlloc();
     468       61923 :     if (opts == nullptr)
     469             :     {
     470           0 :         FreeGTH(psGTH);
     471           0 :         return nullptr;
     472             :     }
     473       61923 :     VSI_TIFFSetOpenOptions(opts);
     474      123879 :     TIFF *tif = TIFFClientOpenExt(
     475       61938 :         psGTH->psShared->pszName, pszMode, reinterpret_cast<thandle_t>(psGTH),
     476             :         _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
     477             :         _tiffSizeProc, _tiffMapProc, _tiffUnmapProc, opts);
     478       61941 :     TIFFOpenOptionsFree(opts);
     479             : #else
     480             :     TIFF *tif = XTIFFClientOpen(
     481             :         psGTH->psShared->pszName, pszMode, reinterpret_cast<thandle_t>(psGTH),
     482             :         _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
     483             :         _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
     484             : #endif
     485       61936 :     if (tif == nullptr)
     486          14 :         FreeGTH(psGTH);
     487             : 
     488       61897 :     return tif;
     489             : }
     490             : 
     491             : // Open a TIFF file for read/writing.
     492       60424 : TIFF *VSI_TIFFOpen(const char *name, const char *mode, VSILFILE *fpL)
     493             : {
     494             : 
     495       60424 :     if (VSIFSeekL(fpL, 0, SEEK_SET) < 0)
     496           0 :         return nullptr;
     497             : 
     498             :     GDALTiffHandle *psGTH =
     499       60420 :         static_cast<GDALTiffHandle *>(CPLCalloc(1, sizeof(GDALTiffHandle)));
     500       60419 :     psGTH->bFree = true;
     501       60419 :     psGTH->psParent = nullptr;
     502       60415 :     psGTH->psShared = static_cast<GDALTiffHandleShared *>(
     503       60419 :         CPLCalloc(1, sizeof(GDALTiffHandleShared)));
     504       60415 :     psGTH->psShared->bReadOnly = (strchr(mode, '+') == nullptr);
     505       60415 :     psGTH->psShared->bLazyStrileLoading = (strchr(mode, 'D') != nullptr);
     506       60415 :     psGTH->psShared->pszName = CPLStrdup(name);
     507       60415 :     psGTH->psShared->fpL = fpL;
     508       60415 :     psGTH->psShared->psActiveHandle = psGTH;
     509       60415 :     psGTH->psShared->nFileLength = 0;
     510       60415 :     psGTH->psShared->bAtEndOfFile = false;
     511       60415 :     psGTH->psShared->nUserCounter = 1;
     512             : 
     513       60415 :     return VSI_TIFFOpen_common(psGTH, mode);
     514             : }
     515             : 
     516        1562 : TIFF *VSI_TIFFOpenChild(TIFF *parent)
     517             : {
     518             :     GDALTiffHandle *psGTHParent =
     519        1562 :         reinterpret_cast<GDALTiffHandle *>(TIFFClientdata(parent));
     520             : 
     521             :     GDALTiffHandle *psGTH =
     522        1562 :         static_cast<GDALTiffHandle *>(CPLCalloc(1, sizeof(GDALTiffHandle)));
     523        1562 :     psGTH->bFree = true;
     524        1562 :     psGTH->psParent = psGTHParent;
     525        1562 :     psGTH->psShared = psGTHParent->psShared;
     526        1562 :     psGTH->psShared->nUserCounter++;
     527             : 
     528        1562 :     SetActiveGTH(psGTH);
     529        1562 :     VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_SET);
     530        1562 :     psGTH->psShared->bAtEndOfFile = false;
     531             : 
     532        1562 :     const char *mode =
     533         750 :         psGTH->psShared->bReadOnly && psGTH->psShared->bLazyStrileLoading
     534        3124 :             ? "rDO"
     535        1624 :         : psGTH->psShared->bReadOnly          ? "r"
     536         812 :         : psGTH->psShared->bLazyStrileLoading ? "r+D"
     537             :                                               : "r+";
     538        1562 :     return VSI_TIFFOpen_common(psGTH, mode);
     539             : }
     540             : 
     541             : // Re-open a TIFF handle (seeking to the appropriate directory is then needed)
     542           9 : TIFF *VSI_TIFFReOpen(TIFF *tif)
     543             : {
     544           9 :     thandle_t th = TIFFClientdata(tif);
     545           9 :     GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
     546             : 
     547             :     // Disable freeing of psGTH in _tiffCloseProc(), which could be called
     548             :     // if XTIFFClientOpen() fails, or obviously by XTIFFClose()
     549           9 :     psGTH->bFree = false;
     550             : 
     551           9 :     const char *mode =
     552           0 :         psGTH->psShared->bReadOnly && psGTH->psShared->bLazyStrileLoading
     553          18 :             ? "rDO"
     554          18 :         : psGTH->psShared->bReadOnly          ? "r"
     555           9 :         : psGTH->psShared->bLazyStrileLoading ? "r+D"
     556             :                                               : "r+";
     557             : 
     558           9 :     SetActiveGTH(psGTH);
     559           9 :     VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_SET);
     560           9 :     psGTH->psShared->bAtEndOfFile = false;
     561             : 
     562             : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
     563           9 :     TIFF *newHandle = nullptr;
     564           9 :     TIFFOpenOptions *opts = TIFFOpenOptionsAlloc();
     565           9 :     if (opts != nullptr)
     566             :     {
     567           9 :         VSI_TIFFSetOpenOptions(opts);
     568          18 :         newHandle = TIFFClientOpenExt(
     569           9 :             psGTH->psShared->pszName, mode, reinterpret_cast<thandle_t>(psGTH),
     570             :             _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
     571             :             _tiffSizeProc, _tiffMapProc, _tiffUnmapProc, opts);
     572           9 :         TIFFOpenOptionsFree(opts);
     573             :     }
     574             : #else
     575             :     TIFF *newHandle = XTIFFClientOpen(
     576             :         psGTH->psShared->pszName, mode, reinterpret_cast<thandle_t>(psGTH),
     577             :         _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
     578             :         _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
     579             : #endif
     580           9 :     if (newHandle != nullptr)
     581           9 :         XTIFFClose(tif);
     582             : 
     583           9 :     psGTH->bFree = true;
     584             : 
     585           9 :     return newHandle;
     586             : }

Generated by: LCOV version 1.14