LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffdataset_write.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 3833 4193 91.4 %
Date: 2025-08-01 10:10:57 Functions: 109 138 79.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GeoTIFF Driver
       4             :  * Purpose:  Write/set operations on GTiffDataset
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1998, 2002, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2007-2015, Even Rouault <even dot rouault at spatialys dot com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "gtiffdataset.h"
      15             : #include "gtiffrasterband.h"
      16             : #include "gtiffoddbitsband.h"
      17             : 
      18             : #include <cassert>
      19             : #include <cerrno>
      20             : 
      21             : #include <algorithm>
      22             : #include <cmath>
      23             : #include <limits>
      24             : #include <memory>
      25             : #include <mutex>
      26             : #include <set>
      27             : #include <string>
      28             : #include <tuple>
      29             : #include <utility>
      30             : 
      31             : #include "cpl_error.h"
      32             : #include "cpl_error_internal.h"  // CPLErrorHandlerAccumulatorStruct
      33             : #include "cpl_float.h"
      34             : #include "cpl_md5.h"
      35             : #include "cpl_vsi.h"
      36             : #include "cpl_vsi_virtual.h"
      37             : #include "cpl_worker_thread_pool.h"
      38             : #include "fetchbufferdirectio.h"
      39             : #include "gdal_mdreader.h"          // GDALWriteRPCTXTFile()
      40             : #include "gdal_priv_templates.hpp"  // GDALIsValueInRange<>
      41             : #include "gdal_thread_pool.h"       // GDALGetGlobalThreadPool()
      42             : #include "geovalues.h"              // RasterPixelIsPoint
      43             : #include "gt_jpeg_copy.h"
      44             : #include "gt_overview.h"  // GTIFFBuildOverviewMetadata()
      45             : #include "quant_table_md5sum.h"
      46             : #include "quant_table_md5sum_jpeg9e.h"
      47             : #include "tif_jxl.h"
      48             : #include "tifvsi.h"
      49             : #include "xtiffio.h"
      50             : 
      51             : #if LIFFLIB_VERSION > 20230908 || defined(INTERNAL_LIBTIFF)
      52             : /* libtiff < 4.6.1 doesn't generate a LERC mask for multi-band contig configuration */
      53             : #define LIBTIFF_MULTIBAND_LERC_NAN_OK
      54             : #endif
      55             : 
      56             : static const int knGTIFFJpegTablesModeDefault = JPEGTABLESMODE_QUANT;
      57             : 
      58             : static constexpr const char szPROFILE_BASELINE[] = "BASELINE";
      59             : static constexpr const char szPROFILE_GeoTIFF[] = "GeoTIFF";
      60             : static constexpr const char szPROFILE_GDALGeoTIFF[] = "GDALGeoTIFF";
      61             : 
      62             : // Due to libgeotiff/xtiff.c declaring TIFFTAG_GEOTIEPOINTS with field_readcount
      63             : // and field_writecount == -1 == TIFF_VARIABLE, we are limited to writing
      64             : // 65535 values in that tag. That could potentially be overcome by changing the tag
      65             : // declaration to using TIFF_VARIABLE2 where the count is a uint32_t.
      66             : constexpr int knMAX_GCP_COUNT =
      67             :     static_cast<int>(std::numeric_limits<uint16_t>::max() / 6);
      68             : 
      69             : enum
      70             : {
      71             :     ENDIANNESS_NATIVE,
      72             :     ENDIANNESS_LITTLE,
      73             :     ENDIANNESS_BIG
      74             : };
      75             : 
      76       16982 : static signed char GTiffGetWebPLevel(CSLConstList papszOptions)
      77             : {
      78       16982 :     int nWebPLevel = DEFAULT_WEBP_LEVEL;
      79       16982 :     const char *pszValue = CSLFetchNameValue(papszOptions, "WEBP_LEVEL");
      80       16982 :     if (pszValue != nullptr)
      81             :     {
      82          51 :         nWebPLevel = atoi(pszValue);
      83          51 :         if (!(nWebPLevel >= 1 && nWebPLevel <= 100))
      84             :         {
      85           0 :             CPLError(CE_Warning, CPLE_IllegalArg,
      86             :                      "WEBP_LEVEL=%s value not recognised, ignoring.", pszValue);
      87           0 :             nWebPLevel = DEFAULT_WEBP_LEVEL;
      88             :         }
      89             :     }
      90       16982 :     return static_cast<signed char>(nWebPLevel);
      91             : }
      92             : 
      93       16988 : static bool GTiffGetWebPLossless(CSLConstList papszOptions)
      94             : {
      95       16988 :     return CPLFetchBool(papszOptions, "WEBP_LOSSLESS", false);
      96             : }
      97             : 
      98       17054 : static double GTiffGetLERCMaxZError(CSLConstList papszOptions)
      99             : {
     100       17054 :     return CPLAtof(CSLFetchNameValueDef(papszOptions, "MAX_Z_ERROR", "0.0"));
     101             : }
     102             : 
     103        7562 : static double GTiffGetLERCMaxZErrorOverview(CSLConstList papszOptions)
     104             : {
     105        7562 :     return CPLAtof(CSLFetchNameValueDef(
     106             :         papszOptions, "MAX_Z_ERROR_OVERVIEW",
     107        7562 :         CSLFetchNameValueDef(papszOptions, "MAX_Z_ERROR", "0.0")));
     108             : }
     109             : 
     110             : #if HAVE_JXL
     111       17055 : static bool GTiffGetJXLLossless(CSLConstList papszOptions)
     112             : {
     113       17055 :     return CPLTestBool(
     114       17055 :         CSLFetchNameValueDef(papszOptions, "JXL_LOSSLESS", "TRUE"));
     115             : }
     116             : 
     117       17055 : static uint32_t GTiffGetJXLEffort(CSLConstList papszOptions)
     118             : {
     119       17055 :     return atoi(CSLFetchNameValueDef(papszOptions, "JXL_EFFORT", "5"));
     120             : }
     121             : 
     122       16975 : static float GTiffGetJXLDistance(CSLConstList papszOptions)
     123             : {
     124             :     return static_cast<float>(
     125       16975 :         CPLAtof(CSLFetchNameValueDef(papszOptions, "JXL_DISTANCE", "1.0")));
     126             : }
     127             : 
     128       17055 : static float GTiffGetJXLAlphaDistance(CSLConstList papszOptions)
     129             : {
     130       17055 :     return static_cast<float>(CPLAtof(
     131       17055 :         CSLFetchNameValueDef(papszOptions, "JXL_ALPHA_DISTANCE", "-1.0")));
     132             : }
     133             : 
     134             : #endif
     135             : 
     136             : /************************************************************************/
     137             : /*                           FillEmptyTiles()                           */
     138             : /************************************************************************/
     139             : 
     140        7735 : CPLErr GTiffDataset::FillEmptyTiles()
     141             : 
     142             : {
     143             :     /* -------------------------------------------------------------------- */
     144             :     /*      How many blocks are there in this file?                         */
     145             :     /* -------------------------------------------------------------------- */
     146       15470 :     const int nBlockCount = m_nPlanarConfig == PLANARCONFIG_SEPARATE
     147        7735 :                                 ? m_nBlocksPerBand * nBands
     148             :                                 : m_nBlocksPerBand;
     149             : 
     150             :     /* -------------------------------------------------------------------- */
     151             :     /*      Fetch block maps.                                               */
     152             :     /* -------------------------------------------------------------------- */
     153        7735 :     toff_t *panByteCounts = nullptr;
     154             : 
     155        7735 :     if (TIFFIsTiled(m_hTIFF))
     156        1007 :         TIFFGetField(m_hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts);
     157             :     else
     158        6728 :         TIFFGetField(m_hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts);
     159             : 
     160        7735 :     if (panByteCounts == nullptr)
     161             :     {
     162             :         // Got here with libtiff 3.9.3 and tiff_write_8 test.
     163           0 :         ReportError(CE_Failure, CPLE_AppDefined,
     164             :                     "FillEmptyTiles() failed because panByteCounts == NULL");
     165           0 :         return CE_Failure;
     166             :     }
     167             : 
     168             :     /* -------------------------------------------------------------------- */
     169             :     /*      Prepare a blank data buffer to write for uninitialized blocks.  */
     170             :     /* -------------------------------------------------------------------- */
     171             :     const GPtrDiff_t nBlockBytes =
     172        7735 :         TIFFIsTiled(m_hTIFF) ? static_cast<GPtrDiff_t>(TIFFTileSize(m_hTIFF))
     173        6728 :                              : static_cast<GPtrDiff_t>(TIFFStripSize(m_hTIFF));
     174             : 
     175        7735 :     GByte *pabyData = static_cast<GByte *>(VSI_CALLOC_VERBOSE(nBlockBytes, 1));
     176        7735 :     if (pabyData == nullptr)
     177             :     {
     178           0 :         return CE_Failure;
     179             :     }
     180             : 
     181             :     // Force tiles completely filled with the nodata value to be written.
     182        7735 :     m_bWriteEmptyTiles = true;
     183             : 
     184             :     /* -------------------------------------------------------------------- */
     185             :     /*      If set, fill data buffer with no data value.                    */
     186             :     /* -------------------------------------------------------------------- */
     187        7735 :     if ((m_bNoDataSet && m_dfNoDataValue != 0.0) ||
     188        7500 :         (m_bNoDataSetAsInt64 && m_nNoDataValueInt64 != 0) ||
     189        7498 :         (m_bNoDataSetAsUInt64 && m_nNoDataValueUInt64 != 0))
     190             :     {
     191         239 :         const GDALDataType eDataType = GetRasterBand(1)->GetRasterDataType();
     192         239 :         const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
     193         239 :         if (nDataTypeSize &&
     194         239 :             nDataTypeSize * 8 == static_cast<int>(m_nBitsPerSample))
     195             :         {
     196         228 :             if (m_bNoDataSetAsInt64)
     197             :             {
     198           3 :                 GDALCopyWords64(&m_nNoDataValueInt64, GDT_Int64, 0, pabyData,
     199             :                                 eDataType, nDataTypeSize,
     200           3 :                                 nBlockBytes / nDataTypeSize);
     201             :             }
     202         225 :             else if (m_bNoDataSetAsUInt64)
     203             :             {
     204           2 :                 GDALCopyWords64(&m_nNoDataValueUInt64, GDT_UInt64, 0, pabyData,
     205             :                                 eDataType, nDataTypeSize,
     206           2 :                                 nBlockBytes / nDataTypeSize);
     207             :             }
     208             :             else
     209             :             {
     210         223 :                 double dfNoData = m_dfNoDataValue;
     211         223 :                 GDALCopyWords64(&dfNoData, GDT_Float64, 0, pabyData, eDataType,
     212         223 :                                 nDataTypeSize, nBlockBytes / nDataTypeSize);
     213         228 :             }
     214             :         }
     215          11 :         else if (nDataTypeSize)
     216             :         {
     217             :             // Handle non power-of-two depths.
     218             :             // Ideally make a packed buffer, but that is a bit tedious,
     219             :             // so use the normal I/O interfaces.
     220             : 
     221          11 :             CPLFree(pabyData);
     222             : 
     223          11 :             pabyData = static_cast<GByte *>(VSI_MALLOC3_VERBOSE(
     224             :                 m_nBlockXSize, m_nBlockYSize, nDataTypeSize));
     225          11 :             if (pabyData == nullptr)
     226           0 :                 return CE_Failure;
     227          11 :             if (m_bNoDataSetAsInt64)
     228             :             {
     229           0 :                 GDALCopyWords64(&m_nNoDataValueInt64, GDT_Int64, 0, pabyData,
     230             :                                 eDataType, nDataTypeSize,
     231           0 :                                 static_cast<GPtrDiff_t>(m_nBlockXSize) *
     232           0 :                                     m_nBlockYSize);
     233             :             }
     234          11 :             else if (m_bNoDataSetAsUInt64)
     235             :             {
     236           0 :                 GDALCopyWords64(&m_nNoDataValueUInt64, GDT_UInt64, 0, pabyData,
     237             :                                 eDataType, nDataTypeSize,
     238           0 :                                 static_cast<GPtrDiff_t>(m_nBlockXSize) *
     239           0 :                                     m_nBlockYSize);
     240             :             }
     241             :             else
     242             :             {
     243          11 :                 GDALCopyWords64(&m_dfNoDataValue, GDT_Float64, 0, pabyData,
     244             :                                 eDataType, nDataTypeSize,
     245          11 :                                 static_cast<GPtrDiff_t>(m_nBlockXSize) *
     246          11 :                                     m_nBlockYSize);
     247             :             }
     248          11 :             CPLErr eErr = CE_None;
     249          46 :             for (int iBlock = 0; iBlock < nBlockCount; ++iBlock)
     250             :             {
     251          35 :                 if (panByteCounts[iBlock] == 0)
     252             :                 {
     253          18 :                     if (m_nPlanarConfig == PLANARCONFIG_SEPARATE || nBands == 1)
     254             :                     {
     255          24 :                         if (GetRasterBand(1 + iBlock / m_nBlocksPerBand)
     256          12 :                                 ->WriteBlock((iBlock % m_nBlocksPerBand) %
     257          12 :                                                  m_nBlocksPerRow,
     258          12 :                                              (iBlock % m_nBlocksPerBand) /
     259          12 :                                                  m_nBlocksPerRow,
     260          12 :                                              pabyData) != CE_None)
     261             :                         {
     262           0 :                             eErr = CE_Failure;
     263             :                         }
     264             :                     }
     265             :                     else
     266             :                     {
     267             :                         // In contig case, don't directly call WriteBlock(), as
     268             :                         // it could cause useless decompression-recompression.
     269           6 :                         const int nXOff =
     270           6 :                             (iBlock % m_nBlocksPerRow) * m_nBlockXSize;
     271           6 :                         const int nYOff =
     272           6 :                             (iBlock / m_nBlocksPerRow) * m_nBlockYSize;
     273           6 :                         const int nXSize =
     274           6 :                             (nXOff + m_nBlockXSize <= nRasterXSize)
     275           6 :                                 ? m_nBlockXSize
     276           2 :                                 : nRasterXSize - nXOff;
     277           6 :                         const int nYSize =
     278           6 :                             (nYOff + m_nBlockYSize <= nRasterYSize)
     279           6 :                                 ? m_nBlockYSize
     280           3 :                                 : nRasterYSize - nYOff;
     281          18 :                         for (int iBand = 1; iBand <= nBands; ++iBand)
     282             :                         {
     283          12 :                             if (GetRasterBand(iBand)->RasterIO(
     284             :                                     GF_Write, nXOff, nYOff, nXSize, nYSize,
     285             :                                     pabyData, nXSize, nYSize, eDataType, 0, 0,
     286          12 :                                     nullptr) != CE_None)
     287             :                             {
     288           0 :                                 eErr = CE_Failure;
     289             :                             }
     290             :                         }
     291             :                     }
     292             :                 }
     293             :             }
     294          11 :             CPLFree(pabyData);
     295          11 :             return eErr;
     296         228 :         }
     297             :     }
     298             : 
     299             :     /* -------------------------------------------------------------------- */
     300             :     /*      When we must fill with zeroes, try to create non-sparse file    */
     301             :     /*      w.r.t TIFF spec ... as a sparse file w.r.t filesystem, ie by    */
     302             :     /*      seeking to end of file instead of writing zero blocks.          */
     303             :     /* -------------------------------------------------------------------- */
     304        7496 :     else if (m_nCompression == COMPRESSION_NONE && (m_nBitsPerSample % 8) == 0)
     305             :     {
     306        6059 :         CPLErr eErr = CE_None;
     307             :         // Only use libtiff to write the first sparse block to ensure that it
     308             :         // will serialize offset and count arrays back to disk.
     309        6059 :         int nCountBlocksToZero = 0;
     310     2317360 :         for (int iBlock = 0; iBlock < nBlockCount; ++iBlock)
     311             :         {
     312     2311310 :             if (panByteCounts[iBlock] == 0)
     313             :             {
     314     2218360 :                 if (nCountBlocksToZero == 0)
     315             :                 {
     316        1066 :                     const bool bWriteEmptyTilesBak = m_bWriteEmptyTiles;
     317        1066 :                     m_bWriteEmptyTiles = true;
     318        1066 :                     const bool bOK = WriteEncodedTileOrStrip(iBlock, pabyData,
     319        1066 :                                                              FALSE) == CE_None;
     320        1066 :                     m_bWriteEmptyTiles = bWriteEmptyTilesBak;
     321        1066 :                     if (!bOK)
     322             :                     {
     323           2 :                         eErr = CE_Failure;
     324           2 :                         break;
     325             :                     }
     326             :                 }
     327     2218360 :                 nCountBlocksToZero++;
     328             :             }
     329             :         }
     330        6059 :         CPLFree(pabyData);
     331             : 
     332        6059 :         --nCountBlocksToZero;
     333             : 
     334             :         // And then seek to end of file for other ones.
     335        6059 :         if (nCountBlocksToZero > 0)
     336             :         {
     337         321 :             toff_t *panByteOffsets = nullptr;
     338             : 
     339         321 :             if (TIFFIsTiled(m_hTIFF))
     340          87 :                 TIFFGetField(m_hTIFF, TIFFTAG_TILEOFFSETS, &panByteOffsets);
     341             :             else
     342         234 :                 TIFFGetField(m_hTIFF, TIFFTAG_STRIPOFFSETS, &panByteOffsets);
     343             : 
     344         321 :             if (panByteOffsets == nullptr)
     345             :             {
     346           0 :                 ReportError(
     347             :                     CE_Failure, CPLE_AppDefined,
     348             :                     "FillEmptyTiles() failed because panByteOffsets == NULL");
     349           0 :                 return CE_Failure;
     350             :             }
     351             : 
     352         321 :             VSILFILE *fpTIF = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
     353         321 :             VSIFSeekL(fpTIF, 0, SEEK_END);
     354         321 :             const vsi_l_offset nOffset = VSIFTellL(fpTIF);
     355             : 
     356         321 :             vsi_l_offset iBlockToZero = 0;
     357     2226470 :             for (int iBlock = 0; iBlock < nBlockCount; ++iBlock)
     358             :             {
     359     2226150 :                 if (panByteCounts[iBlock] == 0)
     360             :                 {
     361     2217300 :                     panByteOffsets[iBlock] = static_cast<toff_t>(
     362     2217300 :                         nOffset + iBlockToZero * nBlockBytes);
     363     2217300 :                     panByteCounts[iBlock] = nBlockBytes;
     364     2217300 :                     iBlockToZero++;
     365             :                 }
     366             :             }
     367         321 :             CPLAssert(iBlockToZero ==
     368             :                       static_cast<vsi_l_offset>(nCountBlocksToZero));
     369             : 
     370         321 :             if (VSIFTruncateL(fpTIF, nOffset + iBlockToZero * nBlockBytes) != 0)
     371             :             {
     372           0 :                 eErr = CE_Failure;
     373           0 :                 ReportError(CE_Failure, CPLE_FileIO,
     374             :                             "Cannot initialize empty blocks");
     375             :             }
     376             :         }
     377             : 
     378        6059 :         return eErr;
     379             :     }
     380             : 
     381             :     /* -------------------------------------------------------------------- */
     382             :     /*      Check all blocks, writing out data for uninitialized blocks.    */
     383             :     /* -------------------------------------------------------------------- */
     384             : 
     385        1665 :     GByte *pabyRaw = nullptr;
     386        1665 :     vsi_l_offset nRawSize = 0;
     387        1665 :     CPLErr eErr = CE_None;
     388       45415 :     for (int iBlock = 0; iBlock < nBlockCount; ++iBlock)
     389             :     {
     390       43757 :         if (panByteCounts[iBlock] == 0)
     391             :         {
     392        8938 :             if (pabyRaw == nullptr)
     393             :             {
     394        1638 :                 if (WriteEncodedTileOrStrip(iBlock, pabyData, FALSE) != CE_None)
     395             :                 {
     396           7 :                     eErr = CE_Failure;
     397           7 :                     break;
     398             :                 }
     399             : 
     400        1631 :                 vsi_l_offset nOffset = 0;
     401        1631 :                 if (!IsBlockAvailable(iBlock, &nOffset, &nRawSize, nullptr))
     402           0 :                     break;
     403             : 
     404             :                 // When using compression, get back the compressed block
     405             :                 // so we can use the raw API to write it faster.
     406        1631 :                 if (m_nCompression != COMPRESSION_NONE)
     407             :                 {
     408             :                     pabyRaw = static_cast<GByte *>(
     409         427 :                         VSI_MALLOC_VERBOSE(static_cast<size_t>(nRawSize)));
     410         427 :                     if (pabyRaw)
     411             :                     {
     412             :                         VSILFILE *fp =
     413         427 :                             VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
     414         427 :                         const vsi_l_offset nCurOffset = VSIFTellL(fp);
     415         427 :                         VSIFSeekL(fp, nOffset, SEEK_SET);
     416         427 :                         VSIFReadL(pabyRaw, 1, static_cast<size_t>(nRawSize),
     417             :                                   fp);
     418         427 :                         VSIFSeekL(fp, nCurOffset, SEEK_SET);
     419             :                     }
     420             :                 }
     421             :             }
     422             :             else
     423             :             {
     424        7300 :                 WriteRawStripOrTile(iBlock, pabyRaw,
     425             :                                     static_cast<GPtrDiff_t>(nRawSize));
     426             :             }
     427             :         }
     428             :     }
     429             : 
     430        1665 :     CPLFree(pabyData);
     431        1665 :     VSIFree(pabyRaw);
     432        1665 :     return eErr;
     433             : }
     434             : 
     435             : /************************************************************************/
     436             : /*                         HasOnlyNoData()                              */
     437             : /************************************************************************/
     438             : 
     439       42264 : bool GTiffDataset::HasOnlyNoData(const void *pBuffer, int nWidth, int nHeight,
     440             :                                  int nLineStride, int nComponents)
     441             : {
     442       42264 :     if (m_nSampleFormat == SAMPLEFORMAT_COMPLEXINT ||
     443       42264 :         m_nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP)
     444           0 :         return false;
     445       42264 :     if (m_bNoDataSetAsInt64 || m_bNoDataSetAsUInt64)
     446           2 :         return false;  // FIXME: over pessimistic
     447       84524 :     return GDALBufferHasOnlyNoData(
     448       42262 :         pBuffer, m_bNoDataSet ? m_dfNoDataValue : 0.0, nWidth, nHeight,
     449       42262 :         nLineStride, nComponents, m_nBitsPerSample,
     450       42262 :         m_nSampleFormat == SAMPLEFORMAT_UINT  ? GSF_UNSIGNED_INT
     451        4737 :         : m_nSampleFormat == SAMPLEFORMAT_INT ? GSF_SIGNED_INT
     452       42262 :                                               : GSF_FLOATING_POINT);
     453             : }
     454             : 
     455             : /************************************************************************/
     456             : /*                     IsFirstPixelEqualToNoData()                      */
     457             : /************************************************************************/
     458             : 
     459      166694 : inline bool GTiffDataset::IsFirstPixelEqualToNoData(const void *pBuffer)
     460             : {
     461      166694 :     const GDALDataType eDT = GetRasterBand(1)->GetRasterDataType();
     462      166704 :     const double dfEffectiveNoData = (m_bNoDataSet) ? m_dfNoDataValue : 0.0;
     463      166704 :     if (m_bNoDataSetAsInt64 || m_bNoDataSetAsUInt64)
     464           3 :         return true;  // FIXME: over pessimistic
     465      166701 :     if (m_nBitsPerSample == 8 ||
     466       58281 :         (m_nBitsPerSample < 8 && dfEffectiveNoData == 0))
     467             :     {
     468      111870 :         if (eDT == GDT_Int8)
     469             :         {
     470         270 :             return GDALIsValueInRange<signed char>(dfEffectiveNoData) &&
     471         135 :                    *(static_cast<const signed char *>(pBuffer)) ==
     472         270 :                        static_cast<signed char>(dfEffectiveNoData);
     473             :         }
     474      223439 :         return GDALIsValueInRange<GByte>(dfEffectiveNoData) &&
     475      111704 :                *(static_cast<const GByte *>(pBuffer)) ==
     476      223439 :                    static_cast<GByte>(dfEffectiveNoData);
     477             :     }
     478       54831 :     if (m_nBitsPerSample == 16 && eDT == GDT_UInt16)
     479             :     {
     480        3742 :         return GDALIsValueInRange<GUInt16>(dfEffectiveNoData) &&
     481        1871 :                *(static_cast<const GUInt16 *>(pBuffer)) ==
     482        3742 :                    static_cast<GUInt16>(dfEffectiveNoData);
     483             :     }
     484       52960 :     if (m_nBitsPerSample == 16 && eDT == GDT_Int16)
     485             :     {
     486        8430 :         return GDALIsValueInRange<GInt16>(dfEffectiveNoData) &&
     487        4215 :                *(static_cast<const GInt16 *>(pBuffer)) ==
     488        8430 :                    static_cast<GInt16>(dfEffectiveNoData);
     489             :     }
     490       48745 :     if (m_nBitsPerSample == 32 && eDT == GDT_UInt32)
     491             :     {
     492         370 :         return GDALIsValueInRange<GUInt32>(dfEffectiveNoData) &&
     493         185 :                *(static_cast<const GUInt32 *>(pBuffer)) ==
     494         370 :                    static_cast<GUInt32>(dfEffectiveNoData);
     495             :     }
     496       48560 :     if (m_nBitsPerSample == 32 && eDT == GDT_Int32)
     497             :     {
     498         498 :         return GDALIsValueInRange<GInt32>(dfEffectiveNoData) &&
     499         249 :                *(static_cast<const GInt32 *>(pBuffer)) ==
     500         498 :                    static_cast<GInt32>(dfEffectiveNoData);
     501             :     }
     502       48311 :     if (m_nBitsPerSample == 64 && eDT == GDT_UInt64)
     503             :     {
     504         234 :         return GDALIsValueInRange<std::uint64_t>(dfEffectiveNoData) &&
     505         117 :                *(static_cast<const std::uint64_t *>(pBuffer)) ==
     506         234 :                    static_cast<std::uint64_t>(dfEffectiveNoData);
     507             :     }
     508       48194 :     if (m_nBitsPerSample == 64 && eDT == GDT_Int64)
     509             :     {
     510         236 :         return GDALIsValueInRange<std::int64_t>(dfEffectiveNoData) &&
     511         118 :                *(static_cast<const std::int64_t *>(pBuffer)) ==
     512         236 :                    static_cast<std::int64_t>(dfEffectiveNoData);
     513             :     }
     514       48076 :     if (m_nBitsPerSample == 32 && eDT == GDT_Float32)
     515             :     {
     516       41207 :         if (std::isnan(m_dfNoDataValue))
     517           3 :             return CPL_TO_BOOL(
     518           6 :                 std::isnan(*(static_cast<const float *>(pBuffer))));
     519       82403 :         return GDALIsValueInRange<float>(dfEffectiveNoData) &&
     520       41197 :                *(static_cast<const float *>(pBuffer)) ==
     521       82393 :                    static_cast<float>(dfEffectiveNoData);
     522             :     }
     523        6869 :     if (m_nBitsPerSample == 64 && eDT == GDT_Float64)
     524             :     {
     525        4227 :         if (std::isnan(dfEffectiveNoData))
     526           0 :             return CPL_TO_BOOL(
     527           0 :                 std::isnan(*(static_cast<const double *>(pBuffer))));
     528        4227 :         return *(static_cast<const double *>(pBuffer)) == dfEffectiveNoData;
     529             :     }
     530        2642 :     return false;
     531             : }
     532             : 
     533             : /************************************************************************/
     534             : /*                      WriteDealWithLercAndNan()                       */
     535             : /************************************************************************/
     536             : 
     537             : template <typename T>
     538           0 : void GTiffDataset::WriteDealWithLercAndNan(T *pBuffer, int nActualBlockWidth,
     539             :                                            int nActualBlockHeight,
     540             :                                            int nStrileHeight)
     541             : {
     542             :     // This method does 2 things:
     543             :     // - warn the user if he tries to write NaN values with libtiff < 4.6.1
     544             :     //   and multi-band PlanarConfig=Contig configuration
     545             :     // - and in right-most and bottom-most tiles, replace non accessible
     546             :     //   pixel values by a safe one.
     547             : 
     548           0 :     const auto fPaddingValue =
     549             : #if !defined(LIBTIFF_MULTIBAND_LERC_NAN_OK)
     550             :         m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands > 1
     551             :             ? 0
     552             :             :
     553             : #endif
     554             :             std::numeric_limits<T>::quiet_NaN();
     555             : 
     556           0 :     const int nBandsPerStrile =
     557           0 :         m_nPlanarConfig == PLANARCONFIG_CONTIG ? nBands : 1;
     558           0 :     for (int j = 0; j < nActualBlockHeight; ++j)
     559             :     {
     560             : #if !defined(LIBTIFF_MULTIBAND_LERC_NAN_OK)
     561             :         static bool bHasWarned = false;
     562             :         if (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands > 1 && !bHasWarned)
     563             :         {
     564             :             for (int i = 0; i < nActualBlockWidth * nBandsPerStrile; ++i)
     565             :             {
     566             :                 if (std::isnan(
     567             :                         pBuffer[j * m_nBlockXSize * nBandsPerStrile + i]))
     568             :                 {
     569             :                     bHasWarned = true;
     570             :                     CPLError(CE_Warning, CPLE_AppDefined,
     571             :                              "libtiff < 4.6.1 does not handle properly NaN "
     572             :                              "values for multi-band PlanarConfig=Contig "
     573             :                              "configuration. As a workaround, you can set the "
     574             :                              "INTERLEAVE=BAND creation option.");
     575             :                     break;
     576             :                 }
     577             :             }
     578             :         }
     579             : #endif
     580           0 :         for (int i = nActualBlockWidth * nBandsPerStrile;
     581           0 :              i < m_nBlockXSize * nBandsPerStrile; ++i)
     582             :         {
     583           0 :             pBuffer[j * m_nBlockXSize * nBandsPerStrile + i] = fPaddingValue;
     584             :         }
     585             :     }
     586           0 :     for (int j = nActualBlockHeight; j < nStrileHeight; ++j)
     587             :     {
     588           0 :         for (int i = 0; i < m_nBlockXSize * nBandsPerStrile; ++i)
     589             :         {
     590           0 :             pBuffer[j * m_nBlockXSize * nBandsPerStrile + i] = fPaddingValue;
     591             :         }
     592             :     }
     593           0 : }
     594             : 
     595             : /************************************************************************/
     596             : /*                        WriteEncodedTile()                            */
     597             : /************************************************************************/
     598             : 
     599       49834 : bool GTiffDataset::WriteEncodedTile(uint32_t tile, GByte *pabyData,
     600             :                                     int bPreserveDataBuffer)
     601             : {
     602       49834 :     const int iColumn = (tile % m_nBlocksPerBand) % m_nBlocksPerRow;
     603       49834 :     const int iRow = (tile % m_nBlocksPerBand) / m_nBlocksPerRow;
     604             : 
     605       99668 :     const int nActualBlockWidth = (iColumn == m_nBlocksPerRow - 1)
     606       49834 :                                       ? nRasterXSize - iColumn * m_nBlockXSize
     607             :                                       : m_nBlockXSize;
     608       99668 :     const int nActualBlockHeight = (iRow == m_nBlocksPerColumn - 1)
     609       49834 :                                        ? nRasterYSize - iRow * m_nBlockYSize
     610             :                                        : m_nBlockYSize;
     611             : 
     612             :     /* -------------------------------------------------------------------- */
     613             :     /*      Don't write empty blocks in some cases.                         */
     614             :     /* -------------------------------------------------------------------- */
     615       49834 :     if (!m_bWriteEmptyTiles && IsFirstPixelEqualToNoData(pabyData))
     616             :     {
     617        1938 :         if (!IsBlockAvailable(tile, nullptr, nullptr, nullptr))
     618             :         {
     619        1938 :             const int nComponents =
     620        1938 :                 m_nPlanarConfig == PLANARCONFIG_CONTIG ? nBands : 1;
     621             : 
     622        1938 :             if (HasOnlyNoData(pabyData, nActualBlockWidth, nActualBlockHeight,
     623             :                               m_nBlockXSize, nComponents))
     624             :             {
     625        1188 :                 return true;
     626             :             }
     627             :         }
     628             :     }
     629             : 
     630             :     // Is this a partial right edge or bottom edge tile?
     631       94458 :     const bool bPartialTile = (nActualBlockWidth < m_nBlockXSize) ||
     632       45812 :                               (nActualBlockHeight < m_nBlockYSize);
     633             : 
     634             :     const bool bIsLercFloatingPoint =
     635       48712 :         m_nCompression == COMPRESSION_LERC &&
     636          66 :         (GetRasterBand(1)->GetRasterDataType() == GDT_Float32 ||
     637          64 :          GetRasterBand(1)->GetRasterDataType() == GDT_Float64);
     638             : 
     639             :     // Do we need to spread edge values right or down for a partial
     640             :     // JPEG encoded tile?  We do this to avoid edge artifacts.
     641             :     // We also need to be careful with LERC and NaN values
     642       48646 :     const bool bNeedTempBuffer =
     643       53049 :         bPartialTile &&
     644        4403 :         (m_nCompression == COMPRESSION_JPEG || bIsLercFloatingPoint);
     645             : 
     646             :     // If we need to fill out the tile, or if we want to prevent
     647             :     // TIFFWriteEncodedTile from altering the buffer as part of
     648             :     // byte swapping the data on write then we will need a temporary
     649             :     // working buffer.  If not, we can just do a direct write.
     650       48646 :     const GPtrDiff_t cc = static_cast<GPtrDiff_t>(TIFFTileSize(m_hTIFF));
     651             : 
     652       62912 :     if (bPreserveDataBuffer &&
     653       14275 :         (TIFFIsByteSwapped(m_hTIFF) || bNeedTempBuffer || m_panMaskOffsetLsb))
     654             :     {
     655         158 :         if (m_pabyTempWriteBuffer == nullptr)
     656             :         {
     657          35 :             m_pabyTempWriteBuffer = CPLMalloc(cc);
     658             :         }
     659         158 :         memcpy(m_pabyTempWriteBuffer, pabyData, cc);
     660             : 
     661         158 :         pabyData = static_cast<GByte *>(m_pabyTempWriteBuffer);
     662             :     }
     663             : 
     664             :     // Perform tile fill if needed.
     665             :     // TODO: we should also handle the case of nBitsPerSample == 12
     666             :     // but this is more involved.
     667       48637 :     if (bPartialTile && m_nCompression == COMPRESSION_JPEG &&
     668         134 :         m_nBitsPerSample == 8)
     669             :     {
     670         132 :         const int nComponents =
     671         132 :             m_nPlanarConfig == PLANARCONFIG_CONTIG ? nBands : 1;
     672             : 
     673         132 :         CPLDebug("GTiff", "Filling out jpeg edge tile on write.");
     674             : 
     675         132 :         const int nRightPixelsToFill =
     676         132 :             iColumn == m_nBlocksPerRow - 1
     677         132 :                 ? m_nBlockXSize * (iColumn + 1) - nRasterXSize
     678             :                 : 0;
     679         132 :         const int nBottomPixelsToFill =
     680         132 :             iRow == m_nBlocksPerColumn - 1
     681         132 :                 ? m_nBlockYSize * (iRow + 1) - nRasterYSize
     682             :                 : 0;
     683             : 
     684             :         // Fill out to the right.
     685         132 :         const int iSrcX = m_nBlockXSize - nRightPixelsToFill - 1;
     686             : 
     687       12461 :         for (int iX = iSrcX + 1; iX < m_nBlockXSize; ++iX)
     688             :         {
     689     3955880 :             for (int iY = 0; iY < m_nBlockYSize; ++iY)
     690             :             {
     691     3943550 :                 memcpy(pabyData +
     692     3943550 :                            (static_cast<GPtrDiff_t>(m_nBlockXSize) * iY + iX) *
     693     3943550 :                                nComponents,
     694     3943550 :                        pabyData + (static_cast<GPtrDiff_t>(m_nBlockXSize) * iY +
     695     3943550 :                                    iSrcX) *
     696     3943550 :                                       nComponents,
     697             :                        nComponents);
     698             :             }
     699             :         }
     700             : 
     701             :         // Now fill out the bottom.
     702         132 :         const int iSrcY = m_nBlockYSize - nBottomPixelsToFill - 1;
     703       17682 :         for (int iY = iSrcY + 1; iY < m_nBlockYSize; ++iY)
     704             :         {
     705       17550 :             memcpy(pabyData + static_cast<GPtrDiff_t>(m_nBlockXSize) *
     706       17550 :                                   nComponents * iY,
     707       17550 :                    pabyData + static_cast<GPtrDiff_t>(m_nBlockXSize) *
     708       17550 :                                   nComponents * iSrcY,
     709       17550 :                    static_cast<GPtrDiff_t>(m_nBlockXSize) * nComponents);
     710             :         }
     711             :     }
     712             : 
     713       48637 :     if (bIsLercFloatingPoint &&
     714             :         (bPartialTile
     715             : #if !defined(LIBTIFF_MULTIBAND_LERC_NAN_OK)
     716             :          /* libtiff < 4.6.1 doesn't generate a LERC mask for multi-band contig configuration */
     717             :          || (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands > 1)
     718             : #endif
     719             :              ))
     720             :     {
     721           0 :         if (GetRasterBand(1)->GetRasterDataType() == GDT_Float32)
     722           0 :             WriteDealWithLercAndNan(reinterpret_cast<float *>(pabyData),
     723             :                                     nActualBlockWidth, nActualBlockHeight,
     724             :                                     m_nBlockYSize);
     725             :         else
     726           0 :             WriteDealWithLercAndNan(reinterpret_cast<double *>(pabyData),
     727             :                                     nActualBlockWidth, nActualBlockHeight,
     728             :                                     m_nBlockYSize);
     729             :     }
     730             : 
     731       48637 :     if (m_panMaskOffsetLsb)
     732             :     {
     733           0 :         const int iBand = m_nPlanarConfig == PLANARCONFIG_SEPARATE
     734           0 :                               ? static_cast<int>(tile) / m_nBlocksPerBand
     735             :                               : -1;
     736           0 :         DiscardLsb(pabyData, cc, iBand);
     737             :     }
     738             : 
     739       48635 :     if (m_bStreamingOut)
     740             :     {
     741          17 :         if (tile != static_cast<uint32_t>(m_nLastWrittenBlockId + 1))
     742             :         {
     743           1 :             ReportError(CE_Failure, CPLE_NotSupported,
     744             :                         "Attempt to write block %d whereas %d was expected",
     745           1 :                         tile, m_nLastWrittenBlockId + 1);
     746           1 :             return false;
     747             :         }
     748          16 :         if (static_cast<GPtrDiff_t>(VSIFWriteL(pabyData, 1, cc, m_fpToWrite)) !=
     749             :             cc)
     750             :         {
     751           0 :             ReportError(CE_Failure, CPLE_FileIO,
     752             :                         "Could not write " CPL_FRMT_GUIB " bytes",
     753             :                         static_cast<GUIntBig>(cc));
     754           0 :             return false;
     755             :         }
     756          16 :         m_nLastWrittenBlockId = tile;
     757          16 :         return true;
     758             :     }
     759             : 
     760             :     /* -------------------------------------------------------------------- */
     761             :     /*      Should we do compression in a worker thread ?                   */
     762             :     /* -------------------------------------------------------------------- */
     763       48618 :     if (SubmitCompressionJob(tile, pabyData, cc, m_nBlockYSize))
     764       19771 :         return true;
     765             : 
     766       28846 :     return TIFFWriteEncodedTile(m_hTIFF, tile, pabyData, cc) == cc;
     767             : }
     768             : 
     769             : /************************************************************************/
     770             : /*                        WriteEncodedStrip()                           */
     771             : /************************************************************************/
     772             : 
     773      165487 : bool GTiffDataset::WriteEncodedStrip(uint32_t strip, GByte *pabyData,
     774             :                                      int bPreserveDataBuffer)
     775             : {
     776      165487 :     GPtrDiff_t cc = static_cast<GPtrDiff_t>(TIFFStripSize(m_hTIFF));
     777      165493 :     const auto ccFull = cc;
     778             : 
     779             :     /* -------------------------------------------------------------------- */
     780             :     /*      If this is the last strip in the image, and is partial, then    */
     781             :     /*      we need to trim the number of scanlines written to the          */
     782             :     /*      amount of valid data we have. (#2748)                           */
     783             :     /* -------------------------------------------------------------------- */
     784      165493 :     const int nStripWithinBand = strip % m_nBlocksPerBand;
     785      165493 :     int nStripHeight = m_nRowsPerStrip;
     786             : 
     787      165493 :     if (nStripWithinBand * nStripHeight > GetRasterYSize() - nStripHeight)
     788             :     {
     789         376 :         nStripHeight = GetRasterYSize() - nStripWithinBand * m_nRowsPerStrip;
     790         376 :         cc = (cc / m_nRowsPerStrip) * nStripHeight;
     791         752 :         CPLDebug("GTiff",
     792             :                  "Adjusted bytes to write from " CPL_FRMT_GUIB
     793             :                  " to " CPL_FRMT_GUIB ".",
     794         376 :                  static_cast<GUIntBig>(TIFFStripSize(m_hTIFF)),
     795             :                  static_cast<GUIntBig>(cc));
     796             :     }
     797             : 
     798             :     /* -------------------------------------------------------------------- */
     799             :     /*      Don't write empty blocks in some cases.                         */
     800             :     /* -------------------------------------------------------------------- */
     801      165491 :     if (!m_bWriteEmptyTiles && IsFirstPixelEqualToNoData(pabyData))
     802             :     {
     803       40496 :         if (!IsBlockAvailable(strip, nullptr, nullptr, nullptr))
     804             :         {
     805       40326 :             const int nComponents =
     806       40326 :                 m_nPlanarConfig == PLANARCONFIG_CONTIG ? nBands : 1;
     807             : 
     808       40326 :             if (HasOnlyNoData(pabyData, m_nBlockXSize, nStripHeight,
     809             :                               m_nBlockXSize, nComponents))
     810             :             {
     811       28296 :                 return true;
     812             :             }
     813             :         }
     814             :     }
     815             : 
     816             :     /* -------------------------------------------------------------------- */
     817             :     /*      TIFFWriteEncodedStrip can alter the passed buffer if            */
     818             :     /*      byte-swapping is necessary so we use a temporary buffer         */
     819             :     /*      before calling it.                                              */
     820             :     /* -------------------------------------------------------------------- */
     821      226406 :     if (bPreserveDataBuffer &&
     822       89208 :         (TIFFIsByteSwapped(m_hTIFF) || m_panMaskOffsetLsb))
     823             :     {
     824         294 :         if (m_pabyTempWriteBuffer == nullptr)
     825             :         {
     826         126 :             m_pabyTempWriteBuffer = CPLMalloc(ccFull);
     827             :         }
     828         294 :         memcpy(m_pabyTempWriteBuffer, pabyData, cc);
     829         294 :         pabyData = static_cast<GByte *>(m_pabyTempWriteBuffer);
     830             :     }
     831             : 
     832             : #if !defined(LIBTIFF_MULTIBAND_LERC_NAN_OK)
     833             :     const bool bIsLercFloatingPoint =
     834             :         m_nCompression == COMPRESSION_LERC &&
     835             :         (GetRasterBand(1)->GetRasterDataType() == GDT_Float32 ||
     836             :          GetRasterBand(1)->GetRasterDataType() == GDT_Float64);
     837             :     if (bIsLercFloatingPoint &&
     838             :         /* libtiff < 4.6.1 doesn't generate a LERC mask for multi-band contig configuration */
     839             :         m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands > 1)
     840             :     {
     841             :         if (GetRasterBand(1)->GetRasterDataType() == GDT_Float32)
     842             :             WriteDealWithLercAndNan(reinterpret_cast<float *>(pabyData),
     843             :                                     m_nBlockXSize, nStripHeight, nStripHeight);
     844             :         else
     845             :             WriteDealWithLercAndNan(reinterpret_cast<double *>(pabyData),
     846             :                                     m_nBlockXSize, nStripHeight, nStripHeight);
     847             :     }
     848             : #endif
     849             : 
     850      137198 :     if (m_panMaskOffsetLsb)
     851             :     {
     852         366 :         int iBand = m_nPlanarConfig == PLANARCONFIG_SEPARATE
     853         183 :                         ? static_cast<int>(strip) / m_nBlocksPerBand
     854             :                         : -1;
     855         183 :         DiscardLsb(pabyData, cc, iBand);
     856             :     }
     857             : 
     858      137194 :     if (m_bStreamingOut)
     859             :     {
     860        1408 :         if (strip != static_cast<uint32_t>(m_nLastWrittenBlockId + 1))
     861             :         {
     862           1 :             ReportError(CE_Failure, CPLE_NotSupported,
     863             :                         "Attempt to write block %d whereas %d was expected",
     864           1 :                         strip, m_nLastWrittenBlockId + 1);
     865           1 :             return false;
     866             :         }
     867        1407 :         if (static_cast<GPtrDiff_t>(VSIFWriteL(pabyData, 1, cc, m_fpToWrite)) !=
     868             :             cc)
     869             :         {
     870           0 :             ReportError(CE_Failure, CPLE_FileIO,
     871             :                         "Could not write " CPL_FRMT_GUIB " bytes",
     872             :                         static_cast<GUIntBig>(cc));
     873           0 :             return false;
     874             :         }
     875        1407 :         m_nLastWrittenBlockId = strip;
     876        1407 :         return true;
     877             :     }
     878             : 
     879             :     /* -------------------------------------------------------------------- */
     880             :     /*      Should we do compression in a worker thread ?                   */
     881             :     /* -------------------------------------------------------------------- */
     882      135786 :     if (SubmitCompressionJob(strip, pabyData, cc, nStripHeight))
     883        6731 :         return true;
     884             : 
     885      129053 :     return TIFFWriteEncodedStrip(m_hTIFF, strip, pabyData, cc) == cc;
     886             : }
     887             : 
     888             : /************************************************************************/
     889             : /*                        InitCompressionThreads()                      */
     890             : /************************************************************************/
     891             : 
     892       30571 : void GTiffDataset::InitCompressionThreads(bool bUpdateMode,
     893             :                                           CSLConstList papszOptions)
     894             : {
     895             :     // Raster == tile, then no need for threads
     896       30571 :     if (m_nBlockXSize == nRasterXSize && m_nBlockYSize == nRasterYSize)
     897       22484 :         return;
     898             : 
     899        8087 :     const char *pszValue = CSLFetchNameValue(papszOptions, "NUM_THREADS");
     900        8203 :     if (pszValue == nullptr)
     901        8137 :         pszValue = CPLGetConfigOption("GDAL_NUM_THREADS", nullptr);
     902        8210 :     if (pszValue)
     903             :     {
     904             :         int nThreads =
     905         108 :             EQUAL(pszValue, "ALL_CPUS") ? CPLGetNumCPUs() : atoi(pszValue);
     906         108 :         if (nThreads > 1024)
     907           0 :             nThreads = 1024;  // to please Coverity
     908         108 :         if (nThreads > 1)
     909             :         {
     910          92 :             if ((bUpdateMode && m_nCompression != COMPRESSION_NONE) ||
     911          17 :                 (nBands >= 1 && IsMultiThreadedReadCompatible()))
     912             :             {
     913          70 :                 CPLDebug("GTiff",
     914             :                          "Using up to %d threads for compression/decompression",
     915             :                          nThreads);
     916             : 
     917          70 :                 m_poThreadPool = GDALGetGlobalThreadPool(nThreads);
     918          70 :                 if (bUpdateMode && m_poThreadPool)
     919          58 :                     m_poCompressQueue = m_poThreadPool->CreateJobQueue();
     920             : 
     921          70 :                 if (m_poCompressQueue != nullptr)
     922             :                 {
     923             :                     // Add a margin of an extra job w.r.t thread number
     924             :                     // so as to optimize compression time (enables the main
     925             :                     // thread to do boring I/O while all CPUs are working).
     926          58 :                     m_asCompressionJobs.resize(nThreads + 1);
     927          58 :                     memset(&m_asCompressionJobs[0], 0,
     928          58 :                            m_asCompressionJobs.size() *
     929             :                                sizeof(GTiffCompressionJob));
     930          58 :                     for (int i = 0;
     931         280 :                          i < static_cast<int>(m_asCompressionJobs.size()); ++i)
     932             :                     {
     933         444 :                         m_asCompressionJobs[i].pszTmpFilename =
     934         222 :                             CPLStrdup(VSIMemGenerateHiddenFilename(
     935             :                                 CPLSPrintf("thread_job_%d.tif", i)));
     936         222 :                         m_asCompressionJobs[i].nStripOrTile = -1;
     937             :                     }
     938             : 
     939             :                     // This is kind of a hack, but basically using
     940             :                     // TIFFWriteRawStrip/Tile and then TIFFReadEncodedStrip/Tile
     941             :                     // does not work on a newly created file, because
     942             :                     // TIFF_MYBUFFER is not set in tif_flags
     943             :                     // (if using TIFFWriteEncodedStrip/Tile first,
     944             :                     // TIFFWriteBufferSetup() is automatically called).
     945             :                     // This should likely rather fixed in libtiff itself.
     946          58 :                     CPL_IGNORE_RET_VAL(
     947          58 :                         TIFFWriteBufferSetup(m_hTIFF, nullptr, -1));
     948             :                 }
     949             :             }
     950             :         }
     951          33 :         else if (nThreads < 0 ||
     952          33 :                  (!EQUAL(pszValue, "0") && !EQUAL(pszValue, "1") &&
     953           3 :                   !EQUAL(pszValue, "ALL_CPUS")))
     954             :         {
     955           3 :             ReportError(CE_Warning, CPLE_AppDefined,
     956             :                         "Invalid value for NUM_THREADS: %s", pszValue);
     957             :         }
     958             :     }
     959             : }
     960             : 
     961             : /************************************************************************/
     962             : /*                      ThreadCompressionFunc()                         */
     963             : /************************************************************************/
     964             : 
     965       26513 : void GTiffDataset::ThreadCompressionFunc(void *pData)
     966             : {
     967       26513 :     GTiffCompressionJob *psJob = static_cast<GTiffCompressionJob *>(pData);
     968       26513 :     GTiffDataset *poDS = psJob->poDS;
     969             : 
     970       26513 :     VSILFILE *fpTmp = VSIFOpenL(psJob->pszTmpFilename, "wb+");
     971       26514 :     TIFF *hTIFFTmp = VSI_TIFFOpen(
     972       53028 :         psJob->pszTmpFilename, psJob->bTIFFIsBigEndian ? "wb+" : "wl+", fpTmp);
     973       26514 :     CPLAssert(hTIFFTmp != nullptr);
     974       26514 :     TIFFSetField(hTIFFTmp, TIFFTAG_IMAGEWIDTH, poDS->m_nBlockXSize);
     975       26514 :     TIFFSetField(hTIFFTmp, TIFFTAG_IMAGELENGTH, psJob->nHeight);
     976       26514 :     TIFFSetField(hTIFFTmp, TIFFTAG_BITSPERSAMPLE, poDS->m_nBitsPerSample);
     977       26514 :     TIFFSetField(hTIFFTmp, TIFFTAG_COMPRESSION, poDS->m_nCompression);
     978       26514 :     TIFFSetField(hTIFFTmp, TIFFTAG_PHOTOMETRIC, poDS->m_nPhotometric);
     979       26514 :     TIFFSetField(hTIFFTmp, TIFFTAG_SAMPLEFORMAT, poDS->m_nSampleFormat);
     980       26514 :     TIFFSetField(hTIFFTmp, TIFFTAG_SAMPLESPERPIXEL, poDS->m_nSamplesPerPixel);
     981       26514 :     TIFFSetField(hTIFFTmp, TIFFTAG_ROWSPERSTRIP, poDS->m_nBlockYSize);
     982       26513 :     TIFFSetField(hTIFFTmp, TIFFTAG_PLANARCONFIG, poDS->m_nPlanarConfig);
     983       26514 :     if (psJob->nPredictor != PREDICTOR_NONE)
     984         262 :         TIFFSetField(hTIFFTmp, TIFFTAG_PREDICTOR, psJob->nPredictor);
     985       26514 :     if (poDS->m_nCompression == COMPRESSION_LERC)
     986             :     {
     987          24 :         TIFFSetField(hTIFFTmp, TIFFTAG_LERC_PARAMETERS, 2,
     988          24 :                      poDS->m_anLercAddCompressionAndVersion);
     989             :     }
     990       26514 :     if (psJob->nExtraSampleCount)
     991             :     {
     992         336 :         TIFFSetField(hTIFFTmp, TIFFTAG_EXTRASAMPLES, psJob->nExtraSampleCount,
     993             :                      psJob->pExtraSamples);
     994             :     }
     995             : 
     996       26514 :     poDS->RestoreVolatileParameters(hTIFFTmp);
     997             : 
     998       53022 :     bool bOK = TIFFWriteEncodedStrip(hTIFFTmp, 0, psJob->pabyBuffer,
     999       26513 :                                      psJob->nBufferSize) == psJob->nBufferSize;
    1000             : 
    1001       26509 :     toff_t nOffset = 0;
    1002       26509 :     if (bOK)
    1003             :     {
    1004       26509 :         toff_t *panOffsets = nullptr;
    1005       26509 :         toff_t *panByteCounts = nullptr;
    1006       26509 :         TIFFGetField(hTIFFTmp, TIFFTAG_STRIPOFFSETS, &panOffsets);
    1007       26509 :         TIFFGetField(hTIFFTmp, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts);
    1008             : 
    1009       26511 :         nOffset = panOffsets[0];
    1010       26511 :         psJob->nCompressedBufferSize =
    1011       26511 :             static_cast<GPtrDiff_t>(panByteCounts[0]);
    1012             :     }
    1013             :     else
    1014             :     {
    1015           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1016             :                  "Error when compressing strip/tile %d", psJob->nStripOrTile);
    1017             :     }
    1018             : 
    1019       26511 :     XTIFFClose(hTIFFTmp);
    1020       26513 :     if (VSIFCloseL(fpTmp) != 0)
    1021             :     {
    1022           0 :         if (bOK)
    1023             :         {
    1024           0 :             bOK = false;
    1025           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1026             :                      "Error when compressing strip/tile %d",
    1027             :                      psJob->nStripOrTile);
    1028             :         }
    1029             :     }
    1030             : 
    1031       26509 :     if (bOK)
    1032             :     {
    1033       26509 :         vsi_l_offset nFileSize = 0;
    1034             :         GByte *pabyCompressedBuffer =
    1035       26509 :             VSIGetMemFileBuffer(psJob->pszTmpFilename, &nFileSize, FALSE);
    1036       26514 :         CPLAssert(static_cast<vsi_l_offset>(
    1037             :                       nOffset + psJob->nCompressedBufferSize) <= nFileSize);
    1038       26514 :         psJob->pabyCompressedBuffer = pabyCompressedBuffer + nOffset;
    1039             :     }
    1040             :     else
    1041             :     {
    1042           0 :         psJob->pabyCompressedBuffer = nullptr;
    1043           0 :         psJob->nCompressedBufferSize = 0;
    1044             :     }
    1045             : 
    1046       26514 :     auto poMainDS = poDS->m_poBaseDS ? poDS->m_poBaseDS : poDS;
    1047       26514 :     if (poMainDS->m_poCompressQueue)
    1048             :     {
    1049        1576 :         std::lock_guard oLock(poMainDS->m_oCompressThreadPoolMutex);
    1050        1576 :         psJob->bReady = true;
    1051             :     }
    1052       26514 : }
    1053             : 
    1054             : /************************************************************************/
    1055             : /*                        WriteRawStripOrTile()                         */
    1056             : /************************************************************************/
    1057             : 
    1058       33814 : void GTiffDataset::WriteRawStripOrTile(int nStripOrTile,
    1059             :                                        GByte *pabyCompressedBuffer,
    1060             :                                        GPtrDiff_t nCompressedBufferSize)
    1061             : {
    1062             : #ifdef DEBUG_VERBOSE
    1063             :     CPLDebug("GTIFF", "Writing raw strip/tile %d, size " CPL_FRMT_GUIB,
    1064             :              nStripOrTile, static_cast<GUIntBig>(nCompressedBufferSize));
    1065             : #endif
    1066       33814 :     toff_t *panOffsets = nullptr;
    1067       33814 :     toff_t *panByteCounts = nullptr;
    1068       33814 :     bool bWriteAtEnd = true;
    1069       33814 :     bool bWriteLeader = m_bLeaderSizeAsUInt4;
    1070       33814 :     bool bWriteTrailer = m_bTrailerRepeatedLast4BytesRepeated;
    1071       33814 :     if (TIFFGetField(m_hTIFF,
    1072       33814 :                      TIFFIsTiled(m_hTIFF) ? TIFFTAG_TILEOFFSETS
    1073             :                                           : TIFFTAG_STRIPOFFSETS,
    1074       33814 :                      &panOffsets) &&
    1075       33814 :         panOffsets != nullptr && panOffsets[nStripOrTile] != 0)
    1076             :     {
    1077             :         // Forces TIFFAppendStrip() to consider if the location of the
    1078             :         // tile/strip can be reused or if the strile should be written at end of
    1079             :         // file.
    1080         360 :         TIFFSetWriteOffset(m_hTIFF, 0);
    1081             : 
    1082         360 :         if (m_bBlockOrderRowMajor)
    1083             :         {
    1084         264 :             if (TIFFGetField(m_hTIFF,
    1085         264 :                              TIFFIsTiled(m_hTIFF) ? TIFFTAG_TILEBYTECOUNTS
    1086             :                                                   : TIFFTAG_STRIPBYTECOUNTS,
    1087         528 :                              &panByteCounts) &&
    1088         264 :                 panByteCounts != nullptr)
    1089             :             {
    1090         264 :                 if (static_cast<GUIntBig>(nCompressedBufferSize) >
    1091         264 :                     panByteCounts[nStripOrTile])
    1092             :                 {
    1093           8 :                     GTiffDataset *poRootDS = m_poBaseDS ? m_poBaseDS : this;
    1094           8 :                     if (!poRootDS->m_bKnownIncompatibleEdition &&
    1095           8 :                         !poRootDS->m_bWriteKnownIncompatibleEdition)
    1096             :                     {
    1097           8 :                         ReportError(
    1098             :                             CE_Warning, CPLE_AppDefined,
    1099             :                             "A strile cannot be rewritten in place, which "
    1100             :                             "invalidates the BLOCK_ORDER optimization.");
    1101           8 :                         poRootDS->m_bKnownIncompatibleEdition = true;
    1102           8 :                         poRootDS->m_bWriteKnownIncompatibleEdition = true;
    1103             :                     }
    1104             :                 }
    1105             :                 // For mask interleaving, if the size is not exactly the same,
    1106             :                 // completely give up (we could potentially move the mask in
    1107             :                 // case the imagery is smaller)
    1108         256 :                 else if (m_poMaskDS && m_bMaskInterleavedWithImagery &&
    1109           0 :                          static_cast<GUIntBig>(nCompressedBufferSize) !=
    1110           0 :                              panByteCounts[nStripOrTile])
    1111             :                 {
    1112           0 :                     GTiffDataset *poRootDS = m_poBaseDS ? m_poBaseDS : this;
    1113           0 :                     if (!poRootDS->m_bKnownIncompatibleEdition &&
    1114           0 :                         !poRootDS->m_bWriteKnownIncompatibleEdition)
    1115             :                     {
    1116           0 :                         ReportError(
    1117             :                             CE_Warning, CPLE_AppDefined,
    1118             :                             "A strile cannot be rewritten in place, which "
    1119             :                             "invalidates the MASK_INTERLEAVED_WITH_IMAGERY "
    1120             :                             "optimization.");
    1121           0 :                         poRootDS->m_bKnownIncompatibleEdition = true;
    1122           0 :                         poRootDS->m_bWriteKnownIncompatibleEdition = true;
    1123             :                     }
    1124           0 :                     bWriteLeader = false;
    1125           0 :                     bWriteTrailer = false;
    1126           0 :                     if (m_bLeaderSizeAsUInt4)
    1127             :                     {
    1128             :                         // If there was a valid leader, invalidat it
    1129           0 :                         VSI_TIFFSeek(m_hTIFF, panOffsets[nStripOrTile] - 4,
    1130             :                                      SEEK_SET);
    1131             :                         uint32_t nOldSize;
    1132           0 :                         VSIFReadL(&nOldSize, 1, 4,
    1133             :                                   VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF)));
    1134           0 :                         CPL_LSBPTR32(&nOldSize);
    1135           0 :                         if (nOldSize == panByteCounts[nStripOrTile])
    1136             :                         {
    1137           0 :                             uint32_t nInvalidatedSize = 0;
    1138           0 :                             VSI_TIFFSeek(m_hTIFF, panOffsets[nStripOrTile] - 4,
    1139             :                                          SEEK_SET);
    1140           0 :                             VSI_TIFFWrite(m_hTIFF, &nInvalidatedSize,
    1141             :                                           sizeof(nInvalidatedSize));
    1142             :                         }
    1143           0 :                     }
    1144             :                 }
    1145             :                 else
    1146             :                 {
    1147         256 :                     bWriteAtEnd = false;
    1148             :                 }
    1149             :             }
    1150             :         }
    1151             :     }
    1152       33814 :     if (bWriteLeader &&
    1153       24943 :         static_cast<GUIntBig>(nCompressedBufferSize) <= 0xFFFFFFFFU)
    1154             :     {
    1155             :         // cppcheck-suppress knownConditionTrueFalse
    1156       24943 :         if (bWriteAtEnd)
    1157             :         {
    1158       24687 :             VSI_TIFFSeek(m_hTIFF, 0, SEEK_END);
    1159             :         }
    1160             :         else
    1161             :         {
    1162             :             // If we rewrite an existing strile in place with an existing
    1163             :             // leader, check that the leader is valid, before rewriting it. And
    1164             :             // if it is not valid, then do not write the trailer, as we could
    1165             :             // corrupt other data.
    1166         256 :             VSI_TIFFSeek(m_hTIFF, panOffsets[nStripOrTile] - 4, SEEK_SET);
    1167             :             uint32_t nOldSize;
    1168         256 :             VSIFReadL(&nOldSize, 1, 4,
    1169             :                       VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF)));
    1170         256 :             CPL_LSBPTR32(&nOldSize);
    1171         256 :             bWriteLeader =
    1172         256 :                 panByteCounts && nOldSize == panByteCounts[nStripOrTile];
    1173         256 :             bWriteTrailer = bWriteLeader;
    1174         256 :             VSI_TIFFSeek(m_hTIFF, panOffsets[nStripOrTile] - 4, SEEK_SET);
    1175             :         }
    1176             :         // cppcheck-suppress knownConditionTrueFalse
    1177       24943 :         if (bWriteLeader)
    1178             :         {
    1179       24943 :             uint32_t nSize = static_cast<uint32_t>(nCompressedBufferSize);
    1180       24943 :             CPL_LSBPTR32(&nSize);
    1181       24943 :             if (!VSI_TIFFWrite(m_hTIFF, &nSize, sizeof(nSize)))
    1182           0 :                 m_bWriteError = true;
    1183             :         }
    1184             :     }
    1185             :     tmsize_t written;
    1186       33814 :     if (TIFFIsTiled(m_hTIFF))
    1187       26157 :         written = TIFFWriteRawTile(m_hTIFF, nStripOrTile, pabyCompressedBuffer,
    1188             :                                    nCompressedBufferSize);
    1189             :     else
    1190        7657 :         written = TIFFWriteRawStrip(m_hTIFF, nStripOrTile, pabyCompressedBuffer,
    1191             :                                     nCompressedBufferSize);
    1192       33814 :     if (written != nCompressedBufferSize)
    1193          12 :         m_bWriteError = true;
    1194       33814 :     if (bWriteTrailer &&
    1195       24943 :         static_cast<GUIntBig>(nCompressedBufferSize) <= 0xFFFFFFFFU)
    1196             :     {
    1197       24943 :         GByte abyLastBytes[4] = {};
    1198       24943 :         if (nCompressedBufferSize >= 4)
    1199       24943 :             memcpy(abyLastBytes,
    1200       24943 :                    pabyCompressedBuffer + nCompressedBufferSize - 4, 4);
    1201             :         else
    1202           0 :             memcpy(abyLastBytes, pabyCompressedBuffer, nCompressedBufferSize);
    1203       24943 :         if (!VSI_TIFFWrite(m_hTIFF, abyLastBytes, 4))
    1204           0 :             m_bWriteError = true;
    1205             :     }
    1206       33814 : }
    1207             : 
    1208             : /************************************************************************/
    1209             : /*                        WaitCompletionForJobIdx()                     */
    1210             : /************************************************************************/
    1211             : 
    1212        1576 : void GTiffDataset::WaitCompletionForJobIdx(int i)
    1213             : {
    1214        1576 :     auto poMainDS = m_poBaseDS ? m_poBaseDS : this;
    1215        1576 :     auto poQueue = poMainDS->m_poCompressQueue.get();
    1216        1576 :     auto &oQueue = poMainDS->m_asQueueJobIdx;
    1217        1576 :     auto &asJobs = poMainDS->m_asCompressionJobs;
    1218        1576 :     auto &mutex = poMainDS->m_oCompressThreadPoolMutex;
    1219             : 
    1220        1576 :     CPLAssert(i >= 0 && static_cast<size_t>(i) < asJobs.size());
    1221        1576 :     CPLAssert(asJobs[i].nStripOrTile >= 0);
    1222        1576 :     CPLAssert(!oQueue.empty());
    1223             : 
    1224        1576 :     bool bHasWarned = false;
    1225             :     while (true)
    1226             :     {
    1227             :         bool bReady;
    1228             :         {
    1229        2291 :             std::lock_guard oLock(mutex);
    1230        2291 :             bReady = asJobs[i].bReady;
    1231             :         }
    1232        2291 :         if (!bReady)
    1233             :         {
    1234         715 :             if (!bHasWarned)
    1235             :             {
    1236         477 :                 CPLDebug("GTIFF",
    1237             :                          "Waiting for worker job to finish handling block %d",
    1238         477 :                          asJobs[i].nStripOrTile);
    1239         477 :                 bHasWarned = true;
    1240             :             }
    1241         715 :             poQueue->GetPool()->WaitEvent();
    1242             :         }
    1243             :         else
    1244             :         {
    1245        1576 :             break;
    1246             :         }
    1247         715 :     }
    1248             : 
    1249        1576 :     if (asJobs[i].nCompressedBufferSize)
    1250             :     {
    1251        3152 :         asJobs[i].poDS->WriteRawStripOrTile(asJobs[i].nStripOrTile,
    1252        1576 :                                             asJobs[i].pabyCompressedBuffer,
    1253        1576 :                                             asJobs[i].nCompressedBufferSize);
    1254             :     }
    1255        1576 :     asJobs[i].pabyCompressedBuffer = nullptr;
    1256        1576 :     asJobs[i].nBufferSize = 0;
    1257             :     {
    1258             :         // Likely useless, but makes Coverity happy
    1259        1576 :         std::lock_guard oLock(mutex);
    1260        1576 :         asJobs[i].bReady = false;
    1261             :     }
    1262        1576 :     asJobs[i].nStripOrTile = -1;
    1263        1576 :     oQueue.pop();
    1264        1576 : }
    1265             : 
    1266             : /************************************************************************/
    1267             : /*                        WaitCompletionForBlock()                      */
    1268             : /************************************************************************/
    1269             : 
    1270     2300550 : void GTiffDataset::WaitCompletionForBlock(int nBlockId)
    1271             : {
    1272     2300550 :     auto poQueue = m_poBaseDS ? m_poBaseDS->m_poCompressQueue.get()
    1273     2281400 :                               : m_poCompressQueue.get();
    1274             :     // cppcheck-suppress constVariableReference
    1275     2300540 :     auto &oQueue = m_poBaseDS ? m_poBaseDS->m_asQueueJobIdx : m_asQueueJobIdx;
    1276             :     // cppcheck-suppress constVariableReference
    1277     2281390 :     auto &asJobs =
    1278     2300540 :         m_poBaseDS ? m_poBaseDS->m_asCompressionJobs : m_asCompressionJobs;
    1279             : 
    1280     2300540 :     if (poQueue != nullptr && !oQueue.empty())
    1281             :     {
    1282        1066 :         for (int i = 0; i < static_cast<int>(asJobs.size()); ++i)
    1283             :         {
    1284         888 :             if (asJobs[i].poDS == this && asJobs[i].nStripOrTile == nBlockId)
    1285             :             {
    1286         128 :                 while (!oQueue.empty() &&
    1287          64 :                        !(asJobs[oQueue.front()].poDS == this &&
    1288          64 :                          asJobs[oQueue.front()].nStripOrTile == nBlockId))
    1289             :                 {
    1290           0 :                     WaitCompletionForJobIdx(oQueue.front());
    1291             :                 }
    1292          64 :                 CPLAssert(!oQueue.empty() &&
    1293             :                           asJobs[oQueue.front()].poDS == this &&
    1294             :                           asJobs[oQueue.front()].nStripOrTile == nBlockId);
    1295          64 :                 WaitCompletionForJobIdx(oQueue.front());
    1296             :             }
    1297             :         }
    1298             :     }
    1299     2300540 : }
    1300             : 
    1301             : /************************************************************************/
    1302             : /*                      SubmitCompressionJob()                          */
    1303             : /************************************************************************/
    1304             : 
    1305      184422 : bool GTiffDataset::SubmitCompressionJob(int nStripOrTile, GByte *pabyData,
    1306             :                                         GPtrDiff_t cc, int nHeight)
    1307             : {
    1308             :     /* -------------------------------------------------------------------- */
    1309             :     /*      Should we do compression in a worker thread ?                   */
    1310             :     /* -------------------------------------------------------------------- */
    1311      184422 :     auto poQueue = m_poBaseDS ? m_poBaseDS->m_poCompressQueue.get()
    1312      170453 :                               : m_poCompressQueue.get();
    1313             : 
    1314      184405 :     if (poQueue && m_nCompression == COMPRESSION_NONE)
    1315             :     {
    1316             :         // We don't do multi-threaded compression for uncompressed...
    1317             :         // but we must wait for other related compression tasks (e.g mask)
    1318             :         // to be completed
    1319           0 :         poQueue->WaitCompletion();
    1320             : 
    1321             :         // Flush remaining data
    1322             :         // cppcheck-suppress constVariableReference
    1323           0 :         auto &oQueue =
    1324           0 :             m_poBaseDS ? m_poBaseDS->m_asQueueJobIdx : m_asQueueJobIdx;
    1325           0 :         while (!oQueue.empty())
    1326             :         {
    1327           0 :             WaitCompletionForJobIdx(oQueue.front());
    1328             :         }
    1329             :     }
    1330             : 
    1331             :     const auto SetupJob =
    1332      122734 :         [this, pabyData, cc, nHeight, nStripOrTile](GTiffCompressionJob &sJob)
    1333             :     {
    1334       26514 :         sJob.poDS = this;
    1335       26514 :         sJob.bTIFFIsBigEndian = CPL_TO_BOOL(TIFFIsBigEndian(m_hTIFF));
    1336             :         GByte *pabyBuffer =
    1337       26514 :             static_cast<GByte *>(VSI_REALLOC_VERBOSE(sJob.pabyBuffer, cc));
    1338       26514 :         if (!pabyBuffer)
    1339           0 :             return false;
    1340       26514 :         sJob.pabyBuffer = pabyBuffer;
    1341       26514 :         memcpy(sJob.pabyBuffer, pabyData, cc);
    1342       26514 :         sJob.nBufferSize = cc;
    1343       26514 :         sJob.nHeight = nHeight;
    1344       26514 :         sJob.nStripOrTile = nStripOrTile;
    1345       26514 :         sJob.nPredictor = PREDICTOR_NONE;
    1346       26514 :         if (GTIFFSupportsPredictor(m_nCompression))
    1347             :         {
    1348       16678 :             TIFFGetField(m_hTIFF, TIFFTAG_PREDICTOR, &sJob.nPredictor);
    1349             :         }
    1350             : 
    1351       26514 :         sJob.pExtraSamples = nullptr;
    1352       26514 :         sJob.nExtraSampleCount = 0;
    1353       26514 :         TIFFGetField(m_hTIFF, TIFFTAG_EXTRASAMPLES, &sJob.nExtraSampleCount,
    1354             :                      &sJob.pExtraSamples);
    1355       26514 :         return true;
    1356      184405 :     };
    1357             : 
    1358      184405 :     if (poQueue == nullptr || !(m_nCompression == COMPRESSION_ADOBE_DEFLATE ||
    1359         806 :                                 m_nCompression == COMPRESSION_LZW ||
    1360          78 :                                 m_nCompression == COMPRESSION_PACKBITS ||
    1361          72 :                                 m_nCompression == COMPRESSION_LZMA ||
    1362          62 :                                 m_nCompression == COMPRESSION_ZSTD ||
    1363          52 :                                 m_nCompression == COMPRESSION_LERC ||
    1364          46 :                                 m_nCompression == COMPRESSION_JXL ||
    1365          46 :                                 m_nCompression == COMPRESSION_JXL_DNG_1_7 ||
    1366          28 :                                 m_nCompression == COMPRESSION_WEBP ||
    1367          18 :                                 m_nCompression == COMPRESSION_JPEG))
    1368             :     {
    1369      182829 :         if (m_bBlockOrderRowMajor || m_bLeaderSizeAsUInt4 ||
    1370      157895 :             m_bTrailerRepeatedLast4BytesRepeated)
    1371             :         {
    1372             :             GTiffCompressionJob sJob;
    1373       24931 :             memset(&sJob, 0, sizeof(sJob));
    1374       24931 :             if (SetupJob(sJob))
    1375             :             {
    1376       24938 :                 sJob.pszTmpFilename =
    1377       24938 :                     CPLStrdup(VSIMemGenerateHiddenFilename("temp.tif"));
    1378             : 
    1379       24938 :                 ThreadCompressionFunc(&sJob);
    1380             : 
    1381       24938 :                 if (sJob.nCompressedBufferSize)
    1382             :                 {
    1383       24938 :                     sJob.poDS->WriteRawStripOrTile(sJob.nStripOrTile,
    1384             :                                                    sJob.pabyCompressedBuffer,
    1385             :                                                    sJob.nCompressedBufferSize);
    1386             :                 }
    1387             : 
    1388       24938 :                 CPLFree(sJob.pabyBuffer);
    1389       24938 :                 VSIUnlink(sJob.pszTmpFilename);
    1390       24938 :                 CPLFree(sJob.pszTmpFilename);
    1391       24938 :                 return sJob.nCompressedBufferSize > 0 && !m_bWriteError;
    1392             :             }
    1393             :         }
    1394             : 
    1395      157898 :         return false;
    1396             :     }
    1397             : 
    1398        1576 :     auto poMainDS = m_poBaseDS ? m_poBaseDS : this;
    1399        1576 :     auto &oQueue = poMainDS->m_asQueueJobIdx;
    1400        1576 :     auto &asJobs = poMainDS->m_asCompressionJobs;
    1401             : 
    1402        1576 :     int nNextCompressionJobAvail = -1;
    1403             : 
    1404        1576 :     if (oQueue.size() == asJobs.size())
    1405             :     {
    1406        1443 :         CPLAssert(!oQueue.empty());
    1407        1443 :         nNextCompressionJobAvail = oQueue.front();
    1408        1443 :         WaitCompletionForJobIdx(nNextCompressionJobAvail);
    1409             :     }
    1410             :     else
    1411             :     {
    1412         133 :         const int nJobs = static_cast<int>(asJobs.size());
    1413         324 :         for (int i = 0; i < nJobs; ++i)
    1414             :         {
    1415         324 :             if (asJobs[i].nBufferSize == 0)
    1416             :             {
    1417         133 :                 nNextCompressionJobAvail = i;
    1418         133 :                 break;
    1419             :             }
    1420             :         }
    1421             :     }
    1422        1576 :     CPLAssert(nNextCompressionJobAvail >= 0);
    1423             : 
    1424        1576 :     GTiffCompressionJob *psJob = &asJobs[nNextCompressionJobAvail];
    1425        1576 :     bool bOK = SetupJob(*psJob);
    1426        1576 :     if (bOK)
    1427             :     {
    1428        1576 :         poQueue->SubmitJob(ThreadCompressionFunc, psJob);
    1429        1576 :         oQueue.push(nNextCompressionJobAvail);
    1430             :     }
    1431             : 
    1432        1576 :     return bOK;
    1433             : }
    1434             : 
    1435             : /************************************************************************/
    1436             : /*                          DiscardLsb()                                */
    1437             : /************************************************************************/
    1438             : 
    1439         272 : template <class T> bool MustNotDiscardLsb(T value, bool bHasNoData, T nodata)
    1440             : {
    1441         272 :     return bHasNoData && value == nodata;
    1442             : }
    1443             : 
    1444             : template <>
    1445          44 : bool MustNotDiscardLsb<float>(float value, bool bHasNoData, float nodata)
    1446             : {
    1447          44 :     return (bHasNoData && value == nodata) || !std::isfinite(value);
    1448             : }
    1449             : 
    1450             : template <>
    1451          44 : bool MustNotDiscardLsb<double>(double value, bool bHasNoData, double nodata)
    1452             : {
    1453          44 :     return (bHasNoData && value == nodata) || !std::isfinite(value);
    1454             : }
    1455             : 
    1456             : template <class T> T AdjustValue(T value, uint64_t nRoundUpBitTest);
    1457             : 
    1458          10 : template <class T> T AdjustValueInt(T value, uint64_t nRoundUpBitTest)
    1459             : {
    1460          10 :     if (value >=
    1461          10 :         static_cast<T>(std::numeric_limits<T>::max() - (nRoundUpBitTest << 1)))
    1462           0 :         return static_cast<T>(value - (nRoundUpBitTest << 1));
    1463          10 :     return static_cast<T>(value + (nRoundUpBitTest << 1));
    1464             : }
    1465             : 
    1466           0 : template <> int8_t AdjustValue<int8_t>(int8_t value, uint64_t nRoundUpBitTest)
    1467             : {
    1468           0 :     return AdjustValueInt(value, nRoundUpBitTest);
    1469             : }
    1470             : 
    1471             : template <>
    1472           2 : uint8_t AdjustValue<uint8_t>(uint8_t value, uint64_t nRoundUpBitTest)
    1473             : {
    1474           2 :     return AdjustValueInt(value, nRoundUpBitTest);
    1475             : }
    1476             : 
    1477             : template <>
    1478           2 : int16_t AdjustValue<int16_t>(int16_t value, uint64_t nRoundUpBitTest)
    1479             : {
    1480           2 :     return AdjustValueInt(value, nRoundUpBitTest);
    1481             : }
    1482             : 
    1483             : template <>
    1484           2 : uint16_t AdjustValue<uint16_t>(uint16_t value, uint64_t nRoundUpBitTest)
    1485             : {
    1486           2 :     return AdjustValueInt(value, nRoundUpBitTest);
    1487             : }
    1488             : 
    1489             : template <>
    1490           2 : int32_t AdjustValue<int32_t>(int32_t value, uint64_t nRoundUpBitTest)
    1491             : {
    1492           2 :     return AdjustValueInt(value, nRoundUpBitTest);
    1493             : }
    1494             : 
    1495             : template <>
    1496           2 : uint32_t AdjustValue<uint32_t>(uint32_t value, uint64_t nRoundUpBitTest)
    1497             : {
    1498           2 :     return AdjustValueInt(value, nRoundUpBitTest);
    1499             : }
    1500             : 
    1501             : template <>
    1502           0 : int64_t AdjustValue<int64_t>(int64_t value, uint64_t nRoundUpBitTest)
    1503             : {
    1504           0 :     return AdjustValueInt(value, nRoundUpBitTest);
    1505             : }
    1506             : 
    1507             : template <>
    1508           0 : uint64_t AdjustValue<uint64_t>(uint64_t value, uint64_t nRoundUpBitTest)
    1509             : {
    1510           0 :     return AdjustValueInt(value, nRoundUpBitTest);
    1511             : }
    1512             : 
    1513           0 : template <> GFloat16 AdjustValue<GFloat16>(GFloat16 value, uint64_t)
    1514             : {
    1515             :     using std::nextafter;
    1516           0 :     return nextafter(value, cpl::NumericLimits<GFloat16>::max());
    1517             : }
    1518             : 
    1519           0 : template <> float AdjustValue<float>(float value, uint64_t)
    1520             : {
    1521           0 :     return std::nextafter(value, std::numeric_limits<float>::max());
    1522             : }
    1523             : 
    1524           0 : template <> double AdjustValue<double>(double value, uint64_t)
    1525             : {
    1526           0 :     return std::nextafter(value, std::numeric_limits<double>::max());
    1527             : }
    1528             : 
    1529             : template <class Teffective, class T>
    1530             : T RoundValueDiscardLsb(const void *ptr, uint64_t nMask,
    1531             :                        uint64_t nRoundUpBitTest);
    1532             : 
    1533             : template <class T>
    1534          16 : T RoundValueDiscardLsbUnsigned(const void *ptr, uint64_t nMask,
    1535             :                                uint64_t nRoundUpBitTest)
    1536             : {
    1537          32 :     if ((*reinterpret_cast<const T *>(ptr) & nMask) >
    1538          16 :         static_cast<uint64_t>(std::numeric_limits<T>::max()) -
    1539          16 :             (nRoundUpBitTest << 1U))
    1540             :     {
    1541           4 :         return static_cast<T>(std::numeric_limits<T>::max() & nMask);
    1542             :     }
    1543          12 :     const uint64_t newval =
    1544          12 :         (*reinterpret_cast<const T *>(ptr) & nMask) + (nRoundUpBitTest << 1U);
    1545          12 :     return static_cast<T>(newval);
    1546             : }
    1547             : 
    1548             : template <class T>
    1549          18 : T RoundValueDiscardLsbSigned(const void *ptr, uint64_t nMask,
    1550             :                              uint64_t nRoundUpBitTest)
    1551             : {
    1552          18 :     T oldval = *reinterpret_cast<const T *>(ptr);
    1553          18 :     if (oldval < 0)
    1554             :     {
    1555           4 :         return static_cast<T>(oldval & nMask);
    1556             :     }
    1557          14 :     const uint64_t newval =
    1558          14 :         (*reinterpret_cast<const T *>(ptr) & nMask) + (nRoundUpBitTest << 1U);
    1559          14 :     if (newval > static_cast<uint64_t>(std::numeric_limits<T>::max()))
    1560           4 :         return static_cast<T>(std::numeric_limits<T>::max() & nMask);
    1561          10 :     return static_cast<T>(newval);
    1562             : }
    1563             : 
    1564             : template <>
    1565          11 : uint16_t RoundValueDiscardLsb<uint16_t, uint16_t>(const void *ptr,
    1566             :                                                   uint64_t nMask,
    1567             :                                                   uint64_t nRoundUpBitTest)
    1568             : {
    1569          11 :     return RoundValueDiscardLsbUnsigned<uint16_t>(ptr, nMask, nRoundUpBitTest);
    1570             : }
    1571             : 
    1572             : template <>
    1573           5 : uint32_t RoundValueDiscardLsb<uint32_t, uint32_t>(const void *ptr,
    1574             :                                                   uint64_t nMask,
    1575             :                                                   uint64_t nRoundUpBitTest)
    1576             : {
    1577           5 :     return RoundValueDiscardLsbUnsigned<uint32_t>(ptr, nMask, nRoundUpBitTest);
    1578             : }
    1579             : 
    1580             : template <>
    1581           0 : uint64_t RoundValueDiscardLsb<uint64_t, uint64_t>(const void *ptr,
    1582             :                                                   uint64_t nMask,
    1583             :                                                   uint64_t nRoundUpBitTest)
    1584             : {
    1585           0 :     return RoundValueDiscardLsbUnsigned<uint64_t>(ptr, nMask, nRoundUpBitTest);
    1586             : }
    1587             : 
    1588             : template <>
    1589           0 : int8_t RoundValueDiscardLsb<int8_t, int8_t>(const void *ptr, uint64_t nMask,
    1590             :                                             uint64_t nRoundUpBitTest)
    1591             : {
    1592           0 :     return RoundValueDiscardLsbSigned<int8_t>(ptr, nMask, nRoundUpBitTest);
    1593             : }
    1594             : 
    1595             : template <>
    1596          13 : int16_t RoundValueDiscardLsb<int16_t, int16_t>(const void *ptr, uint64_t nMask,
    1597             :                                                uint64_t nRoundUpBitTest)
    1598             : {
    1599          13 :     return RoundValueDiscardLsbSigned<int16_t>(ptr, nMask, nRoundUpBitTest);
    1600             : }
    1601             : 
    1602             : template <>
    1603           5 : int32_t RoundValueDiscardLsb<int32_t, int32_t>(const void *ptr, uint64_t nMask,
    1604             :                                                uint64_t nRoundUpBitTest)
    1605             : {
    1606           5 :     return RoundValueDiscardLsbSigned<int32_t>(ptr, nMask, nRoundUpBitTest);
    1607             : }
    1608             : 
    1609             : template <>
    1610           0 : int64_t RoundValueDiscardLsb<int64_t, int64_t>(const void *ptr, uint64_t nMask,
    1611             :                                                uint64_t nRoundUpBitTest)
    1612             : {
    1613           0 :     return RoundValueDiscardLsbSigned<int64_t>(ptr, nMask, nRoundUpBitTest);
    1614             : }
    1615             : 
    1616             : template <>
    1617           0 : uint16_t RoundValueDiscardLsb<GFloat16, uint16_t>(const void *ptr,
    1618             :                                                   uint64_t nMask,
    1619             :                                                   uint64_t nRoundUpBitTest)
    1620             : {
    1621           0 :     return RoundValueDiscardLsbUnsigned<uint16_t>(ptr, nMask, nRoundUpBitTest);
    1622             : }
    1623             : 
    1624             : template <>
    1625           0 : uint32_t RoundValueDiscardLsb<float, uint32_t>(const void *ptr, uint64_t nMask,
    1626             :                                                uint64_t nRoundUpBitTest)
    1627             : {
    1628           0 :     return RoundValueDiscardLsbUnsigned<uint32_t>(ptr, nMask, nRoundUpBitTest);
    1629             : }
    1630             : 
    1631             : template <>
    1632           0 : uint64_t RoundValueDiscardLsb<double, uint64_t>(const void *ptr, uint64_t nMask,
    1633             :                                                 uint64_t nRoundUpBitTest)
    1634             : {
    1635           0 :     return RoundValueDiscardLsbUnsigned<uint64_t>(ptr, nMask, nRoundUpBitTest);
    1636             : }
    1637             : 
    1638             : template <class Teffective, class T>
    1639         145 : static void DiscardLsbT(GByte *pabyBuffer, size_t nBytes, int iBand, int nBands,
    1640             :                         uint16_t nPlanarConfig,
    1641             :                         const GTiffDataset::MaskOffset *panMaskOffsetLsb,
    1642             :                         bool bHasNoData, Teffective nNoDataValue)
    1643             : {
    1644             :     static_assert(sizeof(Teffective) == sizeof(T),
    1645             :                   "sizeof(Teffective) == sizeof(T)");
    1646         145 :     if (nPlanarConfig == PLANARCONFIG_SEPARATE)
    1647             :     {
    1648          98 :         const auto nMask = panMaskOffsetLsb[iBand].nMask;
    1649          98 :         const auto nRoundUpBitTest = panMaskOffsetLsb[iBand].nRoundUpBitTest;
    1650         196 :         for (size_t i = 0; i < nBytes / sizeof(T); ++i)
    1651             :         {
    1652          98 :             if (MustNotDiscardLsb(reinterpret_cast<Teffective *>(pabyBuffer)[i],
    1653             :                                   bHasNoData, nNoDataValue))
    1654             :             {
    1655          22 :                 continue;
    1656             :             }
    1657             : 
    1658          76 :             if (reinterpret_cast<T *>(pabyBuffer)[i] & nRoundUpBitTest)
    1659             :             {
    1660          30 :                 reinterpret_cast<T *>(pabyBuffer)[i] =
    1661          15 :                     RoundValueDiscardLsb<Teffective, T>(
    1662          15 :                         &(reinterpret_cast<T *>(pabyBuffer)[i]), nMask,
    1663             :                         nRoundUpBitTest);
    1664             :             }
    1665             :             else
    1666             :             {
    1667          61 :                 reinterpret_cast<T *>(pabyBuffer)[i] = static_cast<T>(
    1668          61 :                     reinterpret_cast<T *>(pabyBuffer)[i] & nMask);
    1669             :             }
    1670             : 
    1671             :             // Make sure that by discarding LSB we don't end up to a value
    1672             :             // that is no the nodata value
    1673          76 :             if (MustNotDiscardLsb(reinterpret_cast<Teffective *>(pabyBuffer)[i],
    1674             :                                   bHasNoData, nNoDataValue))
    1675             :             {
    1676           8 :                 reinterpret_cast<Teffective *>(pabyBuffer)[i] =
    1677           4 :                     AdjustValue(nNoDataValue, nRoundUpBitTest);
    1678             :             }
    1679             :         }
    1680             :     }
    1681             :     else
    1682             :     {
    1683          94 :         for (size_t i = 0; i < nBytes / sizeof(T); i += nBands)
    1684             :         {
    1685         147 :             for (int j = 0; j < nBands; ++j)
    1686             :             {
    1687         100 :                 if (MustNotDiscardLsb(
    1688         100 :                         reinterpret_cast<Teffective *>(pabyBuffer)[i + j],
    1689             :                         bHasNoData, nNoDataValue))
    1690             :                 {
    1691          14 :                     continue;
    1692             :                 }
    1693             : 
    1694          86 :                 if (reinterpret_cast<T *>(pabyBuffer)[i + j] &
    1695          86 :                     panMaskOffsetLsb[j].nRoundUpBitTest)
    1696             :                 {
    1697          38 :                     reinterpret_cast<T *>(pabyBuffer)[i + j] =
    1698          19 :                         RoundValueDiscardLsb<Teffective, T>(
    1699          19 :                             &(reinterpret_cast<T *>(pabyBuffer)[i + j]),
    1700          19 :                             panMaskOffsetLsb[j].nMask,
    1701          19 :                             panMaskOffsetLsb[j].nRoundUpBitTest);
    1702             :                 }
    1703             :                 else
    1704             :                 {
    1705          67 :                     reinterpret_cast<T *>(pabyBuffer)[i + j] = static_cast<T>(
    1706          67 :                         (reinterpret_cast<T *>(pabyBuffer)[i + j] &
    1707          67 :                          panMaskOffsetLsb[j].nMask));
    1708             :                 }
    1709             : 
    1710             :                 // Make sure that by discarding LSB we don't end up to a value
    1711             :                 // that is no the nodata value
    1712          86 :                 if (MustNotDiscardLsb(
    1713          86 :                         reinterpret_cast<Teffective *>(pabyBuffer)[i + j],
    1714             :                         bHasNoData, nNoDataValue))
    1715             :                 {
    1716           8 :                     reinterpret_cast<Teffective *>(pabyBuffer)[i + j] =
    1717           4 :                         AdjustValue(nNoDataValue,
    1718           4 :                                     panMaskOffsetLsb[j].nRoundUpBitTest);
    1719             :                 }
    1720             :             }
    1721             :         }
    1722             :     }
    1723         145 : }
    1724             : 
    1725         183 : static void DiscardLsb(GByte *pabyBuffer, GPtrDiff_t nBytes, int iBand,
    1726             :                        int nBands, uint16_t nSampleFormat,
    1727             :                        uint16_t nBitsPerSample, uint16_t nPlanarConfig,
    1728             :                        const GTiffDataset::MaskOffset *panMaskOffsetLsb,
    1729             :                        bool bHasNoData, double dfNoDataValue)
    1730             : {
    1731         183 :     if (nBitsPerSample == 8 && nSampleFormat == SAMPLEFORMAT_UINT)
    1732             :     {
    1733          38 :         uint8_t nNoDataValue = 0;
    1734          38 :         if (bHasNoData && GDALIsValueExactAs<uint8_t>(dfNoDataValue))
    1735             :         {
    1736           6 :             nNoDataValue = static_cast<uint8_t>(dfNoDataValue);
    1737             :         }
    1738             :         else
    1739             :         {
    1740          32 :             bHasNoData = false;
    1741             :         }
    1742          38 :         if (nPlanarConfig == PLANARCONFIG_SEPARATE)
    1743             :         {
    1744          25 :             const auto nMask =
    1745          25 :                 static_cast<unsigned>(panMaskOffsetLsb[iBand].nMask);
    1746          25 :             const auto nRoundUpBitTest =
    1747          25 :                 static_cast<unsigned>(panMaskOffsetLsb[iBand].nRoundUpBitTest);
    1748          50 :             for (decltype(nBytes) i = 0; i < nBytes; ++i)
    1749             :             {
    1750          25 :                 if (bHasNoData && pabyBuffer[i] == nNoDataValue)
    1751           3 :                     continue;
    1752             : 
    1753             :                 // Keep 255 in case it is alpha.
    1754          22 :                 if (pabyBuffer[i] != 255)
    1755             :                 {
    1756          21 :                     if (pabyBuffer[i] & nRoundUpBitTest)
    1757           5 :                         pabyBuffer[i] = static_cast<GByte>(
    1758           5 :                             std::min(255U, (pabyBuffer[i] & nMask) +
    1759           5 :                                                (nRoundUpBitTest << 1U)));
    1760             :                     else
    1761          16 :                         pabyBuffer[i] =
    1762          16 :                             static_cast<GByte>(pabyBuffer[i] & nMask);
    1763             : 
    1764             :                     // Make sure that by discarding LSB we don't end up to a
    1765             :                     // value that is no the nodata value
    1766          21 :                     if (bHasNoData && pabyBuffer[i] == nNoDataValue)
    1767           2 :                         pabyBuffer[i] =
    1768           1 :                             AdjustValue(nNoDataValue, nRoundUpBitTest);
    1769             :                 }
    1770             :             }
    1771             :         }
    1772             :         else
    1773             :         {
    1774          26 :             for (decltype(nBytes) i = 0; i < nBytes; i += nBands)
    1775             :             {
    1776          42 :                 for (int j = 0; j < nBands; ++j)
    1777             :                 {
    1778          29 :                     if (bHasNoData && pabyBuffer[i + j] == nNoDataValue)
    1779           2 :                         continue;
    1780             : 
    1781             :                     // Keep 255 in case it is alpha.
    1782          27 :                     if (pabyBuffer[i + j] != 255)
    1783             :                     {
    1784          25 :                         if (pabyBuffer[i + j] &
    1785          25 :                             panMaskOffsetLsb[j].nRoundUpBitTest)
    1786             :                         {
    1787           6 :                             pabyBuffer[i + j] = static_cast<GByte>(std::min(
    1788          12 :                                 255U,
    1789           6 :                                 (pabyBuffer[i + j] &
    1790             :                                  static_cast<unsigned>(
    1791           6 :                                      panMaskOffsetLsb[j].nMask)) +
    1792             :                                     (static_cast<unsigned>(
    1793           6 :                                          panMaskOffsetLsb[j].nRoundUpBitTest)
    1794           6 :                                      << 1U)));
    1795             :                         }
    1796             :                         else
    1797             :                         {
    1798          19 :                             pabyBuffer[i + j] = static_cast<GByte>(
    1799          19 :                                 pabyBuffer[i + j] & panMaskOffsetLsb[j].nMask);
    1800             :                         }
    1801             : 
    1802             :                         // Make sure that by discarding LSB we don't end up to a
    1803             :                         // value that is no the nodata value
    1804          25 :                         if (bHasNoData && pabyBuffer[i + j] == nNoDataValue)
    1805           1 :                             pabyBuffer[i + j] = AdjustValue(
    1806             :                                 nNoDataValue,
    1807           1 :                                 panMaskOffsetLsb[j].nRoundUpBitTest);
    1808             :                     }
    1809             :                 }
    1810             :             }
    1811          38 :         }
    1812             :     }
    1813         145 :     else if (nBitsPerSample == 8 && nSampleFormat == SAMPLEFORMAT_INT)
    1814             :     {
    1815           0 :         int8_t nNoDataValue = 0;
    1816           0 :         if (bHasNoData && GDALIsValueExactAs<int8_t>(dfNoDataValue))
    1817             :         {
    1818           0 :             nNoDataValue = static_cast<int8_t>(dfNoDataValue);
    1819             :         }
    1820             :         else
    1821             :         {
    1822           0 :             bHasNoData = false;
    1823             :         }
    1824           0 :         DiscardLsbT<int8_t, int8_t>(pabyBuffer, nBytes, iBand, nBands,
    1825             :                                     nPlanarConfig, panMaskOffsetLsb, bHasNoData,
    1826           0 :                                     nNoDataValue);
    1827             :     }
    1828         145 :     else if (nBitsPerSample == 16 && nSampleFormat == SAMPLEFORMAT_INT)
    1829             :     {
    1830          48 :         int16_t nNoDataValue = 0;
    1831          48 :         if (bHasNoData && GDALIsValueExactAs<int16_t>(dfNoDataValue))
    1832             :         {
    1833           6 :             nNoDataValue = static_cast<int16_t>(dfNoDataValue);
    1834             :         }
    1835             :         else
    1836             :         {
    1837          42 :             bHasNoData = false;
    1838             :         }
    1839          48 :         DiscardLsbT<int16_t, int16_t>(pabyBuffer, nBytes, iBand, nBands,
    1840             :                                       nPlanarConfig, panMaskOffsetLsb,
    1841          48 :                                       bHasNoData, nNoDataValue);
    1842             :     }
    1843          97 :     else if (nBitsPerSample == 16 && nSampleFormat == SAMPLEFORMAT_UINT)
    1844             :     {
    1845          33 :         uint16_t nNoDataValue = 0;
    1846          33 :         if (bHasNoData && GDALIsValueExactAs<uint16_t>(dfNoDataValue))
    1847             :         {
    1848           6 :             nNoDataValue = static_cast<uint16_t>(dfNoDataValue);
    1849             :         }
    1850             :         else
    1851             :         {
    1852          27 :             bHasNoData = false;
    1853             :         }
    1854          33 :         DiscardLsbT<uint16_t, uint16_t>(pabyBuffer, nBytes, iBand, nBands,
    1855             :                                         nPlanarConfig, panMaskOffsetLsb,
    1856          33 :                                         bHasNoData, nNoDataValue);
    1857             :     }
    1858          64 :     else if (nBitsPerSample == 32 && nSampleFormat == SAMPLEFORMAT_INT)
    1859             :     {
    1860          13 :         int32_t nNoDataValue = 0;
    1861          13 :         if (bHasNoData && GDALIsValueExactAs<int32_t>(dfNoDataValue))
    1862             :         {
    1863           6 :             nNoDataValue = static_cast<int32_t>(dfNoDataValue);
    1864             :         }
    1865             :         else
    1866             :         {
    1867           7 :             bHasNoData = false;
    1868             :         }
    1869          13 :         DiscardLsbT<int32_t, int32_t>(pabyBuffer, nBytes, iBand, nBands,
    1870             :                                       nPlanarConfig, panMaskOffsetLsb,
    1871          13 :                                       bHasNoData, nNoDataValue);
    1872             :     }
    1873          51 :     else if (nBitsPerSample == 32 && nSampleFormat == SAMPLEFORMAT_UINT)
    1874             :     {
    1875          13 :         uint32_t nNoDataValue = 0;
    1876          13 :         if (bHasNoData && GDALIsValueExactAs<uint32_t>(dfNoDataValue))
    1877             :         {
    1878           6 :             nNoDataValue = static_cast<uint32_t>(dfNoDataValue);
    1879             :         }
    1880             :         else
    1881             :         {
    1882           7 :             bHasNoData = false;
    1883             :         }
    1884          13 :         DiscardLsbT<uint32_t, uint32_t>(pabyBuffer, nBytes, iBand, nBands,
    1885             :                                         nPlanarConfig, panMaskOffsetLsb,
    1886          13 :                                         bHasNoData, nNoDataValue);
    1887             :     }
    1888          38 :     else if (nBitsPerSample == 64 && nSampleFormat == SAMPLEFORMAT_INT)
    1889             :     {
    1890             :         // FIXME: we should not rely on dfNoDataValue when we support native
    1891             :         // data type for nodata
    1892           0 :         int64_t nNoDataValue = 0;
    1893           0 :         if (bHasNoData && GDALIsValueExactAs<int64_t>(dfNoDataValue))
    1894             :         {
    1895           0 :             nNoDataValue = static_cast<int64_t>(dfNoDataValue);
    1896             :         }
    1897             :         else
    1898             :         {
    1899           0 :             bHasNoData = false;
    1900             :         }
    1901           0 :         DiscardLsbT<int64_t, int64_t>(pabyBuffer, nBytes, iBand, nBands,
    1902             :                                       nPlanarConfig, panMaskOffsetLsb,
    1903           0 :                                       bHasNoData, nNoDataValue);
    1904             :     }
    1905          38 :     else if (nBitsPerSample == 64 && nSampleFormat == SAMPLEFORMAT_UINT)
    1906             :     {
    1907             :         // FIXME: we should not rely on dfNoDataValue when we support native
    1908             :         // data type for nodata
    1909           0 :         uint64_t nNoDataValue = 0;
    1910           0 :         if (bHasNoData && GDALIsValueExactAs<uint64_t>(dfNoDataValue))
    1911             :         {
    1912           0 :             nNoDataValue = static_cast<uint64_t>(dfNoDataValue);
    1913             :         }
    1914             :         else
    1915             :         {
    1916           0 :             bHasNoData = false;
    1917             :         }
    1918           0 :         DiscardLsbT<uint64_t, uint64_t>(pabyBuffer, nBytes, iBand, nBands,
    1919             :                                         nPlanarConfig, panMaskOffsetLsb,
    1920           0 :                                         bHasNoData, nNoDataValue);
    1921             :     }
    1922          38 :     else if (nBitsPerSample == 16 && nSampleFormat == SAMPLEFORMAT_IEEEFP)
    1923             :     {
    1924           0 :         const GFloat16 fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
    1925           0 :         DiscardLsbT<GFloat16, uint16_t>(pabyBuffer, nBytes, iBand, nBands,
    1926             :                                         nPlanarConfig, panMaskOffsetLsb,
    1927           0 :                                         bHasNoData, fNoDataValue);
    1928             :     }
    1929          38 :     else if (nBitsPerSample == 32 && nSampleFormat == SAMPLEFORMAT_IEEEFP)
    1930             :     {
    1931          19 :         const float fNoDataValue = static_cast<float>(dfNoDataValue);
    1932          19 :         DiscardLsbT<float, uint32_t>(pabyBuffer, nBytes, iBand, nBands,
    1933             :                                      nPlanarConfig, panMaskOffsetLsb,
    1934          19 :                                      bHasNoData, fNoDataValue);
    1935             :     }
    1936          19 :     else if (nBitsPerSample == 64 && nSampleFormat == SAMPLEFORMAT_IEEEFP)
    1937             :     {
    1938          19 :         DiscardLsbT<double, uint64_t>(pabyBuffer, nBytes, iBand, nBands,
    1939             :                                       nPlanarConfig, panMaskOffsetLsb,
    1940             :                                       bHasNoData, dfNoDataValue);
    1941             :     }
    1942         183 : }
    1943             : 
    1944         183 : void GTiffDataset::DiscardLsb(GByte *pabyBuffer, GPtrDiff_t nBytes,
    1945             :                               int iBand) const
    1946             : {
    1947         183 :     ::DiscardLsb(pabyBuffer, nBytes, iBand, nBands, m_nSampleFormat,
    1948         183 :                  m_nBitsPerSample, m_nPlanarConfig, m_panMaskOffsetLsb,
    1949         183 :                  m_bNoDataSet, m_dfNoDataValue);
    1950         183 : }
    1951             : 
    1952             : /************************************************************************/
    1953             : /*                  WriteEncodedTileOrStrip()                           */
    1954             : /************************************************************************/
    1955             : 
    1956      215320 : CPLErr GTiffDataset::WriteEncodedTileOrStrip(uint32_t tile_or_strip, void *data,
    1957             :                                              int bPreserveDataBuffer)
    1958             : {
    1959      215320 :     CPLErr eErr = CE_None;
    1960             : 
    1961      215320 :     if (TIFFIsTiled(m_hTIFF))
    1962             :     {
    1963       49831 :         if (!(WriteEncodedTile(tile_or_strip, static_cast<GByte *>(data),
    1964             :                                bPreserveDataBuffer)))
    1965             :         {
    1966          14 :             eErr = CE_Failure;
    1967             :         }
    1968             :     }
    1969             :     else
    1970             :     {
    1971      165489 :         if (!(WriteEncodedStrip(tile_or_strip, static_cast<GByte *>(data),
    1972             :                                 bPreserveDataBuffer)))
    1973             :         {
    1974           8 :             eErr = CE_Failure;
    1975             :         }
    1976             :     }
    1977             : 
    1978      215325 :     return eErr;
    1979             : }
    1980             : 
    1981             : /************************************************************************/
    1982             : /*                           FlushBlockBuf()                            */
    1983             : /************************************************************************/
    1984             : 
    1985        9603 : CPLErr GTiffDataset::FlushBlockBuf()
    1986             : 
    1987             : {
    1988        9603 :     if (m_nLoadedBlock < 0 || !m_bLoadedBlockDirty)
    1989           0 :         return CE_None;
    1990             : 
    1991        9603 :     m_bLoadedBlockDirty = false;
    1992             : 
    1993             :     const CPLErr eErr =
    1994        9603 :         WriteEncodedTileOrStrip(m_nLoadedBlock, m_pabyBlockBuf, true);
    1995        9603 :     if (eErr != CE_None)
    1996             :     {
    1997           0 :         ReportError(CE_Failure, CPLE_AppDefined,
    1998             :                     "WriteEncodedTile/Strip() failed.");
    1999           0 :         m_bWriteError = true;
    2000             :     }
    2001             : 
    2002        9603 :     return eErr;
    2003             : }
    2004             : 
    2005             : /************************************************************************/
    2006             : /*                   GTiffFillStreamableOffsetAndCount()                */
    2007             : /************************************************************************/
    2008             : 
    2009           8 : static void GTiffFillStreamableOffsetAndCount(TIFF *hTIFF, int nSize)
    2010             : {
    2011           8 :     uint32_t nXSize = 0;
    2012           8 :     uint32_t nYSize = 0;
    2013           8 :     TIFFGetField(hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize);
    2014           8 :     TIFFGetField(hTIFF, TIFFTAG_IMAGELENGTH, &nYSize);
    2015           8 :     const bool bIsTiled = CPL_TO_BOOL(TIFFIsTiled(hTIFF));
    2016             :     const int nBlockCount =
    2017           8 :         bIsTiled ? TIFFNumberOfTiles(hTIFF) : TIFFNumberOfStrips(hTIFF);
    2018             : 
    2019           8 :     toff_t *panOffset = nullptr;
    2020           8 :     TIFFGetField(hTIFF, bIsTiled ? TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS,
    2021             :                  &panOffset);
    2022           8 :     toff_t *panSize = nullptr;
    2023           8 :     TIFFGetField(hTIFF,
    2024             :                  bIsTiled ? TIFFTAG_TILEBYTECOUNTS : TIFFTAG_STRIPBYTECOUNTS,
    2025             :                  &panSize);
    2026           8 :     toff_t nOffset = nSize;
    2027             :     // Trick to avoid clang static analyzer raising false positive about
    2028             :     // divide by zero later.
    2029           8 :     int nBlocksPerBand = 1;
    2030           8 :     uint32_t nRowsPerStrip = 0;
    2031           8 :     if (!bIsTiled)
    2032             :     {
    2033           6 :         TIFFGetField(hTIFF, TIFFTAG_ROWSPERSTRIP, &nRowsPerStrip);
    2034           6 :         if (nRowsPerStrip > static_cast<uint32_t>(nYSize))
    2035           0 :             nRowsPerStrip = nYSize;
    2036           6 :         nBlocksPerBand = DIV_ROUND_UP(nYSize, nRowsPerStrip);
    2037             :     }
    2038        2947 :     for (int i = 0; i < nBlockCount; ++i)
    2039             :     {
    2040             :         GPtrDiff_t cc = bIsTiled
    2041        2939 :                             ? static_cast<GPtrDiff_t>(TIFFTileSize(hTIFF))
    2042        2907 :                             : static_cast<GPtrDiff_t>(TIFFStripSize(hTIFF));
    2043        2939 :         if (!bIsTiled)
    2044             :         {
    2045             :             /* --------------------------------------------------------------------
    2046             :              */
    2047             :             /*      If this is the last strip in the image, and is partial, then
    2048             :              */
    2049             :             /*      we need to trim the number of scanlines written to the */
    2050             :             /*      amount of valid data we have. (#2748) */
    2051             :             /* --------------------------------------------------------------------
    2052             :              */
    2053        2907 :             int nStripWithinBand = i % nBlocksPerBand;
    2054        2907 :             if (nStripWithinBand * nRowsPerStrip > nYSize - nRowsPerStrip)
    2055             :             {
    2056           1 :                 cc = (cc / nRowsPerStrip) *
    2057           1 :                      (nYSize - nStripWithinBand * nRowsPerStrip);
    2058             :             }
    2059             :         }
    2060        2939 :         panOffset[i] = nOffset;
    2061        2939 :         panSize[i] = cc;
    2062        2939 :         nOffset += cc;
    2063             :     }
    2064           8 : }
    2065             : 
    2066             : /************************************************************************/
    2067             : /*                             Crystalize()                             */
    2068             : /*                                                                      */
    2069             : /*      Make sure that the directory information is written out for     */
    2070             : /*      a new file, require before writing any imagery data.            */
    2071             : /************************************************************************/
    2072             : 
    2073     2639300 : void GTiffDataset::Crystalize()
    2074             : 
    2075             : {
    2076     2639300 :     if (m_bCrystalized)
    2077     2633820 :         return;
    2078             : 
    2079             :     // TODO: libtiff writes extended tags in the order they are specified
    2080             :     // and not in increasing order.
    2081        5479 :     WriteMetadata(this, m_hTIFF, true, m_eProfile, m_pszFilename,
    2082        5479 :                   m_papszCreationOptions);
    2083        5461 :     WriteGeoTIFFInfo();
    2084        5461 :     if (m_bNoDataSet)
    2085         292 :         WriteNoDataValue(m_hTIFF, m_dfNoDataValue);
    2086        5169 :     else if (m_bNoDataSetAsInt64)
    2087           1 :         WriteNoDataValue(m_hTIFF, m_nNoDataValueInt64);
    2088        5168 :     else if (m_bNoDataSetAsUInt64)
    2089           1 :         WriteNoDataValue(m_hTIFF, m_nNoDataValueUInt64);
    2090             : 
    2091        5461 :     m_bMetadataChanged = false;
    2092        5461 :     m_bGeoTIFFInfoChanged = false;
    2093        5461 :     m_bNoDataChanged = false;
    2094        5461 :     m_bNeedsRewrite = false;
    2095             : 
    2096        5461 :     m_bCrystalized = true;
    2097             : 
    2098        5461 :     TIFFWriteCheck(m_hTIFF, TIFFIsTiled(m_hTIFF), "GTiffDataset::Crystalize");
    2099             : 
    2100        5461 :     TIFFWriteDirectory(m_hTIFF);
    2101        5461 :     if (m_bStreamingOut)
    2102             :     {
    2103             :         // We need to write twice the directory to be sure that custom
    2104             :         // TIFF tags are correctly sorted and that padding bytes have been
    2105             :         // added.
    2106           3 :         TIFFSetDirectory(m_hTIFF, 0);
    2107           3 :         TIFFWriteDirectory(m_hTIFF);
    2108             : 
    2109           3 :         if (VSIFSeekL(m_fpL, 0, SEEK_END) != 0)
    2110             :         {
    2111           0 :             ReportError(CE_Failure, CPLE_FileIO, "Could not seek");
    2112             :         }
    2113           3 :         const int nSize = static_cast<int>(VSIFTellL(m_fpL));
    2114             : 
    2115           3 :         TIFFSetDirectory(m_hTIFF, 0);
    2116           3 :         GTiffFillStreamableOffsetAndCount(m_hTIFF, nSize);
    2117           3 :         TIFFWriteDirectory(m_hTIFF);
    2118             : 
    2119           3 :         vsi_l_offset nDataLength = 0;
    2120             :         void *pabyBuffer =
    2121           3 :             VSIGetMemFileBuffer(m_pszTmpFilename, &nDataLength, FALSE);
    2122           3 :         if (static_cast<int>(VSIFWriteL(
    2123           3 :                 pabyBuffer, 1, static_cast<int>(nDataLength), m_fpToWrite)) !=
    2124             :             static_cast<int>(nDataLength))
    2125             :         {
    2126           0 :             ReportError(CE_Failure, CPLE_FileIO, "Could not write %d bytes",
    2127             :                         static_cast<int>(nDataLength));
    2128             :         }
    2129             :         // In case of single strip file, there's a libtiff check that would
    2130             :         // issue a warning since the file hasn't the required size.
    2131           3 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    2132           3 :         TIFFSetDirectory(m_hTIFF, 0);
    2133           3 :         CPLPopErrorHandler();
    2134             :     }
    2135             :     else
    2136             :     {
    2137        5458 :         const tdir_t nNumberOfDirs = TIFFNumberOfDirectories(m_hTIFF);
    2138        5458 :         if (nNumberOfDirs > 0)
    2139             :         {
    2140        5458 :             TIFFSetDirectory(m_hTIFF, static_cast<tdir_t>(nNumberOfDirs - 1));
    2141             :         }
    2142             :     }
    2143             : 
    2144        5461 :     RestoreVolatileParameters(m_hTIFF);
    2145             : 
    2146        5461 :     m_nDirOffset = TIFFCurrentDirOffset(m_hTIFF);
    2147             : }
    2148             : 
    2149             : /************************************************************************/
    2150             : /*                             FlushCache()                             */
    2151             : /*                                                                      */
    2152             : /*      We override this so we can also flush out local tiff strip      */
    2153             : /*      cache if need be.                                               */
    2154             : /************************************************************************/
    2155             : 
    2156        4368 : CPLErr GTiffDataset::FlushCache(bool bAtClosing)
    2157             : 
    2158             : {
    2159        4368 :     return FlushCacheInternal(bAtClosing, true);
    2160             : }
    2161             : 
    2162       44704 : CPLErr GTiffDataset::FlushCacheInternal(bool bAtClosing, bool bFlushDirectory)
    2163             : {
    2164       44704 :     if (m_bIsFinalized)
    2165           1 :         return CE_None;
    2166             : 
    2167       44703 :     CPLErr eErr = GDALPamDataset::FlushCache(bAtClosing);
    2168             : 
    2169       44702 :     if (m_bLoadedBlockDirty && m_nLoadedBlock != -1)
    2170             :     {
    2171         258 :         if (FlushBlockBuf() != CE_None)
    2172           0 :             eErr = CE_Failure;
    2173             :     }
    2174             : 
    2175       44702 :     CPLFree(m_pabyBlockBuf);
    2176       44703 :     m_pabyBlockBuf = nullptr;
    2177       44703 :     m_nLoadedBlock = -1;
    2178       44703 :     m_bLoadedBlockDirty = false;
    2179             : 
    2180             :     // Finish compression
    2181       44703 :     auto poQueue = m_poBaseDS ? m_poBaseDS->m_poCompressQueue.get()
    2182       42374 :                               : m_poCompressQueue.get();
    2183       44701 :     if (poQueue)
    2184             :     {
    2185         161 :         poQueue->WaitCompletion();
    2186             : 
    2187             :         // Flush remaining data
    2188             :         // cppcheck-suppress constVariableReference
    2189             : 
    2190         161 :         auto &oQueue =
    2191         161 :             m_poBaseDS ? m_poBaseDS->m_asQueueJobIdx : m_asQueueJobIdx;
    2192         230 :         while (!oQueue.empty())
    2193             :         {
    2194          69 :             WaitCompletionForJobIdx(oQueue.front());
    2195             :         }
    2196             :     }
    2197             : 
    2198       44701 :     if (bFlushDirectory && GetAccess() == GA_Update)
    2199             :     {
    2200       13300 :         if (FlushDirectory() != CE_None)
    2201          12 :             eErr = CE_Failure;
    2202             :     }
    2203       44702 :     return eErr;
    2204             : }
    2205             : 
    2206             : /************************************************************************/
    2207             : /*                           FlushDirectory()                           */
    2208             : /************************************************************************/
    2209             : 
    2210       20489 : CPLErr GTiffDataset::FlushDirectory()
    2211             : 
    2212             : {
    2213       20489 :     CPLErr eErr = CE_None;
    2214             : 
    2215         551 :     const auto ReloadAllOtherDirectories = [this]()
    2216             :     {
    2217         271 :         const auto poBaseDS = m_poBaseDS ? m_poBaseDS : this;
    2218         271 :         if (poBaseDS->m_papoOverviewDS)
    2219             :         {
    2220          12 :             for (int i = 0; i < poBaseDS->m_nOverviewCount; ++i)
    2221             :             {
    2222           3 :                 if (poBaseDS->m_papoOverviewDS[i]->m_bCrystalized &&
    2223           3 :                     poBaseDS->m_papoOverviewDS[i] != this)
    2224             :                 {
    2225           3 :                     poBaseDS->m_papoOverviewDS[i]->ReloadDirectory(true);
    2226             :                 }
    2227             : 
    2228           3 :                 if (poBaseDS->m_papoOverviewDS[i]->m_poMaskDS &&
    2229           0 :                     poBaseDS->m_papoOverviewDS[i]->m_poMaskDS != this &&
    2230           0 :                     poBaseDS->m_papoOverviewDS[i]->m_poMaskDS->m_bCrystalized)
    2231             :                 {
    2232           0 :                     poBaseDS->m_papoOverviewDS[i]->m_poMaskDS->ReloadDirectory(
    2233             :                         true);
    2234             :                 }
    2235             :             }
    2236             :         }
    2237         271 :         if (poBaseDS->m_poMaskDS && poBaseDS->m_poMaskDS != this &&
    2238           0 :             poBaseDS->m_poMaskDS->m_bCrystalized)
    2239             :         {
    2240           0 :             poBaseDS->m_poMaskDS->ReloadDirectory(true);
    2241             :         }
    2242         271 :         if (poBaseDS->m_bCrystalized && poBaseDS != this)
    2243             :         {
    2244           6 :             poBaseDS->ReloadDirectory(true);
    2245             :         }
    2246       20760 :     };
    2247             : 
    2248       20489 :     if (eAccess == GA_Update)
    2249             :     {
    2250       14871 :         if (m_bMetadataChanged)
    2251             :         {
    2252         138 :             m_bNeedsRewrite =
    2253         276 :                 WriteMetadata(this, m_hTIFF, true, m_eProfile, m_pszFilename,
    2254         138 :                               m_papszCreationOptions);
    2255         138 :             m_bMetadataChanged = false;
    2256             : 
    2257         138 :             if (m_bForceUnsetRPC)
    2258             :             {
    2259           5 :                 double *padfRPCTag = nullptr;
    2260             :                 uint16_t nCount;
    2261           5 :                 if (TIFFGetField(m_hTIFF, TIFFTAG_RPCCOEFFICIENT, &nCount,
    2262           5 :                                  &padfRPCTag))
    2263             :                 {
    2264           3 :                     std::vector<double> zeroes(92);
    2265           3 :                     TIFFSetField(m_hTIFF, TIFFTAG_RPCCOEFFICIENT, 92,
    2266             :                                  zeroes.data());
    2267           3 :                     TIFFUnsetField(m_hTIFF, TIFFTAG_RPCCOEFFICIENT);
    2268           3 :                     m_bNeedsRewrite = true;
    2269             :                 }
    2270             : 
    2271           5 :                 GDALWriteRPCTXTFile(m_pszFilename, nullptr);
    2272           5 :                 GDALWriteRPBFile(m_pszFilename, nullptr);
    2273             :             }
    2274             :         }
    2275             : 
    2276       14871 :         if (m_bGeoTIFFInfoChanged)
    2277             :         {
    2278         141 :             WriteGeoTIFFInfo();
    2279         141 :             m_bGeoTIFFInfoChanged = false;
    2280             :         }
    2281             : 
    2282       14871 :         if (m_bNoDataChanged)
    2283             :         {
    2284          46 :             if (m_bNoDataSet)
    2285             :             {
    2286          32 :                 WriteNoDataValue(m_hTIFF, m_dfNoDataValue);
    2287             :             }
    2288          14 :             else if (m_bNoDataSetAsInt64)
    2289             :             {
    2290           0 :                 WriteNoDataValue(m_hTIFF, m_nNoDataValueInt64);
    2291             :             }
    2292          14 :             else if (m_bNoDataSetAsUInt64)
    2293             :             {
    2294           0 :                 WriteNoDataValue(m_hTIFF, m_nNoDataValueUInt64);
    2295             :             }
    2296             :             else
    2297             :             {
    2298          14 :                 UnsetNoDataValue(m_hTIFF);
    2299             :             }
    2300          46 :             m_bNeedsRewrite = true;
    2301          46 :             m_bNoDataChanged = false;
    2302             :         }
    2303             : 
    2304       14871 :         if (m_bNeedsRewrite)
    2305             :         {
    2306         296 :             if (!m_bCrystalized)
    2307             :             {
    2308          28 :                 Crystalize();
    2309             :             }
    2310             :             else
    2311             :             {
    2312         268 :                 const TIFFSizeProc pfnSizeProc = TIFFGetSizeProc(m_hTIFF);
    2313             : 
    2314         268 :                 m_nDirOffset = pfnSizeProc(TIFFClientdata(m_hTIFF));
    2315         268 :                 if ((m_nDirOffset % 2) == 1)
    2316          63 :                     ++m_nDirOffset;
    2317             : 
    2318         268 :                 if (TIFFRewriteDirectory(m_hTIFF) == 0)
    2319           0 :                     eErr = CE_Failure;
    2320             : 
    2321         268 :                 TIFFSetSubDirectory(m_hTIFF, m_nDirOffset);
    2322             : 
    2323         268 :                 ReloadAllOtherDirectories();
    2324             : 
    2325         268 :                 if (m_bLayoutIFDSBeforeData && m_bBlockOrderRowMajor &&
    2326           1 :                     m_bLeaderSizeAsUInt4 &&
    2327           1 :                     m_bTrailerRepeatedLast4BytesRepeated &&
    2328           1 :                     !m_bKnownIncompatibleEdition &&
    2329           1 :                     !m_bWriteKnownIncompatibleEdition)
    2330             :                 {
    2331           1 :                     ReportError(CE_Warning, CPLE_AppDefined,
    2332             :                                 "The IFD has been rewritten at the end of "
    2333             :                                 "the file, which breaks COG layout.");
    2334           1 :                     m_bKnownIncompatibleEdition = true;
    2335           1 :                     m_bWriteKnownIncompatibleEdition = true;
    2336             :                 }
    2337             :             }
    2338             : 
    2339         296 :             m_bNeedsRewrite = false;
    2340             :         }
    2341             :     }
    2342             : 
    2343             :     // There are some circumstances in which we can reach this point
    2344             :     // without having made this our directory (SetDirectory()) in which
    2345             :     // case we should not risk a flush.
    2346       35360 :     if (GetAccess() == GA_Update &&
    2347       14871 :         TIFFCurrentDirOffset(m_hTIFF) == m_nDirOffset)
    2348             :     {
    2349       14871 :         const TIFFSizeProc pfnSizeProc = TIFFGetSizeProc(m_hTIFF);
    2350             : 
    2351       14871 :         toff_t nNewDirOffset = pfnSizeProc(TIFFClientdata(m_hTIFF));
    2352       14871 :         if ((nNewDirOffset % 2) == 1)
    2353        3234 :             ++nNewDirOffset;
    2354             : 
    2355       14871 :         if (TIFFFlush(m_hTIFF) == 0)
    2356          12 :             eErr = CE_Failure;
    2357             : 
    2358       14871 :         if (m_nDirOffset != TIFFCurrentDirOffset(m_hTIFF))
    2359             :         {
    2360           3 :             m_nDirOffset = nNewDirOffset;
    2361           3 :             ReloadAllOtherDirectories();
    2362           3 :             CPLDebug("GTiff",
    2363             :                      "directory moved during flush in FlushDirectory()");
    2364             :         }
    2365             :     }
    2366             : 
    2367       20489 :     SetDirectory();
    2368       20489 :     return eErr;
    2369             : }
    2370             : 
    2371             : /************************************************************************/
    2372             : /*                           CleanOverviews()                           */
    2373             : /************************************************************************/
    2374             : 
    2375           5 : CPLErr GTiffDataset::CleanOverviews()
    2376             : 
    2377             : {
    2378           5 :     CPLAssert(!m_poBaseDS);
    2379             : 
    2380           5 :     ScanDirectories();
    2381             : 
    2382           5 :     FlushDirectory();
    2383             : 
    2384             :     /* -------------------------------------------------------------------- */
    2385             :     /*      Cleanup overviews objects, and get offsets to all overview      */
    2386             :     /*      directories.                                                    */
    2387             :     /* -------------------------------------------------------------------- */
    2388          10 :     std::vector<toff_t> anOvDirOffsets;
    2389             : 
    2390          10 :     for (int i = 0; i < m_nOverviewCount; ++i)
    2391             :     {
    2392           5 :         anOvDirOffsets.push_back(m_papoOverviewDS[i]->m_nDirOffset);
    2393           5 :         if (m_papoOverviewDS[i]->m_poMaskDS)
    2394           1 :             anOvDirOffsets.push_back(
    2395           1 :                 m_papoOverviewDS[i]->m_poMaskDS->m_nDirOffset);
    2396           5 :         delete m_papoOverviewDS[i];
    2397             :     }
    2398             : 
    2399             :     /* -------------------------------------------------------------------- */
    2400             :     /*      Loop through all the directories, translating the offsets       */
    2401             :     /*      into indexes we can use with TIFFUnlinkDirectory().             */
    2402             :     /* -------------------------------------------------------------------- */
    2403          10 :     std::vector<uint16_t> anOvDirIndexes;
    2404           5 :     int iThisOffset = 1;
    2405             : 
    2406           5 :     TIFFSetDirectory(m_hTIFF, 0);
    2407             : 
    2408             :     while (true)
    2409             :     {
    2410          28 :         for (toff_t nOffset : anOvDirOffsets)
    2411             :         {
    2412          16 :             if (nOffset == TIFFCurrentDirOffset(m_hTIFF))
    2413             :             {
    2414           6 :                 anOvDirIndexes.push_back(static_cast<uint16_t>(iThisOffset));
    2415             :             }
    2416             :         }
    2417             : 
    2418          12 :         if (TIFFLastDirectory(m_hTIFF))
    2419           5 :             break;
    2420             : 
    2421           7 :         TIFFReadDirectory(m_hTIFF);
    2422           7 :         ++iThisOffset;
    2423           7 :     }
    2424             : 
    2425             :     /* -------------------------------------------------------------------- */
    2426             :     /*      Actually unlink the target directories.  Note that we do        */
    2427             :     /*      this from last to first so as to avoid renumbering any of       */
    2428             :     /*      the earlier directories we need to remove.                      */
    2429             :     /* -------------------------------------------------------------------- */
    2430          11 :     while (!anOvDirIndexes.empty())
    2431             :     {
    2432           6 :         TIFFUnlinkDirectory(m_hTIFF, anOvDirIndexes.back());
    2433           6 :         anOvDirIndexes.pop_back();
    2434             :     }
    2435             : 
    2436           5 :     CPLFree(m_papoOverviewDS);
    2437           5 :     m_nOverviewCount = 0;
    2438           5 :     m_papoOverviewDS = nullptr;
    2439             : 
    2440           5 :     if (m_poMaskDS)
    2441             :     {
    2442           1 :         CPLFree(m_poMaskDS->m_papoOverviewDS);
    2443           1 :         m_poMaskDS->m_nOverviewCount = 0;
    2444           1 :         m_poMaskDS->m_papoOverviewDS = nullptr;
    2445             :     }
    2446             : 
    2447           5 :     if (!SetDirectory())
    2448           0 :         return CE_Failure;
    2449             : 
    2450           5 :     return CE_None;
    2451             : }
    2452             : 
    2453             : /************************************************************************/
    2454             : /*                   RegisterNewOverviewDataset()                       */
    2455             : /************************************************************************/
    2456             : 
    2457         504 : CPLErr GTiffDataset::RegisterNewOverviewDataset(toff_t nOverviewOffset,
    2458             :                                                 int l_nJpegQuality,
    2459             :                                                 CSLConstList papszOptions)
    2460             : {
    2461         504 :     if (m_nOverviewCount == 127)
    2462           0 :         return CE_Failure;
    2463             : 
    2464             :     const auto GetOptionValue =
    2465        3024 :         [papszOptions](const char *pszOptionKey, const char *pszConfigOptionKey,
    2466        6047 :                        const char **ppszKeyUsed = nullptr)
    2467             :     {
    2468        3024 :         const char *pszVal = CSLFetchNameValue(papszOptions, pszOptionKey);
    2469        3024 :         if (pszVal)
    2470             :         {
    2471           1 :             if (ppszKeyUsed)
    2472           1 :                 *ppszKeyUsed = pszOptionKey;
    2473           1 :             return pszVal;
    2474             :         }
    2475        3023 :         pszVal = CSLFetchNameValue(papszOptions, pszConfigOptionKey);
    2476        3023 :         if (pszVal)
    2477             :         {
    2478           0 :             if (ppszKeyUsed)
    2479           0 :                 *ppszKeyUsed = pszConfigOptionKey;
    2480           0 :             return pszVal;
    2481             :         }
    2482        3023 :         pszVal = CPLGetConfigOption(pszConfigOptionKey, nullptr);
    2483        3023 :         if (pszVal && ppszKeyUsed)
    2484          13 :             *ppszKeyUsed = pszConfigOptionKey;
    2485        3023 :         return pszVal;
    2486         504 :     };
    2487             : 
    2488         504 :     int nZLevel = m_nZLevel;
    2489         504 :     if (const char *opt = GetOptionValue("ZLEVEL", "ZLEVEL_OVERVIEW"))
    2490             :     {
    2491           4 :         nZLevel = atoi(opt);
    2492             :     }
    2493             : 
    2494         504 :     int nZSTDLevel = m_nZSTDLevel;
    2495         504 :     if (const char *opt = GetOptionValue("ZSTD_LEVEL", "ZSTD_LEVEL_OVERVIEW"))
    2496             :     {
    2497           4 :         nZSTDLevel = atoi(opt);
    2498             :     }
    2499             : 
    2500         504 :     bool bWebpLossless = m_bWebPLossless;
    2501             :     const char *pszWebPLosslessOverview =
    2502         504 :         GetOptionValue("WEBP_LOSSLESS", "WEBP_LOSSLESS_OVERVIEW");
    2503         504 :     if (pszWebPLosslessOverview)
    2504             :     {
    2505           2 :         bWebpLossless = CPLTestBool(pszWebPLosslessOverview);
    2506             :     }
    2507             : 
    2508         504 :     int nWebpLevel = m_nWebPLevel;
    2509         504 :     const char *pszKeyWebpLevel = "";
    2510         504 :     if (const char *opt = GetOptionValue("WEBP_LEVEL", "WEBP_LEVEL_OVERVIEW",
    2511             :                                          &pszKeyWebpLevel))
    2512             :     {
    2513          14 :         if (pszWebPLosslessOverview == nullptr && m_bWebPLossless)
    2514             :         {
    2515           1 :             CPLDebug("GTiff",
    2516             :                      "%s specified, but not WEBP_LOSSLESS_OVERVIEW. "
    2517             :                      "Assuming WEBP_LOSSLESS_OVERVIEW=NO",
    2518             :                      pszKeyWebpLevel);
    2519           1 :             bWebpLossless = false;
    2520             :         }
    2521          13 :         else if (bWebpLossless)
    2522             :         {
    2523           0 :             CPLError(CE_Warning, CPLE_AppDefined,
    2524             :                      "%s is specified, but WEBP_LOSSLESS_OVERVIEW=YES. "
    2525             :                      "%s will be ignored.",
    2526             :                      pszKeyWebpLevel, pszKeyWebpLevel);
    2527             :         }
    2528          14 :         nWebpLevel = atoi(opt);
    2529             :     }
    2530             : 
    2531         504 :     double dfMaxZError = m_dfMaxZErrorOverview;
    2532         504 :     if (const char *opt = GetOptionValue("MAX_Z_ERROR", "MAX_Z_ERROR_OVERVIEW"))
    2533             :     {
    2534          20 :         dfMaxZError = CPLAtof(opt);
    2535             :     }
    2536             : 
    2537         504 :     GTiffDataset *poODS = new GTiffDataset();
    2538         504 :     poODS->ShareLockWithParentDataset(this);
    2539         504 :     poODS->m_pszFilename = CPLStrdup(m_pszFilename);
    2540         504 :     const char *pszSparseOK = GetOptionValue("SPARSE_OK", "SPARSE_OK_OVERVIEW");
    2541         504 :     if (pszSparseOK && CPLTestBool(pszSparseOK))
    2542             :     {
    2543           1 :         poODS->m_bWriteEmptyTiles = false;
    2544           1 :         poODS->m_bFillEmptyTilesAtClosing = false;
    2545             :     }
    2546             :     else
    2547             :     {
    2548         503 :         poODS->m_bWriteEmptyTiles = m_bWriteEmptyTiles;
    2549         503 :         poODS->m_bFillEmptyTilesAtClosing = m_bFillEmptyTilesAtClosing;
    2550             :     }
    2551         504 :     poODS->m_nJpegQuality = static_cast<signed char>(l_nJpegQuality);
    2552         504 :     poODS->m_nWebPLevel = static_cast<signed char>(nWebpLevel);
    2553         504 :     poODS->m_nZLevel = static_cast<signed char>(nZLevel);
    2554         504 :     poODS->m_nLZMAPreset = m_nLZMAPreset;
    2555         504 :     poODS->m_nZSTDLevel = static_cast<signed char>(nZSTDLevel);
    2556         504 :     poODS->m_bWebPLossless = bWebpLossless;
    2557         504 :     poODS->m_nJpegTablesMode = m_nJpegTablesMode;
    2558         504 :     poODS->m_dfMaxZError = dfMaxZError;
    2559         504 :     poODS->m_dfMaxZErrorOverview = dfMaxZError;
    2560         504 :     memcpy(poODS->m_anLercAddCompressionAndVersion,
    2561         504 :            m_anLercAddCompressionAndVersion,
    2562             :            sizeof(m_anLercAddCompressionAndVersion));
    2563             : #ifdef HAVE_JXL
    2564         504 :     poODS->m_bJXLLossless = m_bJXLLossless;
    2565         504 :     poODS->m_fJXLDistance = m_fJXLDistance;
    2566         504 :     poODS->m_fJXLAlphaDistance = m_fJXLAlphaDistance;
    2567         504 :     poODS->m_nJXLEffort = m_nJXLEffort;
    2568             : #endif
    2569             : 
    2570         504 :     if (poODS->OpenOffset(VSI_TIFFOpenChild(m_hTIFF), nOverviewOffset,
    2571         504 :                           GA_Update) != CE_None)
    2572             :     {
    2573           0 :         delete poODS;
    2574           0 :         return CE_Failure;
    2575             :     }
    2576             : 
    2577             :     // Assign color interpretation from main dataset
    2578         504 :     const int l_nBands = GetRasterCount();
    2579        1516 :     for (int i = 1; i <= l_nBands; i++)
    2580             :     {
    2581        1012 :         auto poBand = dynamic_cast<GTiffRasterBand *>(poODS->GetRasterBand(i));
    2582        1012 :         if (poBand)
    2583        1012 :             poBand->m_eBandInterp = GetRasterBand(i)->GetColorInterpretation();
    2584             :     }
    2585             : 
    2586             :     // Do that now that m_nCompression is set
    2587         504 :     poODS->RestoreVolatileParameters(poODS->m_hTIFF);
    2588             : 
    2589         504 :     ++m_nOverviewCount;
    2590         504 :     m_papoOverviewDS = static_cast<GTiffDataset **>(
    2591         504 :         CPLRealloc(m_papoOverviewDS, m_nOverviewCount * (sizeof(void *))));
    2592         504 :     m_papoOverviewDS[m_nOverviewCount - 1] = poODS;
    2593         504 :     poODS->m_poBaseDS = this;
    2594         504 :     poODS->m_bIsOverview = true;
    2595         504 :     return CE_None;
    2596             : }
    2597             : 
    2598             : /************************************************************************/
    2599             : /*                     CreateTIFFColorTable()                           */
    2600             : /************************************************************************/
    2601             : 
    2602          12 : static void CreateTIFFColorTable(
    2603             :     GDALColorTable *poColorTable, int nBits, int nColorTableMultiplier,
    2604             :     std::vector<unsigned short> &anTRed, std::vector<unsigned short> &anTGreen,
    2605             :     std::vector<unsigned short> &anTBlue, unsigned short *&panRed,
    2606             :     unsigned short *&panGreen, unsigned short *&panBlue)
    2607             : {
    2608             :     int nColors;
    2609             : 
    2610          12 :     if (nBits == 8)
    2611          12 :         nColors = 256;
    2612           0 :     else if (nBits < 8)
    2613           0 :         nColors = 1 << nBits;
    2614             :     else
    2615           0 :         nColors = 65536;
    2616             : 
    2617          12 :     anTRed.resize(nColors, 0);
    2618          12 :     anTGreen.resize(nColors, 0);
    2619          12 :     anTBlue.resize(nColors, 0);
    2620             : 
    2621        3084 :     for (int iColor = 0; iColor < nColors; ++iColor)
    2622             :     {
    2623        3072 :         if (iColor < poColorTable->GetColorEntryCount())
    2624             :         {
    2625             :             GDALColorEntry sRGB;
    2626             : 
    2627        3072 :             poColorTable->GetColorEntryAsRGB(iColor, &sRGB);
    2628             : 
    2629        3072 :             anTRed[iColor] = GTiffDataset::ClampCTEntry(iColor, 1, sRGB.c1,
    2630             :                                                         nColorTableMultiplier);
    2631        3072 :             anTGreen[iColor] = GTiffDataset::ClampCTEntry(
    2632        3072 :                 iColor, 2, sRGB.c2, nColorTableMultiplier);
    2633        3072 :             anTBlue[iColor] = GTiffDataset::ClampCTEntry(iColor, 3, sRGB.c3,
    2634             :                                                          nColorTableMultiplier);
    2635             :         }
    2636             :         else
    2637             :         {
    2638           0 :             anTRed[iColor] = 0;
    2639           0 :             anTGreen[iColor] = 0;
    2640           0 :             anTBlue[iColor] = 0;
    2641             :         }
    2642             :     }
    2643             : 
    2644          12 :     panRed = &(anTRed[0]);
    2645          12 :     panGreen = &(anTGreen[0]);
    2646          12 :     panBlue = &(anTBlue[0]);
    2647          12 : }
    2648             : 
    2649             : /************************************************************************/
    2650             : /*                        GetOverviewParameters()                       */
    2651             : /************************************************************************/
    2652             : 
    2653         319 : bool GTiffDataset::GetOverviewParameters(
    2654             :     int &nCompression, uint16_t &nPlanarConfig, uint16_t &nPredictor,
    2655             :     uint16_t &nPhotometric, int &nOvrJpegQuality, std::string &osNoData,
    2656             :     uint16_t *&panExtraSampleValues, uint16_t &nExtraSamples,
    2657             :     CSLConstList papszOptions) const
    2658             : {
    2659             :     const auto GetOptionValue =
    2660        1057 :         [papszOptions](const char *pszOptionKey, const char *pszConfigOptionKey,
    2661        2110 :                        const char **ppszKeyUsed = nullptr)
    2662             :     {
    2663        1057 :         const char *pszVal = CSLFetchNameValue(papszOptions, pszOptionKey);
    2664        1057 :         if (pszVal)
    2665             :         {
    2666           4 :             if (ppszKeyUsed)
    2667           4 :                 *ppszKeyUsed = pszOptionKey;
    2668           4 :             return pszVal;
    2669             :         }
    2670        1053 :         pszVal = CSLFetchNameValue(papszOptions, pszConfigOptionKey);
    2671        1053 :         if (pszVal)
    2672             :         {
    2673           4 :             if (ppszKeyUsed)
    2674           4 :                 *ppszKeyUsed = pszConfigOptionKey;
    2675           4 :             return pszVal;
    2676             :         }
    2677        1049 :         pszVal = CPLGetConfigOption(pszConfigOptionKey, nullptr);
    2678        1049 :         if (pszVal && ppszKeyUsed)
    2679          56 :             *ppszKeyUsed = pszConfigOptionKey;
    2680        1049 :         return pszVal;
    2681         319 :     };
    2682             : 
    2683             :     /* -------------------------------------------------------------------- */
    2684             :     /*      Determine compression method.                                   */
    2685             :     /* -------------------------------------------------------------------- */
    2686         319 :     nCompression = m_nCompression;
    2687         319 :     const char *pszOptionKey = "";
    2688             :     const char *pszCompressValue =
    2689         319 :         GetOptionValue("COMPRESS", "COMPRESS_OVERVIEW", &pszOptionKey);
    2690         319 :     if (pszCompressValue != nullptr)
    2691             :     {
    2692          54 :         nCompression =
    2693          54 :             GTIFFGetCompressionMethod(pszCompressValue, pszOptionKey);
    2694          54 :         if (nCompression < 0)
    2695             :         {
    2696           0 :             nCompression = m_nCompression;
    2697             :         }
    2698             :     }
    2699             : 
    2700             :     /* -------------------------------------------------------------------- */
    2701             :     /*      Determine planar configuration.                                 */
    2702             :     /* -------------------------------------------------------------------- */
    2703         319 :     nPlanarConfig = m_nPlanarConfig;
    2704         319 :     if (nCompression == COMPRESSION_WEBP)
    2705             :     {
    2706          11 :         nPlanarConfig = PLANARCONFIG_CONTIG;
    2707             :     }
    2708             :     const char *pszInterleave =
    2709         319 :         GetOptionValue("INTERLEAVE", "INTERLEAVE_OVERVIEW", &pszOptionKey);
    2710         319 :     if (pszInterleave != nullptr && pszInterleave[0] != '\0')
    2711             :     {
    2712           2 :         if (EQUAL(pszInterleave, "PIXEL"))
    2713           1 :             nPlanarConfig = PLANARCONFIG_CONTIG;
    2714           1 :         else if (EQUAL(pszInterleave, "BAND"))
    2715           1 :             nPlanarConfig = PLANARCONFIG_SEPARATE;
    2716             :         else
    2717             :         {
    2718           0 :             CPLError(CE_Warning, CPLE_AppDefined,
    2719             :                      "%s=%s unsupported, "
    2720             :                      "value must be PIXEL or BAND. ignoring",
    2721             :                      pszOptionKey, pszInterleave);
    2722             :         }
    2723             :     }
    2724             : 
    2725             :     /* -------------------------------------------------------------------- */
    2726             :     /*      Determine predictor tag                                         */
    2727             :     /* -------------------------------------------------------------------- */
    2728         319 :     nPredictor = PREDICTOR_NONE;
    2729         319 :     if (GTIFFSupportsPredictor(nCompression))
    2730             :     {
    2731             :         const char *pszPredictor =
    2732          73 :             GetOptionValue("PREDICTOR", "PREDICTOR_OVERVIEW");
    2733          73 :         if (pszPredictor != nullptr)
    2734             :         {
    2735           1 :             nPredictor = static_cast<uint16_t>(atoi(pszPredictor));
    2736             :         }
    2737          72 :         else if (GTIFFSupportsPredictor(m_nCompression))
    2738          71 :             TIFFGetField(m_hTIFF, TIFFTAG_PREDICTOR, &nPredictor);
    2739             :     }
    2740             : 
    2741             :     /* -------------------------------------------------------------------- */
    2742             :     /*      Determine photometric tag                                       */
    2743             :     /* -------------------------------------------------------------------- */
    2744         319 :     if (m_nPhotometric == PHOTOMETRIC_YCBCR && nCompression != COMPRESSION_JPEG)
    2745           1 :         nPhotometric = PHOTOMETRIC_RGB;
    2746             :     else
    2747         318 :         nPhotometric = m_nPhotometric;
    2748             :     const char *pszPhotometric =
    2749         319 :         GetOptionValue("PHOTOMETRIC", "PHOTOMETRIC_OVERVIEW", &pszOptionKey);
    2750         319 :     if (!GTIFFUpdatePhotometric(pszPhotometric, pszOptionKey, nCompression,
    2751         319 :                                 pszInterleave, nBands, nPhotometric,
    2752             :                                 nPlanarConfig))
    2753             :     {
    2754           0 :         return false;
    2755             :     }
    2756             : 
    2757             :     /* -------------------------------------------------------------------- */
    2758             :     /*      Determine JPEG quality                                          */
    2759             :     /* -------------------------------------------------------------------- */
    2760         319 :     nOvrJpegQuality = m_nJpegQuality;
    2761         319 :     if (nCompression == COMPRESSION_JPEG)
    2762             :     {
    2763             :         const char *pszJPEGQuality =
    2764          27 :             GetOptionValue("JPEG_QUALITY", "JPEG_QUALITY_OVERVIEW");
    2765          27 :         if (pszJPEGQuality != nullptr)
    2766             :         {
    2767           9 :             nOvrJpegQuality = atoi(pszJPEGQuality);
    2768             :         }
    2769             :     }
    2770             : 
    2771             :     /* -------------------------------------------------------------------- */
    2772             :     /*      Set nodata.                                                     */
    2773             :     /* -------------------------------------------------------------------- */
    2774         319 :     if (m_bNoDataSet)
    2775             :     {
    2776          17 :         osNoData = GTiffFormatGDALNoDataTagValue(m_dfNoDataValue);
    2777             :     }
    2778             : 
    2779             :     /* -------------------------------------------------------------------- */
    2780             :     /*      Fetch extra sample tag                                          */
    2781             :     /* -------------------------------------------------------------------- */
    2782         319 :     panExtraSampleValues = nullptr;
    2783         319 :     nExtraSamples = 0;
    2784         319 :     if (TIFFGetField(m_hTIFF, TIFFTAG_EXTRASAMPLES, &nExtraSamples,
    2785         319 :                      &panExtraSampleValues))
    2786             :     {
    2787             :         uint16_t *panExtraSampleValuesNew = static_cast<uint16_t *>(
    2788          40 :             CPLMalloc(nExtraSamples * sizeof(uint16_t)));
    2789          40 :         memcpy(panExtraSampleValuesNew, panExtraSampleValues,
    2790          40 :                nExtraSamples * sizeof(uint16_t));
    2791          40 :         panExtraSampleValues = panExtraSampleValuesNew;
    2792             :     }
    2793             :     else
    2794             :     {
    2795         279 :         panExtraSampleValues = nullptr;
    2796         279 :         nExtraSamples = 0;
    2797             :     }
    2798             : 
    2799         319 :     return true;
    2800             : }
    2801             : 
    2802             : /************************************************************************/
    2803             : /*                  CreateOverviewsFromSrcOverviews()                   */
    2804             : /************************************************************************/
    2805             : 
    2806             : // If poOvrDS is not null, it is used and poSrcDS is ignored.
    2807             : 
    2808          66 : CPLErr GTiffDataset::CreateOverviewsFromSrcOverviews(GDALDataset *poSrcDS,
    2809             :                                                      GDALDataset *poOvrDS,
    2810             :                                                      int nOverviews)
    2811             : {
    2812          66 :     CPLAssert(poSrcDS->GetRasterCount() != 0);
    2813          66 :     CPLAssert(m_nOverviewCount == 0);
    2814             : 
    2815          66 :     ScanDirectories();
    2816             : 
    2817          66 :     FlushDirectory();
    2818             : 
    2819          66 :     int nOvBitsPerSample = m_nBitsPerSample;
    2820             : 
    2821             :     /* -------------------------------------------------------------------- */
    2822             :     /*      Do we need some metadata for the overviews?                     */
    2823             :     /* -------------------------------------------------------------------- */
    2824         132 :     CPLString osMetadata;
    2825             : 
    2826          66 :     GTIFFBuildOverviewMetadata("NONE", this, false, osMetadata);
    2827             : 
    2828             :     int nCompression;
    2829             :     uint16_t nPlanarConfig;
    2830             :     uint16_t nPredictor;
    2831             :     uint16_t nPhotometric;
    2832             :     int nOvrJpegQuality;
    2833         132 :     std::string osNoData;
    2834          66 :     uint16_t *panExtraSampleValues = nullptr;
    2835          66 :     uint16_t nExtraSamples = 0;
    2836          66 :     if (!GetOverviewParameters(nCompression, nPlanarConfig, nPredictor,
    2837             :                                nPhotometric, nOvrJpegQuality, osNoData,
    2838             :                                panExtraSampleValues, nExtraSamples,
    2839             :                                /*papszOptions=*/nullptr))
    2840             :     {
    2841           0 :         return CE_Failure;
    2842             :     }
    2843             : 
    2844             :     /* -------------------------------------------------------------------- */
    2845             :     /*      Do we have a palette?  If so, create a TIFF compatible version. */
    2846             :     /* -------------------------------------------------------------------- */
    2847         132 :     std::vector<unsigned short> anTRed;
    2848         132 :     std::vector<unsigned short> anTGreen;
    2849          66 :     std::vector<unsigned short> anTBlue;
    2850          66 :     unsigned short *panRed = nullptr;
    2851          66 :     unsigned short *panGreen = nullptr;
    2852          66 :     unsigned short *panBlue = nullptr;
    2853             : 
    2854          66 :     if (nPhotometric == PHOTOMETRIC_PALETTE && m_poColorTable != nullptr)
    2855             :     {
    2856           0 :         if (m_nColorTableMultiplier == 0)
    2857           0 :             m_nColorTableMultiplier = DEFAULT_COLOR_TABLE_MULTIPLIER_257;
    2858             : 
    2859           0 :         CreateTIFFColorTable(m_poColorTable.get(), nOvBitsPerSample,
    2860             :                              m_nColorTableMultiplier, anTRed, anTGreen, anTBlue,
    2861             :                              panRed, panGreen, panBlue);
    2862             :     }
    2863             : 
    2864          66 :     int nOvrBlockXSize = 0;
    2865          66 :     int nOvrBlockYSize = 0;
    2866          66 :     GTIFFGetOverviewBlockSize(GDALRasterBand::ToHandle(GetRasterBand(1)),
    2867             :                               &nOvrBlockXSize, &nOvrBlockYSize);
    2868             : 
    2869          66 :     CPLErr eErr = CE_None;
    2870             : 
    2871         191 :     for (int i = 0; i < nOverviews && eErr == CE_None; ++i)
    2872             :     {
    2873             :         GDALRasterBand *poOvrBand =
    2874         166 :             poOvrDS ? ((i == 0) ? poOvrDS->GetRasterBand(1)
    2875          41 :                                 : poOvrDS->GetRasterBand(1)->GetOverview(i - 1))
    2876          47 :                     : poSrcDS->GetRasterBand(1)->GetOverview(i);
    2877             : 
    2878         125 :         int nOXSize = poOvrBand->GetXSize();
    2879         125 :         int nOYSize = poOvrBand->GetYSize();
    2880             : 
    2881         250 :         toff_t nOverviewOffset = GTIFFWriteDirectory(
    2882             :             m_hTIFF, FILETYPE_REDUCEDIMAGE, nOXSize, nOYSize, nOvBitsPerSample,
    2883         125 :             nPlanarConfig, m_nSamplesPerPixel, nOvrBlockXSize, nOvrBlockYSize,
    2884         125 :             TRUE, nCompression, nPhotometric, m_nSampleFormat, nPredictor,
    2885             :             panRed, panGreen, panBlue, nExtraSamples, panExtraSampleValues,
    2886             :             osMetadata,
    2887         125 :             nOvrJpegQuality >= 0 ? CPLSPrintf("%d", nOvrJpegQuality) : nullptr,
    2888         125 :             CPLSPrintf("%d", m_nJpegTablesMode),
    2889           2 :             osNoData.empty() ? nullptr : osNoData.c_str(),
    2890         125 :             m_anLercAddCompressionAndVersion, m_bWriteCOGLayout);
    2891             : 
    2892         125 :         if (nOverviewOffset == 0)
    2893           0 :             eErr = CE_Failure;
    2894             :         else
    2895         125 :             eErr = RegisterNewOverviewDataset(nOverviewOffset, nOvrJpegQuality,
    2896             :                                               nullptr);
    2897             :     }
    2898             : 
    2899             :     // For directory reloading, so that the chaining to the next directory is
    2900             :     // reloaded, as well as compression parameters.
    2901          66 :     ReloadDirectory();
    2902             : 
    2903          66 :     CPLFree(panExtraSampleValues);
    2904          66 :     panExtraSampleValues = nullptr;
    2905             : 
    2906          66 :     return eErr;
    2907             : }
    2908             : 
    2909             : /************************************************************************/
    2910             : /*                       CreateInternalMaskOverviews()                  */
    2911             : /************************************************************************/
    2912             : 
    2913         268 : CPLErr GTiffDataset::CreateInternalMaskOverviews(int nOvrBlockXSize,
    2914             :                                                  int nOvrBlockYSize)
    2915             : {
    2916         268 :     ScanDirectories();
    2917             : 
    2918             :     /* -------------------------------------------------------------------- */
    2919             :     /*      Create overviews for the mask.                                  */
    2920             :     /* -------------------------------------------------------------------- */
    2921         268 :     CPLErr eErr = CE_None;
    2922             : 
    2923         268 :     if (m_poMaskDS != nullptr && m_poMaskDS->GetRasterCount() == 1)
    2924             :     {
    2925             :         int nMaskOvrCompression;
    2926          42 :         if (strstr(GDALGetMetadataItem(GDALGetDriverByName("GTiff"),
    2927             :                                        GDAL_DMD_CREATIONOPTIONLIST, nullptr),
    2928          42 :                    "<Value>DEFLATE</Value>") != nullptr)
    2929          42 :             nMaskOvrCompression = COMPRESSION_ADOBE_DEFLATE;
    2930             :         else
    2931           0 :             nMaskOvrCompression = COMPRESSION_PACKBITS;
    2932             : 
    2933         117 :         for (int i = 0; i < m_nOverviewCount; ++i)
    2934             :         {
    2935          75 :             if (m_papoOverviewDS[i]->m_poMaskDS == nullptr)
    2936             :             {
    2937         126 :                 const toff_t nOverviewOffset = GTIFFWriteDirectory(
    2938             :                     m_hTIFF, FILETYPE_REDUCEDIMAGE | FILETYPE_MASK,
    2939          63 :                     m_papoOverviewDS[i]->nRasterXSize,
    2940          63 :                     m_papoOverviewDS[i]->nRasterYSize, 1, PLANARCONFIG_CONTIG,
    2941             :                     1, nOvrBlockXSize, nOvrBlockYSize, TRUE,
    2942             :                     nMaskOvrCompression, PHOTOMETRIC_MASK, SAMPLEFORMAT_UINT,
    2943             :                     PREDICTOR_NONE, nullptr, nullptr, nullptr, 0, nullptr, "",
    2944          63 :                     nullptr, nullptr, nullptr, nullptr, m_bWriteCOGLayout);
    2945             : 
    2946          63 :                 if (nOverviewOffset == 0)
    2947             :                 {
    2948           0 :                     eErr = CE_Failure;
    2949           0 :                     continue;
    2950             :                 }
    2951             : 
    2952          63 :                 GTiffDataset *poODS = new GTiffDataset();
    2953          63 :                 poODS->ShareLockWithParentDataset(this);
    2954          63 :                 poODS->m_pszFilename = CPLStrdup(m_pszFilename);
    2955          63 :                 if (poODS->OpenOffset(VSI_TIFFOpenChild(m_hTIFF),
    2956          63 :                                       nOverviewOffset, GA_Update) != CE_None)
    2957             :                 {
    2958           0 :                     delete poODS;
    2959           0 :                     eErr = CE_Failure;
    2960             :                 }
    2961             :                 else
    2962             :                 {
    2963          63 :                     poODS->m_bPromoteTo8Bits = CPLTestBool(CPLGetConfigOption(
    2964             :                         "GDAL_TIFF_INTERNAL_MASK_TO_8BIT", "YES"));
    2965          63 :                     poODS->m_poBaseDS = this;
    2966          63 :                     poODS->m_poImageryDS = m_papoOverviewDS[i];
    2967          63 :                     m_papoOverviewDS[i]->m_poMaskDS = poODS;
    2968          63 :                     ++m_poMaskDS->m_nOverviewCount;
    2969         126 :                     m_poMaskDS->m_papoOverviewDS =
    2970         126 :                         static_cast<GTiffDataset **>(CPLRealloc(
    2971          63 :                             m_poMaskDS->m_papoOverviewDS,
    2972          63 :                             m_poMaskDS->m_nOverviewCount * (sizeof(void *))));
    2973          63 :                     m_poMaskDS
    2974          63 :                         ->m_papoOverviewDS[m_poMaskDS->m_nOverviewCount - 1] =
    2975             :                         poODS;
    2976             :                 }
    2977             :             }
    2978             :         }
    2979             :     }
    2980             : 
    2981         268 :     ReloadDirectory();
    2982             : 
    2983         268 :     return eErr;
    2984             : }
    2985             : 
    2986             : /************************************************************************/
    2987             : /*                            AddOverviews()                            */
    2988             : /************************************************************************/
    2989             : 
    2990             : CPLErr
    2991          13 : GTiffDataset::AddOverviews(const std::vector<GDALDataset *> &apoSrcOvrDSIn,
    2992             :                            GDALProgressFunc pfnProgress, void *pProgressData,
    2993             :                            CSLConstList papszOptions)
    2994             : {
    2995             :     /* -------------------------------------------------------------------- */
    2996             :     /*      If we don't have read access, then create the overviews         */
    2997             :     /*      externally.                                                     */
    2998             :     /* -------------------------------------------------------------------- */
    2999          13 :     if (GetAccess() != GA_Update)
    3000             :     {
    3001           4 :         CPLDebug("GTiff", "File open for read-only accessing, "
    3002             :                           "creating overviews externally.");
    3003             : 
    3004           4 :         CPLErr eErr = GDALDataset::AddOverviews(apoSrcOvrDSIn, pfnProgress,
    3005             :                                                 pProgressData, papszOptions);
    3006           4 :         if (eErr == CE_None && m_poMaskDS)
    3007             :         {
    3008           0 :             ReportError(
    3009             :                 CE_Warning, CPLE_NotSupported,
    3010             :                 "Building external overviews whereas there is an internal "
    3011             :                 "mask is not fully supported. "
    3012             :                 "The overviews of the non-mask bands will be created, "
    3013             :                 "but not the overviews of the mask band.");
    3014             :         }
    3015           4 :         return eErr;
    3016             :     }
    3017             : 
    3018          18 :     std::vector<GDALDataset *> apoSrcOvrDS = apoSrcOvrDSIn;
    3019             :     // Sort overviews by descending size
    3020           9 :     std::sort(apoSrcOvrDS.begin(), apoSrcOvrDS.end(),
    3021           0 :               [](const GDALDataset *poDS1, const GDALDataset *poDS2)
    3022           0 :               { return poDS1->GetRasterXSize() > poDS2->GetRasterXSize(); });
    3023             : 
    3024           9 :     if (!GDALDefaultOverviews::CheckSrcOverviewsConsistencyWithBase(
    3025             :             this, apoSrcOvrDS))
    3026           5 :         return CE_Failure;
    3027             : 
    3028           4 :     ScanDirectories();
    3029             : 
    3030             :     // Make implicit JPEG overviews invisible, but do not destroy
    3031             :     // them in case they are already used (not sure that the client
    3032             :     // has the right to do that). Behavior maybe undefined in GDAL API.
    3033           4 :     m_nJPEGOverviewCount = 0;
    3034             : 
    3035           4 :     FlushDirectory();
    3036             : 
    3037             :     /* -------------------------------------------------------------------- */
    3038             :     /*      If we are averaging bit data to grayscale we need to create     */
    3039             :     /*      8bit overviews.                                                 */
    3040             :     /* -------------------------------------------------------------------- */
    3041           4 :     int nOvBitsPerSample = m_nBitsPerSample;
    3042             : 
    3043             :     /* -------------------------------------------------------------------- */
    3044             :     /*      Do we need some metadata for the overviews?                     */
    3045             :     /* -------------------------------------------------------------------- */
    3046           8 :     CPLString osMetadata;
    3047             : 
    3048           4 :     const bool bIsForMaskBand = nBands == 1 && GetRasterBand(1)->IsMaskBand();
    3049           4 :     GTIFFBuildOverviewMetadata(/* resampling = */ "", this, bIsForMaskBand,
    3050             :                                osMetadata);
    3051             : 
    3052             :     int nCompression;
    3053             :     uint16_t nPlanarConfig;
    3054             :     uint16_t nPredictor;
    3055             :     uint16_t nPhotometric;
    3056             :     int nOvrJpegQuality;
    3057           8 :     std::string osNoData;
    3058           4 :     uint16_t *panExtraSampleValues = nullptr;
    3059           4 :     uint16_t nExtraSamples = 0;
    3060           4 :     if (!GetOverviewParameters(nCompression, nPlanarConfig, nPredictor,
    3061             :                                nPhotometric, nOvrJpegQuality, osNoData,
    3062             :                                panExtraSampleValues, nExtraSamples,
    3063             :                                papszOptions))
    3064             :     {
    3065           0 :         return CE_Failure;
    3066             :     }
    3067             : 
    3068             :     /* -------------------------------------------------------------------- */
    3069             :     /*      Do we have a palette?  If so, create a TIFF compatible version. */
    3070             :     /* -------------------------------------------------------------------- */
    3071           8 :     std::vector<unsigned short> anTRed;
    3072           8 :     std::vector<unsigned short> anTGreen;
    3073           4 :     std::vector<unsigned short> anTBlue;
    3074           4 :     unsigned short *panRed = nullptr;
    3075           4 :     unsigned short *panGreen = nullptr;
    3076           4 :     unsigned short *panBlue = nullptr;
    3077             : 
    3078           4 :     if (nPhotometric == PHOTOMETRIC_PALETTE && m_poColorTable != nullptr)
    3079             :     {
    3080           0 :         if (m_nColorTableMultiplier == 0)
    3081           0 :             m_nColorTableMultiplier = DEFAULT_COLOR_TABLE_MULTIPLIER_257;
    3082             : 
    3083           0 :         CreateTIFFColorTable(m_poColorTable.get(), nOvBitsPerSample,
    3084             :                              m_nColorTableMultiplier, anTRed, anTGreen, anTBlue,
    3085             :                              panRed, panGreen, panBlue);
    3086             :     }
    3087             : 
    3088             :     /* -------------------------------------------------------------------- */
    3089             :     /*      Establish which of the overview levels we already have, and     */
    3090             :     /*      which are new.  We assume that band 1 of the file is            */
    3091             :     /*      representative.                                                 */
    3092             :     /* -------------------------------------------------------------------- */
    3093           4 :     int nOvrBlockXSize = 0;
    3094           4 :     int nOvrBlockYSize = 0;
    3095           4 :     GTIFFGetOverviewBlockSize(GDALRasterBand::ToHandle(GetRasterBand(1)),
    3096             :                               &nOvrBlockXSize, &nOvrBlockYSize);
    3097             : 
    3098           4 :     CPLErr eErr = CE_None;
    3099           8 :     for (const auto *poSrcOvrDS : apoSrcOvrDS)
    3100             :     {
    3101           4 :         bool bFound = false;
    3102           4 :         for (int i = 0; i < m_nOverviewCount && eErr == CE_None; ++i)
    3103             :         {
    3104           2 :             const GTiffDataset *poExistingODS = m_papoOverviewDS[i];
    3105           2 :             if (poExistingODS->GetRasterXSize() ==
    3106           4 :                     poSrcOvrDS->GetRasterXSize() &&
    3107           2 :                 poExistingODS->GetRasterYSize() == poSrcOvrDS->GetRasterYSize())
    3108             :             {
    3109           2 :                 bFound = true;
    3110           2 :                 break;
    3111             :             }
    3112             :         }
    3113           4 :         if (!bFound && eErr == CE_None)
    3114             :         {
    3115           2 :             if (m_bLayoutIFDSBeforeData && !m_bKnownIncompatibleEdition &&
    3116           0 :                 !m_bWriteKnownIncompatibleEdition)
    3117             :             {
    3118           0 :                 ReportError(CE_Warning, CPLE_AppDefined,
    3119             :                             "Adding new overviews invalidates the "
    3120             :                             "LAYOUT=IFDS_BEFORE_DATA property");
    3121           0 :                 m_bKnownIncompatibleEdition = true;
    3122           0 :                 m_bWriteKnownIncompatibleEdition = true;
    3123             :             }
    3124             : 
    3125           6 :             const toff_t nOverviewOffset = GTIFFWriteDirectory(
    3126             :                 m_hTIFF, FILETYPE_REDUCEDIMAGE, poSrcOvrDS->GetRasterXSize(),
    3127             :                 poSrcOvrDS->GetRasterYSize(), nOvBitsPerSample, nPlanarConfig,
    3128           2 :                 m_nSamplesPerPixel, nOvrBlockXSize, nOvrBlockYSize, TRUE,
    3129           2 :                 nCompression, nPhotometric, m_nSampleFormat, nPredictor, panRed,
    3130             :                 panGreen, panBlue, nExtraSamples, panExtraSampleValues,
    3131             :                 osMetadata,
    3132           2 :                 nOvrJpegQuality >= 0 ? CPLSPrintf("%d", nOvrJpegQuality)
    3133             :                                      : nullptr,
    3134           2 :                 CPLSPrintf("%d", m_nJpegTablesMode),
    3135           0 :                 osNoData.empty() ? nullptr : osNoData.c_str(),
    3136           2 :                 m_anLercAddCompressionAndVersion, false);
    3137             : 
    3138           2 :             if (nOverviewOffset == 0)
    3139           0 :                 eErr = CE_Failure;
    3140             :             else
    3141           2 :                 eErr = RegisterNewOverviewDataset(
    3142             :                     nOverviewOffset, nOvrJpegQuality, papszOptions);
    3143             :         }
    3144             :     }
    3145             : 
    3146           4 :     CPLFree(panExtraSampleValues);
    3147           4 :     panExtraSampleValues = nullptr;
    3148             : 
    3149           4 :     ReloadDirectory();
    3150             : 
    3151           4 :     if (!pfnProgress)
    3152           2 :         pfnProgress = GDALDummyProgress;
    3153             : 
    3154             :     // almost 0, but not 0 to please Coverity Scan
    3155           4 :     double dfTotalPixels = std::numeric_limits<double>::min();
    3156           8 :     for (const auto *poSrcOvrDS : apoSrcOvrDS)
    3157             :     {
    3158           4 :         dfTotalPixels += static_cast<double>(poSrcOvrDS->GetRasterXSize()) *
    3159           4 :                          poSrcOvrDS->GetRasterYSize();
    3160             :     }
    3161             : 
    3162             :     // Copy source datasets into target overview datasets
    3163           4 :     double dfCurPixels = 0;
    3164           8 :     for (auto *poSrcOvrDS : apoSrcOvrDS)
    3165             :     {
    3166           4 :         GDALDataset *poDstOvrDS = nullptr;
    3167           4 :         for (int i = 0; i < m_nOverviewCount && eErr == CE_None; ++i)
    3168             :         {
    3169           4 :             GTiffDataset *poExistingODS = m_papoOverviewDS[i];
    3170           4 :             if (poExistingODS->GetRasterXSize() ==
    3171           8 :                     poSrcOvrDS->GetRasterXSize() &&
    3172           4 :                 poExistingODS->GetRasterYSize() == poSrcOvrDS->GetRasterYSize())
    3173             :             {
    3174           4 :                 poDstOvrDS = poExistingODS;
    3175           4 :                 break;
    3176             :             }
    3177             :         }
    3178           4 :         if (poDstOvrDS)
    3179             :         {
    3180             :             const double dfThisPixels =
    3181           4 :                 static_cast<double>(poSrcOvrDS->GetRasterXSize()) *
    3182           4 :                 poSrcOvrDS->GetRasterYSize();
    3183           8 :             void *pScaledProgressData = GDALCreateScaledProgress(
    3184             :                 dfCurPixels / dfTotalPixels,
    3185           4 :                 (dfCurPixels + dfThisPixels) / dfTotalPixels, pfnProgress,
    3186             :                 pProgressData);
    3187           4 :             dfCurPixels += dfThisPixels;
    3188           4 :             eErr = GDALDatasetCopyWholeRaster(GDALDataset::ToHandle(poSrcOvrDS),
    3189             :                                               GDALDataset::ToHandle(poDstOvrDS),
    3190             :                                               nullptr, GDALScaledProgress,
    3191             :                                               pScaledProgressData);
    3192           4 :             GDALDestroyScaledProgress(pScaledProgressData);
    3193             :         }
    3194             :     }
    3195             : 
    3196           4 :     return eErr;
    3197             : }
    3198             : 
    3199             : /************************************************************************/
    3200             : /*                          IBuildOverviews()                           */
    3201             : /************************************************************************/
    3202             : 
    3203         402 : CPLErr GTiffDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
    3204             :                                      const int *panOverviewList, int nBandsIn,
    3205             :                                      const int *panBandList,
    3206             :                                      GDALProgressFunc pfnProgress,
    3207             :                                      void *pProgressData,
    3208             :                                      CSLConstList papszOptions)
    3209             : 
    3210             : {
    3211         402 :     ScanDirectories();
    3212             : 
    3213             :     // Make implicit JPEG overviews invisible, but do not destroy
    3214             :     // them in case they are already used (not sure that the client
    3215             :     // has the right to do that.  Behavior maybe undefined in GDAL API.
    3216         402 :     m_nJPEGOverviewCount = 0;
    3217             : 
    3218             :     /* -------------------------------------------------------------------- */
    3219             :     /*      If RRD or external OVR overviews requested, then invoke         */
    3220             :     /*      generic handling.                                               */
    3221             :     /* -------------------------------------------------------------------- */
    3222         402 :     bool bUseGenericHandling = false;
    3223             : 
    3224         402 :     if (CPLTestBool(CSLFetchNameValueDef(
    3225         802 :             papszOptions, "USE_RRD", CPLGetConfigOption("USE_RRD", "NO"))) ||
    3226         400 :         CPLTestBool(
    3227             :             CSLFetchNameValueDef(papszOptions, "TIFF_USE_OVR",
    3228             :                                  CPLGetConfigOption("TIFF_USE_OVR", "NO"))))
    3229             :     {
    3230           2 :         bUseGenericHandling = true;
    3231             :     }
    3232             : 
    3233             :     /* -------------------------------------------------------------------- */
    3234             :     /*      If we don't have read access, then create the overviews         */
    3235             :     /*      externally.                                                     */
    3236             :     /* -------------------------------------------------------------------- */
    3237         402 :     if (GetAccess() != GA_Update)
    3238             :     {
    3239         143 :         CPLDebug("GTiff", "File open for read-only accessing, "
    3240             :                           "creating overviews externally.");
    3241             : 
    3242         143 :         bUseGenericHandling = true;
    3243             :     }
    3244             : 
    3245         402 :     if (bUseGenericHandling)
    3246             :     {
    3247         145 :         if (m_nOverviewCount != 0)
    3248             :         {
    3249           0 :             ReportError(CE_Failure, CPLE_NotSupported,
    3250             :                         "Cannot add external overviews when there are already "
    3251             :                         "internal overviews");
    3252           0 :             return CE_Failure;
    3253             :         }
    3254             : 
    3255         145 :         CPLStringList aosOptions(papszOptions);
    3256         145 :         if (!m_bWriteEmptyTiles)
    3257             :         {
    3258           1 :             aosOptions.SetNameValue("SPARSE_OK", "YES");
    3259             :         }
    3260             : 
    3261         145 :         CPLErr eErr = GDALDataset::IBuildOverviews(
    3262             :             pszResampling, nOverviews, panOverviewList, nBandsIn, panBandList,
    3263         145 :             pfnProgress, pProgressData, aosOptions);
    3264         145 :         if (eErr == CE_None && m_poMaskDS)
    3265             :         {
    3266           1 :             ReportError(
    3267             :                 CE_Warning, CPLE_NotSupported,
    3268             :                 "Building external overviews whereas there is an internal "
    3269             :                 "mask is not fully supported. "
    3270             :                 "The overviews of the non-mask bands will be created, "
    3271             :                 "but not the overviews of the mask band.");
    3272             :         }
    3273         145 :         return eErr;
    3274             :     }
    3275             : 
    3276             :     /* -------------------------------------------------------------------- */
    3277             :     /*      Our TIFF overview support currently only works safely if all    */
    3278             :     /*      bands are handled at the same time.                             */
    3279             :     /* -------------------------------------------------------------------- */
    3280         257 :     if (nBandsIn != GetRasterCount())
    3281             :     {
    3282           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3283             :                     "Generation of overviews in TIFF currently only "
    3284             :                     "supported when operating on all bands.  "
    3285             :                     "Operation failed.");
    3286           0 :         return CE_Failure;
    3287             :     }
    3288             : 
    3289             :     /* -------------------------------------------------------------------- */
    3290             :     /*      If zero overviews were requested, we need to clear all          */
    3291             :     /*      existing overviews.                                             */
    3292             :     /* -------------------------------------------------------------------- */
    3293         257 :     if (nOverviews == 0)
    3294             :     {
    3295           8 :         if (m_nOverviewCount == 0)
    3296           3 :             return GDALDataset::IBuildOverviews(
    3297             :                 pszResampling, nOverviews, panOverviewList, nBandsIn,
    3298           3 :                 panBandList, pfnProgress, pProgressData, papszOptions);
    3299             : 
    3300           5 :         return CleanOverviews();
    3301             :     }
    3302             : 
    3303         249 :     CPLErr eErr = CE_None;
    3304             : 
    3305             :     /* -------------------------------------------------------------------- */
    3306             :     /*      Initialize progress counter.                                    */
    3307             :     /* -------------------------------------------------------------------- */
    3308         249 :     if (!pfnProgress(0.0, nullptr, pProgressData))
    3309             :     {
    3310           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    3311           0 :         return CE_Failure;
    3312             :     }
    3313             : 
    3314         249 :     FlushDirectory();
    3315             : 
    3316             :     /* -------------------------------------------------------------------- */
    3317             :     /*      If we are averaging bit data to grayscale we need to create     */
    3318             :     /*      8bit overviews.                                                 */
    3319             :     /* -------------------------------------------------------------------- */
    3320         249 :     int nOvBitsPerSample = m_nBitsPerSample;
    3321             : 
    3322         249 :     if (STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2"))
    3323           2 :         nOvBitsPerSample = 8;
    3324             : 
    3325             :     /* -------------------------------------------------------------------- */
    3326             :     /*      Do we need some metadata for the overviews?                     */
    3327             :     /* -------------------------------------------------------------------- */
    3328         498 :     CPLString osMetadata;
    3329             : 
    3330         249 :     const bool bIsForMaskBand = nBands == 1 && GetRasterBand(1)->IsMaskBand();
    3331         249 :     GTIFFBuildOverviewMetadata(pszResampling, this, bIsForMaskBand, osMetadata);
    3332             : 
    3333             :     int nCompression;
    3334             :     uint16_t nPlanarConfig;
    3335             :     uint16_t nPredictor;
    3336             :     uint16_t nPhotometric;
    3337             :     int nOvrJpegQuality;
    3338         498 :     std::string osNoData;
    3339         249 :     uint16_t *panExtraSampleValues = nullptr;
    3340         249 :     uint16_t nExtraSamples = 0;
    3341         249 :     if (!GetOverviewParameters(nCompression, nPlanarConfig, nPredictor,
    3342             :                                nPhotometric, nOvrJpegQuality, osNoData,
    3343             :                                panExtraSampleValues, nExtraSamples,
    3344             :                                papszOptions))
    3345             :     {
    3346           0 :         return CE_Failure;
    3347             :     }
    3348             : 
    3349             :     /* -------------------------------------------------------------------- */
    3350             :     /*      Do we have a palette?  If so, create a TIFF compatible version. */
    3351             :     /* -------------------------------------------------------------------- */
    3352         498 :     std::vector<unsigned short> anTRed;
    3353         498 :     std::vector<unsigned short> anTGreen;
    3354         498 :     std::vector<unsigned short> anTBlue;
    3355         249 :     unsigned short *panRed = nullptr;
    3356         249 :     unsigned short *panGreen = nullptr;
    3357         249 :     unsigned short *panBlue = nullptr;
    3358             : 
    3359         249 :     if (nPhotometric == PHOTOMETRIC_PALETTE && m_poColorTable != nullptr)
    3360             :     {
    3361          12 :         if (m_nColorTableMultiplier == 0)
    3362           0 :             m_nColorTableMultiplier = DEFAULT_COLOR_TABLE_MULTIPLIER_257;
    3363             : 
    3364          12 :         CreateTIFFColorTable(m_poColorTable.get(), nOvBitsPerSample,
    3365             :                              m_nColorTableMultiplier, anTRed, anTGreen, anTBlue,
    3366             :                              panRed, panGreen, panBlue);
    3367             :     }
    3368             : 
    3369             :     /* -------------------------------------------------------------------- */
    3370             :     /*      Establish which of the overview levels we already have, and     */
    3371             :     /*      which are new.  We assume that band 1 of the file is            */
    3372             :     /*      representative.                                                 */
    3373             :     /* -------------------------------------------------------------------- */
    3374         249 :     int nOvrBlockXSize = 0;
    3375         249 :     int nOvrBlockYSize = 0;
    3376         249 :     GTIFFGetOverviewBlockSize(GDALRasterBand::ToHandle(GetRasterBand(1)),
    3377             :                               &nOvrBlockXSize, &nOvrBlockYSize);
    3378         498 :     std::vector<bool> abRequireNewOverview(nOverviews, true);
    3379         682 :     for (int i = 0; i < nOverviews && eErr == CE_None; ++i)
    3380             :     {
    3381         766 :         for (int j = 0; j < m_nOverviewCount && eErr == CE_None; ++j)
    3382             :         {
    3383         389 :             GTiffDataset *poODS = m_papoOverviewDS[j];
    3384             : 
    3385             :             const int nOvFactor =
    3386         389 :                 GDALComputeOvFactor(poODS->GetRasterXSize(), GetRasterXSize(),
    3387             :                                     poODS->GetRasterYSize(), GetRasterYSize());
    3388             : 
    3389             :             // If we already have a 1x1 overview and this new one would result
    3390             :             // in it too, then don't create it.
    3391         449 :             if (poODS->GetRasterXSize() == 1 && poODS->GetRasterYSize() == 1 &&
    3392         449 :                 DIV_ROUND_UP(GetRasterXSize(), panOverviewList[i]) == 1 &&
    3393          21 :                 DIV_ROUND_UP(GetRasterYSize(), panOverviewList[i]) == 1)
    3394             :             {
    3395          21 :                 abRequireNewOverview[i] = false;
    3396          21 :                 break;
    3397             :             }
    3398             : 
    3399         701 :             if (nOvFactor == panOverviewList[i] ||
    3400         333 :                 nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
    3401             :                                                 GetRasterXSize(),
    3402             :                                                 GetRasterYSize()))
    3403             :             {
    3404          35 :                 abRequireNewOverview[i] = false;
    3405          35 :                 break;
    3406             :             }
    3407             :         }
    3408             : 
    3409         433 :         if (abRequireNewOverview[i])
    3410             :         {
    3411         377 :             if (m_bLayoutIFDSBeforeData && !m_bKnownIncompatibleEdition &&
    3412           2 :                 !m_bWriteKnownIncompatibleEdition)
    3413             :             {
    3414           2 :                 ReportError(CE_Warning, CPLE_AppDefined,
    3415             :                             "Adding new overviews invalidates the "
    3416             :                             "LAYOUT=IFDS_BEFORE_DATA property");
    3417           2 :                 m_bKnownIncompatibleEdition = true;
    3418           2 :                 m_bWriteKnownIncompatibleEdition = true;
    3419             :             }
    3420             : 
    3421             :             const int nOXSize =
    3422         377 :                 DIV_ROUND_UP(GetRasterXSize(), panOverviewList[i]);
    3423             :             const int nOYSize =
    3424         377 :                 DIV_ROUND_UP(GetRasterYSize(), panOverviewList[i]);
    3425             : 
    3426         754 :             const toff_t nOverviewOffset = GTIFFWriteDirectory(
    3427             :                 m_hTIFF, FILETYPE_REDUCEDIMAGE, nOXSize, nOYSize,
    3428         377 :                 nOvBitsPerSample, nPlanarConfig, m_nSamplesPerPixel,
    3429             :                 nOvrBlockXSize, nOvrBlockYSize, TRUE, nCompression,
    3430         377 :                 nPhotometric, m_nSampleFormat, nPredictor, panRed, panGreen,
    3431             :                 panBlue, nExtraSamples, panExtraSampleValues, osMetadata,
    3432         377 :                 nOvrJpegQuality >= 0 ? CPLSPrintf("%d", nOvrJpegQuality)
    3433             :                                      : nullptr,
    3434         377 :                 CPLSPrintf("%d", m_nJpegTablesMode),
    3435          25 :                 osNoData.empty() ? nullptr : osNoData.c_str(),
    3436         377 :                 m_anLercAddCompressionAndVersion, false);
    3437             : 
    3438         377 :             if (nOverviewOffset == 0)
    3439           0 :                 eErr = CE_Failure;
    3440             :             else
    3441         377 :                 eErr = RegisterNewOverviewDataset(
    3442             :                     nOverviewOffset, nOvrJpegQuality, papszOptions);
    3443             :         }
    3444             :     }
    3445             : 
    3446         249 :     CPLFree(panExtraSampleValues);
    3447         249 :     panExtraSampleValues = nullptr;
    3448             : 
    3449         249 :     ReloadDirectory();
    3450             : 
    3451             :     /* -------------------------------------------------------------------- */
    3452             :     /*      Create overviews for the mask.                                  */
    3453             :     /* -------------------------------------------------------------------- */
    3454         249 :     if (eErr != CE_None)
    3455           0 :         return eErr;
    3456             : 
    3457         249 :     eErr = CreateInternalMaskOverviews(nOvrBlockXSize, nOvrBlockYSize);
    3458             : 
    3459             :     /* -------------------------------------------------------------------- */
    3460             :     /*      Refresh overviews for the mask                                  */
    3461             :     /* -------------------------------------------------------------------- */
    3462             :     const bool bHasInternalMask =
    3463         249 :         m_poMaskDS != nullptr && m_poMaskDS->GetRasterCount() == 1;
    3464             :     const bool bHasExternalMask =
    3465         249 :         !bHasInternalMask && oOvManager.HaveMaskFile();
    3466         249 :     const bool bHasMask = bHasInternalMask || bHasExternalMask;
    3467             : 
    3468         249 :     if (bHasInternalMask)
    3469             :     {
    3470          23 :         int nMaskOverviews = 0;
    3471             : 
    3472             :         GDALRasterBand **papoOverviewBands = static_cast<GDALRasterBand **>(
    3473          23 :             CPLCalloc(sizeof(void *), m_nOverviewCount));
    3474          62 :         for (int i = 0; i < m_nOverviewCount; ++i)
    3475             :         {
    3476          39 :             if (m_papoOverviewDS[i]->m_poMaskDS != nullptr)
    3477             :             {
    3478          39 :                 papoOverviewBands[nMaskOverviews++] =
    3479          39 :                     m_papoOverviewDS[i]->m_poMaskDS->GetRasterBand(1);
    3480             :             }
    3481             :         }
    3482             : 
    3483          46 :         void *pScaledProgressData = GDALCreateScaledProgress(
    3484          23 :             0, 1.0 / (nBands + 1), pfnProgress, pProgressData);
    3485          46 :         eErr = GDALRegenerateOverviewsEx(
    3486          23 :             m_poMaskDS->GetRasterBand(1), nMaskOverviews,
    3487             :             reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
    3488             :             pszResampling, GDALScaledProgress, pScaledProgressData,
    3489             :             papszOptions);
    3490          23 :         GDALDestroyScaledProgress(pScaledProgressData);
    3491          23 :         CPLFree(papoOverviewBands);
    3492             :     }
    3493         226 :     else if (bHasExternalMask)
    3494             :     {
    3495           4 :         void *pScaledProgressData = GDALCreateScaledProgress(
    3496           2 :             0, 1.0 / (nBands + 1), pfnProgress, pProgressData);
    3497           2 :         eErr = oOvManager.BuildOverviewsMask(
    3498             :             pszResampling, nOverviews, panOverviewList, GDALScaledProgress,
    3499             :             pScaledProgressData, papszOptions);
    3500           2 :         GDALDestroyScaledProgress(pScaledProgressData);
    3501             :     }
    3502             : 
    3503             :     // If we have an alpha band, we want it to be generated before downsampling
    3504             :     // other bands
    3505         249 :     bool bHasAlphaBand = false;
    3506       66241 :     for (int iBand = 0; iBand < nBands; iBand++)
    3507             :     {
    3508       65992 :         if (papoBands[iBand]->GetColorInterpretation() == GCI_AlphaBand)
    3509          18 :             bHasAlphaBand = true;
    3510             :     }
    3511             : 
    3512             :     /* -------------------------------------------------------------------- */
    3513             :     /*      Refresh old overviews that were listed.                         */
    3514             :     /* -------------------------------------------------------------------- */
    3515         249 :     const auto poColorTable = GetRasterBand(panBandList[0])->GetColorTable();
    3516          20 :     if ((m_nPlanarConfig == PLANARCONFIG_CONTIG || bHasAlphaBand) &&
    3517         231 :         GDALDataTypeIsComplex(
    3518         231 :             GetRasterBand(panBandList[0])->GetRasterDataType()) == FALSE &&
    3519          12 :         (poColorTable == nullptr || STARTS_WITH_CI(pszResampling, "NEAR") ||
    3520         499 :          poColorTable->IsIdentity()) &&
    3521         223 :         (STARTS_WITH_CI(pszResampling, "NEAR") ||
    3522         117 :          EQUAL(pszResampling, "AVERAGE") || EQUAL(pszResampling, "RMS") ||
    3523          48 :          EQUAL(pszResampling, "GAUSS") || EQUAL(pszResampling, "CUBIC") ||
    3524          29 :          EQUAL(pszResampling, "CUBICSPLINE") ||
    3525          28 :          EQUAL(pszResampling, "LANCZOS") || EQUAL(pszResampling, "BILINEAR") ||
    3526          24 :          EQUAL(pszResampling, "MODE")))
    3527             :     {
    3528             :         // In the case of pixel interleaved compressed overviews, we want to
    3529             :         // generate the overviews for all the bands block by block, and not
    3530             :         // band after band, in order to write the block once and not loose
    3531             :         // space in the TIFF file.  We also use that logic for uncompressed
    3532             :         // overviews, since GDALRegenerateOverviewsMultiBand() will be able to
    3533             :         // trigger cascading overview regeneration even in the presence
    3534             :         // of an alpha band.
    3535             : 
    3536         202 :         int nNewOverviews = 0;
    3537             : 
    3538             :         GDALRasterBand ***papapoOverviewBands = static_cast<GDALRasterBand ***>(
    3539         202 :             CPLCalloc(sizeof(void *), nBandsIn));
    3540             :         GDALRasterBand **papoBandList =
    3541         202 :             static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nBandsIn));
    3542       66101 :         for (int iBand = 0; iBand < nBandsIn; ++iBand)
    3543             :         {
    3544       65899 :             GDALRasterBand *poBand = GetRasterBand(panBandList[iBand]);
    3545             : 
    3546       65899 :             papoBandList[iBand] = poBand;
    3547      131798 :             papapoOverviewBands[iBand] = static_cast<GDALRasterBand **>(
    3548       65899 :                 CPLCalloc(sizeof(void *), poBand->GetOverviewCount()));
    3549             : 
    3550       65899 :             int iCurOverview = 0;
    3551             :             std::vector<bool> abAlreadyUsedOverviewBand(
    3552       65899 :                 poBand->GetOverviewCount(), false);
    3553             : 
    3554      132084 :             for (int i = 0; i < nOverviews; ++i)
    3555             :             {
    3556       66645 :                 for (int j = 0; j < poBand->GetOverviewCount(); ++j)
    3557             :                 {
    3558       66630 :                     if (abAlreadyUsedOverviewBand[j])
    3559         459 :                         continue;
    3560             : 
    3561             :                     int nOvFactor;
    3562       66171 :                     GDALRasterBand *poOverview = poBand->GetOverview(j);
    3563             : 
    3564       66171 :                     nOvFactor = GDALComputeOvFactor(
    3565             :                         poOverview->GetXSize(), poBand->GetXSize(),
    3566             :                         poOverview->GetYSize(), poBand->GetYSize());
    3567             : 
    3568       66171 :                     GDALCopyNoDataValue(poOverview, poBand);
    3569             : 
    3570       66172 :                     if (nOvFactor == panOverviewList[i] ||
    3571           1 :                         nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
    3572             :                                                         poBand->GetXSize(),
    3573             :                                                         poBand->GetYSize()))
    3574             :                     {
    3575       66170 :                         if (iBand == 0)
    3576             :                         {
    3577             :                             const auto osNewResampling =
    3578         658 :                                 GDALGetNormalizedOvrResampling(pszResampling);
    3579             :                             const char *pszExistingResampling =
    3580         329 :                                 poOverview->GetMetadataItem("RESAMPLING");
    3581         658 :                             if (pszExistingResampling &&
    3582         329 :                                 pszExistingResampling != osNewResampling)
    3583             :                             {
    3584           2 :                                 poOverview->SetMetadataItem(
    3585           2 :                                     "RESAMPLING", osNewResampling.c_str());
    3586             :                             }
    3587             :                         }
    3588             : 
    3589       66170 :                         abAlreadyUsedOverviewBand[j] = true;
    3590       66170 :                         CPLAssert(iCurOverview < poBand->GetOverviewCount());
    3591       66170 :                         papapoOverviewBands[iBand][iCurOverview] = poOverview;
    3592       66170 :                         ++iCurOverview;
    3593       66170 :                         break;
    3594             :                     }
    3595             :                 }
    3596             :             }
    3597             : 
    3598       65899 :             if (nNewOverviews == 0)
    3599             :             {
    3600         202 :                 nNewOverviews = iCurOverview;
    3601             :             }
    3602       65697 :             else if (nNewOverviews != iCurOverview)
    3603             :             {
    3604           0 :                 CPLAssert(false);
    3605             :                 return CE_Failure;
    3606             :             }
    3607             :         }
    3608             : 
    3609             :         void *pScaledProgressData =
    3610         202 :             bHasMask ? GDALCreateScaledProgress(1.0 / (nBands + 1), 1.0,
    3611             :                                                 pfnProgress, pProgressData)
    3612         177 :                      : GDALCreateScaledProgress(0.0, 1.0, pfnProgress,
    3613         202 :                                                 pProgressData);
    3614         202 :         GDALRegenerateOverviewsMultiBand(nBandsIn, papoBandList, nNewOverviews,
    3615             :                                          papapoOverviewBands, pszResampling,
    3616             :                                          GDALScaledProgress,
    3617             :                                          pScaledProgressData, papszOptions);
    3618         202 :         GDALDestroyScaledProgress(pScaledProgressData);
    3619             : 
    3620       66101 :         for (int iBand = 0; iBand < nBandsIn; ++iBand)
    3621             :         {
    3622       65899 :             CPLFree(papapoOverviewBands[iBand]);
    3623             :         }
    3624         202 :         CPLFree(papapoOverviewBands);
    3625         202 :         CPLFree(papoBandList);
    3626             :     }
    3627             :     else
    3628             :     {
    3629             :         GDALRasterBand **papoOverviewBands = static_cast<GDALRasterBand **>(
    3630          47 :             CPLCalloc(sizeof(void *), nOverviews));
    3631             : 
    3632          47 :         const int iBandOffset = bHasMask ? 1 : 0;
    3633             : 
    3634         140 :         for (int iBand = 0; iBand < nBandsIn && eErr == CE_None; ++iBand)
    3635             :         {
    3636          93 :             GDALRasterBand *poBand = GetRasterBand(panBandList[iBand]);
    3637          93 :             if (poBand == nullptr)
    3638             :             {
    3639           0 :                 eErr = CE_Failure;
    3640           0 :                 break;
    3641             :             }
    3642             : 
    3643             :             std::vector<bool> abAlreadyUsedOverviewBand(
    3644         186 :                 poBand->GetOverviewCount(), false);
    3645             : 
    3646          93 :             int nNewOverviews = 0;
    3647         282 :             for (int i = 0; i < nOverviews; ++i)
    3648             :             {
    3649         447 :                 for (int j = 0; j < poBand->GetOverviewCount(); ++j)
    3650             :                 {
    3651         429 :                     if (abAlreadyUsedOverviewBand[j])
    3652         257 :                         continue;
    3653             : 
    3654         172 :                     GDALRasterBand *poOverview = poBand->GetOverview(j);
    3655             : 
    3656         172 :                     GDALCopyNoDataValue(poOverview, poBand);
    3657             : 
    3658         172 :                     const int nOvFactor = GDALComputeOvFactor(
    3659             :                         poOverview->GetXSize(), poBand->GetXSize(),
    3660             :                         poOverview->GetYSize(), poBand->GetYSize());
    3661             : 
    3662         173 :                     if (nOvFactor == panOverviewList[i] ||
    3663           1 :                         nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
    3664             :                                                         poBand->GetXSize(),
    3665             :                                                         poBand->GetYSize()))
    3666             :                     {
    3667         171 :                         if (iBand == 0)
    3668             :                         {
    3669             :                             const auto osNewResampling =
    3670         166 :                                 GDALGetNormalizedOvrResampling(pszResampling);
    3671             :                             const char *pszExistingResampling =
    3672          83 :                                 poOverview->GetMetadataItem("RESAMPLING");
    3673         134 :                             if (pszExistingResampling &&
    3674          51 :                                 pszExistingResampling != osNewResampling)
    3675             :                             {
    3676           1 :                                 poOverview->SetMetadataItem(
    3677           1 :                                     "RESAMPLING", osNewResampling.c_str());
    3678             :                             }
    3679             :                         }
    3680             : 
    3681         171 :                         abAlreadyUsedOverviewBand[j] = true;
    3682         171 :                         CPLAssert(nNewOverviews < poBand->GetOverviewCount());
    3683         171 :                         papoOverviewBands[nNewOverviews++] = poOverview;
    3684         171 :                         break;
    3685             :                     }
    3686             :                 }
    3687             :             }
    3688             : 
    3689         186 :             void *pScaledProgressData = GDALCreateScaledProgress(
    3690          93 :                 (iBand + iBandOffset) /
    3691          93 :                     static_cast<double>(nBandsIn + iBandOffset),
    3692          93 :                 (iBand + iBandOffset + 1) /
    3693          93 :                     static_cast<double>(nBandsIn + iBandOffset),
    3694             :                 pfnProgress, pProgressData);
    3695             : 
    3696          93 :             eErr = GDALRegenerateOverviewsEx(
    3697             :                 poBand, nNewOverviews,
    3698             :                 reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
    3699             :                 pszResampling, GDALScaledProgress, pScaledProgressData,
    3700             :                 papszOptions);
    3701             : 
    3702          93 :             GDALDestroyScaledProgress(pScaledProgressData);
    3703             :         }
    3704             : 
    3705             :         /* --------------------------------------------------------------------
    3706             :          */
    3707             :         /*      Cleanup */
    3708             :         /* --------------------------------------------------------------------
    3709             :          */
    3710          47 :         CPLFree(papoOverviewBands);
    3711             :     }
    3712             : 
    3713         249 :     pfnProgress(1.0, nullptr, pProgressData);
    3714             : 
    3715         249 :     return eErr;
    3716             : }
    3717             : 
    3718             : /************************************************************************/
    3719             : /*                      GTiffWriteDummyGeokeyDirectory()                */
    3720             : /************************************************************************/
    3721             : 
    3722        1395 : static void GTiffWriteDummyGeokeyDirectory(TIFF *hTIFF)
    3723             : {
    3724             :     // If we have existing geokeys, try to wipe them
    3725             :     // by writing a dummy geokey directory. (#2546)
    3726        1395 :     uint16_t *panVI = nullptr;
    3727        1395 :     uint16_t nKeyCount = 0;
    3728             : 
    3729        1395 :     if (TIFFGetField(hTIFF, TIFFTAG_GEOKEYDIRECTORY, &nKeyCount, &panVI))
    3730             :     {
    3731          24 :         GUInt16 anGKVersionInfo[4] = {1, 1, 0, 0};
    3732          24 :         double adfDummyDoubleParams[1] = {0.0};
    3733          24 :         TIFFSetField(hTIFF, TIFFTAG_GEOKEYDIRECTORY, 4, anGKVersionInfo);
    3734          24 :         TIFFSetField(hTIFF, TIFFTAG_GEODOUBLEPARAMS, 1, adfDummyDoubleParams);
    3735          24 :         TIFFSetField(hTIFF, TIFFTAG_GEOASCIIPARAMS, "");
    3736             :     }
    3737        1395 : }
    3738             : 
    3739             : /************************************************************************/
    3740             : /*                    IsSRSCompatibleOfGeoTIFF()                        */
    3741             : /************************************************************************/
    3742             : 
    3743        2957 : static bool IsSRSCompatibleOfGeoTIFF(const OGRSpatialReference *poSRS,
    3744             :                                      GTIFFKeysFlavorEnum eGeoTIFFKeysFlavor)
    3745             : {
    3746        2957 :     char *pszWKT = nullptr;
    3747        2957 :     if ((poSRS->IsGeographic() || poSRS->IsProjected()) && !poSRS->IsCompound())
    3748             :     {
    3749        2939 :         const char *pszAuthName = poSRS->GetAuthorityName(nullptr);
    3750        2939 :         const char *pszAuthCode = poSRS->GetAuthorityCode(nullptr);
    3751        2939 :         if (pszAuthName && pszAuthCode && EQUAL(pszAuthName, "EPSG"))
    3752        2439 :             return true;
    3753             :     }
    3754             :     OGRErr eErr;
    3755             :     {
    3756        1036 :         CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
    3757        1036 :         if (poSRS->IsDerivedGeographic() ||
    3758         518 :             (poSRS->IsProjected() && !poSRS->IsCompound() &&
    3759          68 :              poSRS->GetAxesCount() == 3))
    3760             :         {
    3761           0 :             eErr = OGRERR_FAILURE;
    3762             :         }
    3763             :         else
    3764             :         {
    3765             :             // Geographic3D CRS can't be exported to WKT1, but are
    3766             :             // valid GeoTIFF 1.1
    3767         518 :             const char *const apszOptions[] = {
    3768         518 :                 poSRS->IsGeographic() ? nullptr : "FORMAT=WKT1", nullptr};
    3769         518 :             eErr = poSRS->exportToWkt(&pszWKT, apszOptions);
    3770         518 :             if (eErr == OGRERR_FAILURE && poSRS->IsProjected() &&
    3771             :                 eGeoTIFFKeysFlavor == GEOTIFF_KEYS_ESRI_PE)
    3772             :             {
    3773           0 :                 CPLFree(pszWKT);
    3774           0 :                 const char *const apszOptionsESRIWKT[] = {"FORMAT=WKT1_ESRI",
    3775             :                                                           nullptr};
    3776           0 :                 eErr = poSRS->exportToWkt(&pszWKT, apszOptionsESRIWKT);
    3777             :             }
    3778             :         }
    3779             :     }
    3780         518 :     const bool bCompatibleOfGeoTIFF =
    3781        1035 :         (eErr == OGRERR_NONE && pszWKT != nullptr &&
    3782         517 :          strstr(pszWKT, "custom_proj4") == nullptr);
    3783         518 :     CPLFree(pszWKT);
    3784         518 :     return bCompatibleOfGeoTIFF;
    3785             : }
    3786             : 
    3787             : /************************************************************************/
    3788             : /*                          WriteGeoTIFFInfo()                          */
    3789             : /************************************************************************/
    3790             : 
    3791        5602 : void GTiffDataset::WriteGeoTIFFInfo()
    3792             : 
    3793             : {
    3794        5602 :     bool bPixelIsPoint = false;
    3795        5602 :     bool bPointGeoIgnore = false;
    3796             : 
    3797             :     const char *pszAreaOrPoint =
    3798        5602 :         GTiffDataset::GetMetadataItem(GDALMD_AREA_OR_POINT);
    3799        5602 :     if (pszAreaOrPoint && EQUAL(pszAreaOrPoint, GDALMD_AOP_POINT))
    3800             :     {
    3801          17 :         bPixelIsPoint = true;
    3802             :         bPointGeoIgnore =
    3803          17 :             CPLTestBool(CPLGetConfigOption("GTIFF_POINT_GEO_IGNORE", "FALSE"));
    3804             :     }
    3805             : 
    3806        5602 :     if (m_bForceUnsetGTOrGCPs)
    3807             :     {
    3808          11 :         m_bNeedsRewrite = true;
    3809          11 :         m_bForceUnsetGTOrGCPs = false;
    3810             : 
    3811          11 :         TIFFUnsetField(m_hTIFF, TIFFTAG_GEOPIXELSCALE);
    3812          11 :         TIFFUnsetField(m_hTIFF, TIFFTAG_GEOTIEPOINTS);
    3813          11 :         TIFFUnsetField(m_hTIFF, TIFFTAG_GEOTRANSMATRIX);
    3814             :     }
    3815             : 
    3816        5602 :     if (m_bForceUnsetProjection)
    3817             :     {
    3818           8 :         m_bNeedsRewrite = true;
    3819           8 :         m_bForceUnsetProjection = false;
    3820             : 
    3821           8 :         TIFFUnsetField(m_hTIFF, TIFFTAG_GEOKEYDIRECTORY);
    3822           8 :         TIFFUnsetField(m_hTIFF, TIFFTAG_GEODOUBLEPARAMS);
    3823           8 :         TIFFUnsetField(m_hTIFF, TIFFTAG_GEOASCIIPARAMS);
    3824             :     }
    3825             : 
    3826             :     /* -------------------------------------------------------------------- */
    3827             :     /*      Write geotransform if valid.                                    */
    3828             :     /* -------------------------------------------------------------------- */
    3829        5602 :     if (m_bGeoTransformValid)
    3830             :     {
    3831        1683 :         m_bNeedsRewrite = true;
    3832             : 
    3833             :         /* --------------------------------------------------------------------
    3834             :          */
    3835             :         /*      Clear old tags to ensure we don't end up with conflicting */
    3836             :         /*      information. (#2625) */
    3837             :         /* --------------------------------------------------------------------
    3838             :          */
    3839        1683 :         TIFFUnsetField(m_hTIFF, TIFFTAG_GEOPIXELSCALE);
    3840        1683 :         TIFFUnsetField(m_hTIFF, TIFFTAG_GEOTIEPOINTS);
    3841        1683 :         TIFFUnsetField(m_hTIFF, TIFFTAG_GEOTRANSMATRIX);
    3842             : 
    3843             :         /* --------------------------------------------------------------------
    3844             :          */
    3845             :         /*      Write the transform.  If we have a normal north-up image we */
    3846             :         /*      use the tiepoint plus pixelscale otherwise we use a matrix. */
    3847             :         /* --------------------------------------------------------------------
    3848             :          */
    3849        1683 :         if (m_gt[2] == 0.0 && m_gt[4] == 0.0 && m_gt[5] < 0.0)
    3850             :         {
    3851        1617 :             double dfOffset = 0.0;
    3852        1617 :             if (m_eProfile != GTiffProfile::BASELINE)
    3853             :             {
    3854             :                 // In the case the SRS has a vertical component and we have
    3855             :                 // a single band, encode its scale/offset in the GeoTIFF tags
    3856        1611 :                 int bHasScale = FALSE;
    3857        1611 :                 double dfScale = GetRasterBand(1)->GetScale(&bHasScale);
    3858        1611 :                 int bHasOffset = FALSE;
    3859        1611 :                 dfOffset = GetRasterBand(1)->GetOffset(&bHasOffset);
    3860             :                 const bool bApplyScaleOffset =
    3861        1611 :                     m_oSRS.IsVertical() && GetRasterCount() == 1;
    3862        1611 :                 if (bApplyScaleOffset && !bHasScale)
    3863           0 :                     dfScale = 1.0;
    3864        1611 :                 if (!bApplyScaleOffset || !bHasOffset)
    3865        1608 :                     dfOffset = 0.0;
    3866             :                 const double adfPixelScale[3] = {
    3867        1611 :                     m_gt[1], fabs(m_gt[5]), bApplyScaleOffset ? dfScale : 0.0};
    3868        1611 :                 TIFFSetField(m_hTIFF, TIFFTAG_GEOPIXELSCALE, 3, adfPixelScale);
    3869             :             }
    3870             : 
    3871        1617 :             double adfTiePoints[6] = {0.0,     0.0,     0.0,
    3872        1617 :                                       m_gt[0], m_gt[3], dfOffset};
    3873             : 
    3874        1617 :             if (bPixelIsPoint && !bPointGeoIgnore)
    3875             :             {
    3876          13 :                 adfTiePoints[3] += m_gt[1] * 0.5 + m_gt[2] * 0.5;
    3877          13 :                 adfTiePoints[4] += m_gt[4] * 0.5 + m_gt[5] * 0.5;
    3878             :             }
    3879             : 
    3880        1617 :             if (m_eProfile != GTiffProfile::BASELINE)
    3881        1611 :                 TIFFSetField(m_hTIFF, TIFFTAG_GEOTIEPOINTS, 6, adfTiePoints);
    3882             :         }
    3883             :         else
    3884             :         {
    3885          66 :             double adfMatrix[16] = {};
    3886             : 
    3887          66 :             adfMatrix[0] = m_gt[1];
    3888          66 :             adfMatrix[1] = m_gt[2];
    3889          66 :             adfMatrix[3] = m_gt[0];
    3890          66 :             adfMatrix[4] = m_gt[4];
    3891          66 :             adfMatrix[5] = m_gt[5];
    3892          66 :             adfMatrix[7] = m_gt[3];
    3893          66 :             adfMatrix[15] = 1.0;
    3894             : 
    3895          66 :             if (bPixelIsPoint && !bPointGeoIgnore)
    3896             :             {
    3897           0 :                 adfMatrix[3] += m_gt[1] * 0.5 + m_gt[2] * 0.5;
    3898           0 :                 adfMatrix[7] += m_gt[4] * 0.5 + m_gt[5] * 0.5;
    3899             :             }
    3900             : 
    3901          66 :             if (m_eProfile != GTiffProfile::BASELINE)
    3902          66 :                 TIFFSetField(m_hTIFF, TIFFTAG_GEOTRANSMATRIX, 16, adfMatrix);
    3903             :         }
    3904             : 
    3905             :         // Do we need a world file?
    3906        1683 :         if (CPLFetchBool(m_papszCreationOptions, "TFW", false))
    3907           7 :             GDALWriteWorldFile(m_pszFilename, "tfw", m_gt.data());
    3908        1676 :         else if (CPLFetchBool(m_papszCreationOptions, "WORLDFILE", false))
    3909           2 :             GDALWriteWorldFile(m_pszFilename, "wld", m_gt.data());
    3910             :     }
    3911        3933 :     else if (GetGCPCount() > 0 && GetGCPCount() <= knMAX_GCP_COUNT &&
    3912          14 :              m_eProfile != GTiffProfile::BASELINE)
    3913             :     {
    3914          14 :         m_bNeedsRewrite = true;
    3915             : 
    3916             :         double *padfTiePoints = static_cast<double *>(
    3917          14 :             CPLMalloc(6 * sizeof(double) * GetGCPCount()));
    3918             : 
    3919          74 :         for (size_t iGCP = 0; iGCP < m_aoGCPs.size(); ++iGCP)
    3920             :         {
    3921             : 
    3922          60 :             padfTiePoints[iGCP * 6 + 0] = m_aoGCPs[iGCP].Pixel();
    3923          60 :             padfTiePoints[iGCP * 6 + 1] = m_aoGCPs[iGCP].Line();
    3924          60 :             padfTiePoints[iGCP * 6 + 2] = 0;
    3925          60 :             padfTiePoints[iGCP * 6 + 3] = m_aoGCPs[iGCP].X();
    3926          60 :             padfTiePoints[iGCP * 6 + 4] = m_aoGCPs[iGCP].Y();
    3927          60 :             padfTiePoints[iGCP * 6 + 5] = m_aoGCPs[iGCP].Z();
    3928             : 
    3929          60 :             if (bPixelIsPoint && !bPointGeoIgnore)
    3930             :             {
    3931           0 :                 padfTiePoints[iGCP * 6 + 0] += 0.5;
    3932           0 :                 padfTiePoints[iGCP * 6 + 1] += 0.5;
    3933             :             }
    3934             :         }
    3935             : 
    3936          14 :         TIFFSetField(m_hTIFF, TIFFTAG_GEOTIEPOINTS, 6 * GetGCPCount(),
    3937             :                      padfTiePoints);
    3938          14 :         CPLFree(padfTiePoints);
    3939             :     }
    3940             : 
    3941             :     /* -------------------------------------------------------------------- */
    3942             :     /*      Write out projection definition.                                */
    3943             :     /* -------------------------------------------------------------------- */
    3944        5602 :     const bool bHasProjection = !m_oSRS.IsEmpty();
    3945        5602 :     if ((bHasProjection || bPixelIsPoint) &&
    3946        1399 :         m_eProfile != GTiffProfile::BASELINE)
    3947             :     {
    3948        1395 :         m_bNeedsRewrite = true;
    3949             : 
    3950             :         // If we have existing geokeys, try to wipe them
    3951             :         // by writing a dummy geokey directory. (#2546)
    3952        1395 :         GTiffWriteDummyGeokeyDirectory(m_hTIFF);
    3953             : 
    3954        1395 :         GTIF *psGTIF = GTiffDataset::GTIFNew(m_hTIFF);
    3955             : 
    3956             :         // Set according to coordinate system.
    3957        1395 :         if (bHasProjection)
    3958             :         {
    3959        1394 :             if (IsSRSCompatibleOfGeoTIFF(&m_oSRS, m_eGeoTIFFKeysFlavor))
    3960             :             {
    3961        1392 :                 GTIFSetFromOGISDefnEx(psGTIF,
    3962             :                                       OGRSpatialReference::ToHandle(&m_oSRS),
    3963             :                                       m_eGeoTIFFKeysFlavor, m_eGeoTIFFVersion);
    3964             :             }
    3965             :             else
    3966             :             {
    3967           2 :                 GDALPamDataset::SetSpatialRef(&m_oSRS);
    3968             :             }
    3969             :         }
    3970             : 
    3971        1395 :         if (bPixelIsPoint)
    3972             :         {
    3973          17 :             GTIFKeySet(psGTIF, GTRasterTypeGeoKey, TYPE_SHORT, 1,
    3974             :                        RasterPixelIsPoint);
    3975             :         }
    3976             : 
    3977        1395 :         GTIFWriteKeys(psGTIF);
    3978        1395 :         GTIFFree(psGTIF);
    3979             :     }
    3980        5602 : }
    3981             : 
    3982             : /************************************************************************/
    3983             : /*                         AppendMetadataItem()                         */
    3984             : /************************************************************************/
    3985             : 
    3986        3453 : static void AppendMetadataItem(CPLXMLNode **ppsRoot, CPLXMLNode **ppsTail,
    3987             :                                const char *pszKey, const char *pszValue,
    3988             :                                int nBand, const char *pszRole,
    3989             :                                const char *pszDomain)
    3990             : 
    3991             : {
    3992             :     /* -------------------------------------------------------------------- */
    3993             :     /*      Create the Item element, and subcomponents.                     */
    3994             :     /* -------------------------------------------------------------------- */
    3995        3453 :     CPLXMLNode *psItem = CPLCreateXMLNode(nullptr, CXT_Element, "Item");
    3996        3453 :     CPLCreateXMLNode(CPLCreateXMLNode(psItem, CXT_Attribute, "name"), CXT_Text,
    3997             :                      pszKey);
    3998             : 
    3999        3453 :     if (nBand > 0)
    4000             :     {
    4001         843 :         char szBandId[32] = {};
    4002         843 :         snprintf(szBandId, sizeof(szBandId), "%d", nBand - 1);
    4003         843 :         CPLCreateXMLNode(CPLCreateXMLNode(psItem, CXT_Attribute, "sample"),
    4004             :                          CXT_Text, szBandId);
    4005             :     }
    4006             : 
    4007        3453 :     if (pszRole != nullptr)
    4008         347 :         CPLCreateXMLNode(CPLCreateXMLNode(psItem, CXT_Attribute, "role"),
    4009             :                          CXT_Text, pszRole);
    4010             : 
    4011        3453 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
    4012         954 :         CPLCreateXMLNode(CPLCreateXMLNode(psItem, CXT_Attribute, "domain"),
    4013             :                          CXT_Text, pszDomain);
    4014             : 
    4015             :     // Note: this escaping should not normally be done, as the serialization
    4016             :     // of the tree to XML also does it, so we end up width double XML escaping,
    4017             :     // but keep it for backward compatibility.
    4018        3453 :     char *pszEscapedItemValue = CPLEscapeString(pszValue, -1, CPLES_XML);
    4019        3453 :     CPLCreateXMLNode(psItem, CXT_Text, pszEscapedItemValue);
    4020        3453 :     CPLFree(pszEscapedItemValue);
    4021             : 
    4022             :     /* -------------------------------------------------------------------- */
    4023             :     /*      Create root, if missing.                                        */
    4024             :     /* -------------------------------------------------------------------- */
    4025        3453 :     if (*ppsRoot == nullptr)
    4026         616 :         *ppsRoot = CPLCreateXMLNode(nullptr, CXT_Element, "GDALMetadata");
    4027             : 
    4028             :     /* -------------------------------------------------------------------- */
    4029             :     /*      Append item to tail.  We keep track of the tail to avoid        */
    4030             :     /*      O(nsquared) time as the list gets longer.                       */
    4031             :     /* -------------------------------------------------------------------- */
    4032        3453 :     if (*ppsTail == nullptr)
    4033         616 :         CPLAddXMLChild(*ppsRoot, psItem);
    4034             :     else
    4035        2837 :         CPLAddXMLSibling(*ppsTail, psItem);
    4036             : 
    4037        3453 :     *ppsTail = psItem;
    4038        3453 : }
    4039             : 
    4040             : /************************************************************************/
    4041             : /*                         WriteMDMetadata()                            */
    4042             : /************************************************************************/
    4043             : 
    4044      310176 : static void WriteMDMetadata(GDALMultiDomainMetadata *poMDMD, TIFF *hTIFF,
    4045             :                             CPLXMLNode **ppsRoot, CPLXMLNode **ppsTail,
    4046             :                             int nBand, GTiffProfile eProfile)
    4047             : 
    4048             : {
    4049             : 
    4050             :     /* ==================================================================== */
    4051             :     /*      Process each domain.                                            */
    4052             :     /* ==================================================================== */
    4053      310176 :     CSLConstList papszDomainList = poMDMD->GetDomainList();
    4054      318154 :     for (int iDomain = 0; papszDomainList && papszDomainList[iDomain];
    4055             :          ++iDomain)
    4056             :     {
    4057        7978 :         CSLConstList papszMD = poMDMD->GetMetadata(papszDomainList[iDomain]);
    4058        7978 :         bool bIsXML = false;
    4059             : 
    4060        7978 :         if (EQUAL(papszDomainList[iDomain], "IMAGE_STRUCTURE") ||
    4061        2300 :             EQUAL(papszDomainList[iDomain], "DERIVED_SUBDATASETS"))
    4062        5681 :             continue;  // Ignored.
    4063        2297 :         if (EQUAL(papszDomainList[iDomain], "COLOR_PROFILE"))
    4064           3 :             continue;  // Handled elsewhere.
    4065        2294 :         if (EQUAL(papszDomainList[iDomain], MD_DOMAIN_RPC))
    4066           7 :             continue;  // Handled elsewhere.
    4067        2288 :         if (EQUAL(papszDomainList[iDomain], "xml:ESRI") &&
    4068           1 :             CPLTestBool(CPLGetConfigOption("ESRI_XML_PAM", "NO")))
    4069           1 :             continue;  // Handled elsewhere.
    4070        2286 :         if (EQUAL(papszDomainList[iDomain], "xml:XMP"))
    4071           2 :             continue;  // Handled in SetMetadata.
    4072             : 
    4073        2284 :         if (STARTS_WITH_CI(papszDomainList[iDomain], "xml:"))
    4074           2 :             bIsXML = true;
    4075             : 
    4076             :         /* --------------------------------------------------------------------
    4077             :          */
    4078             :         /*      Process each item in this domain. */
    4079             :         /* --------------------------------------------------------------------
    4080             :          */
    4081        6939 :         for (int iItem = 0; papszMD && papszMD[iItem]; ++iItem)
    4082             :         {
    4083        4655 :             const char *pszItemValue = nullptr;
    4084        4655 :             char *pszItemName = nullptr;
    4085             : 
    4086        4655 :             if (bIsXML)
    4087             :             {
    4088           2 :                 pszItemName = CPLStrdup("doc");
    4089           2 :                 pszItemValue = papszMD[iItem];
    4090             :             }
    4091             :             else
    4092             :             {
    4093        4653 :                 pszItemValue = CPLParseNameValue(papszMD[iItem], &pszItemName);
    4094        4653 :                 if (pszItemName == nullptr)
    4095             :                 {
    4096          49 :                     CPLDebug("GTiff", "Invalid metadata item : %s",
    4097          49 :                              papszMD[iItem]);
    4098          49 :                     continue;
    4099             :                 }
    4100             :             }
    4101             : 
    4102             :             /* --------------------------------------------------------------------
    4103             :              */
    4104             :             /*      Convert into XML item or handle as a special TIFF tag. */
    4105             :             /* --------------------------------------------------------------------
    4106             :              */
    4107        4606 :             if (strlen(papszDomainList[iDomain]) == 0 && nBand == 0 &&
    4108        3546 :                 (STARTS_WITH_CI(pszItemName, "TIFFTAG_") ||
    4109        3485 :                  (EQUAL(pszItemName, "GEO_METADATA") &&
    4110        3484 :                   eProfile == GTiffProfile::GDALGEOTIFF) ||
    4111        3484 :                  (EQUAL(pszItemName, "TIFF_RSID") &&
    4112             :                   eProfile == GTiffProfile::GDALGEOTIFF)))
    4113             :             {
    4114          63 :                 if (EQUAL(pszItemName, "TIFFTAG_RESOLUTIONUNIT"))
    4115             :                 {
    4116             :                     // ResolutionUnit can't be 0, which is the default if
    4117             :                     // atoi() fails.  Set to 1=Unknown.
    4118           9 :                     int v = atoi(pszItemValue);
    4119           9 :                     if (!v)
    4120           1 :                         v = RESUNIT_NONE;
    4121           9 :                     TIFFSetField(hTIFF, TIFFTAG_RESOLUTIONUNIT, v);
    4122             :                 }
    4123             :                 else
    4124             :                 {
    4125          54 :                     bool bFoundTag = false;
    4126          54 :                     size_t iTag = 0;  // Used after for.
    4127          54 :                     const auto *pasTIFFTags = GTiffDataset::GetTIFFTags();
    4128         286 :                     for (; pasTIFFTags[iTag].pszTagName; ++iTag)
    4129             :                     {
    4130         286 :                         if (EQUAL(pszItemName, pasTIFFTags[iTag].pszTagName))
    4131             :                         {
    4132          54 :                             bFoundTag = true;
    4133          54 :                             break;
    4134             :                         }
    4135             :                     }
    4136             : 
    4137          54 :                     if (bFoundTag &&
    4138          54 :                         pasTIFFTags[iTag].eType == GTIFFTAGTYPE_STRING)
    4139          33 :                         TIFFSetField(hTIFF, pasTIFFTags[iTag].nTagVal,
    4140             :                                      pszItemValue);
    4141          21 :                     else if (bFoundTag &&
    4142          21 :                              pasTIFFTags[iTag].eType == GTIFFTAGTYPE_FLOAT)
    4143          16 :                         TIFFSetField(hTIFF, pasTIFFTags[iTag].nTagVal,
    4144             :                                      CPLAtof(pszItemValue));
    4145           5 :                     else if (bFoundTag &&
    4146           5 :                              pasTIFFTags[iTag].eType == GTIFFTAGTYPE_SHORT)
    4147           4 :                         TIFFSetField(hTIFF, pasTIFFTags[iTag].nTagVal,
    4148             :                                      atoi(pszItemValue));
    4149           1 :                     else if (bFoundTag && pasTIFFTags[iTag].eType ==
    4150             :                                               GTIFFTAGTYPE_BYTE_STRING)
    4151             :                     {
    4152           1 :                         uint32_t nLen =
    4153           1 :                             static_cast<uint32_t>(strlen(pszItemValue));
    4154           1 :                         if (nLen)
    4155             :                         {
    4156           1 :                             TIFFSetField(hTIFF, pasTIFFTags[iTag].nTagVal, nLen,
    4157             :                                          pszItemValue);
    4158           1 :                         }
    4159             :                     }
    4160             :                     else
    4161           0 :                         CPLError(CE_Warning, CPLE_NotSupported,
    4162             :                                  "%s metadata item is unhandled and "
    4163             :                                  "will not be written",
    4164             :                                  pszItemName);
    4165          63 :                 }
    4166             :             }
    4167        4543 :             else if (nBand == 0 && EQUAL(pszItemName, GDALMD_AREA_OR_POINT))
    4168             :             {
    4169             :                 /* Do nothing, handled elsewhere. */;
    4170             :             }
    4171             :             else
    4172             :             {
    4173        2720 :                 AppendMetadataItem(ppsRoot, ppsTail, pszItemName, pszItemValue,
    4174        2720 :                                    nBand, nullptr, papszDomainList[iDomain]);
    4175             :             }
    4176             : 
    4177        4606 :             CPLFree(pszItemName);
    4178             :         }
    4179             : 
    4180             :         /* --------------------------------------------------------------------
    4181             :          */
    4182             :         /*      Remove TIFFTAG_xxxxxx that are already set but no longer in */
    4183             :         /*      the metadata list (#5619) */
    4184             :         /* --------------------------------------------------------------------
    4185             :          */
    4186        2284 :         if (strlen(papszDomainList[iDomain]) == 0 && nBand == 0)
    4187             :         {
    4188        2087 :             const auto *pasTIFFTags = GTiffDataset::GetTIFFTags();
    4189       31305 :             for (size_t iTag = 0; pasTIFFTags[iTag].pszTagName; ++iTag)
    4190             :             {
    4191       29218 :                 uint32_t nCount = 0;
    4192       29218 :                 char *pszText = nullptr;
    4193       29218 :                 int16_t nVal = 0;
    4194       29218 :                 float fVal = 0.0f;
    4195             :                 const char *pszVal =
    4196       29218 :                     CSLFetchNameValue(papszMD, pasTIFFTags[iTag].pszTagName);
    4197       58373 :                 if (pszVal == nullptr &&
    4198       29155 :                     ((pasTIFFTags[iTag].eType == GTIFFTAGTYPE_STRING &&
    4199       16663 :                       TIFFGetField(hTIFF, pasTIFFTags[iTag].nTagVal,
    4200       29147 :                                    &pszText)) ||
    4201       29147 :                      (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_SHORT &&
    4202        6248 :                       TIFFGetField(hTIFF, pasTIFFTags[iTag].nTagVal, &nVal)) ||
    4203       29144 :                      (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_FLOAT &&
    4204        4158 :                       TIFFGetField(hTIFF, pasTIFFTags[iTag].nTagVal, &fVal)) ||
    4205       29143 :                      (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_BYTE_STRING &&
    4206        2086 :                       TIFFGetField(hTIFF, pasTIFFTags[iTag].nTagVal, &nCount,
    4207             :                                    &pszText))))
    4208             :                 {
    4209          13 :                     TIFFUnsetField(hTIFF, pasTIFFTags[iTag].nTagVal);
    4210             :                 }
    4211             :             }
    4212             :         }
    4213             :     }
    4214      310176 : }
    4215             : 
    4216             : /************************************************************************/
    4217             : /*                           WriteRPC()                                 */
    4218             : /************************************************************************/
    4219             : 
    4220        9615 : void GTiffDataset::WriteRPC(GDALDataset *poSrcDS, TIFF *l_hTIFF,
    4221             :                             int bSrcIsGeoTIFF, GTiffProfile eProfile,
    4222             :                             const char *pszTIFFFilename,
    4223             :                             CSLConstList papszCreationOptions,
    4224             :                             bool bWriteOnlyInPAMIfNeeded)
    4225             : {
    4226             :     /* -------------------------------------------------------------------- */
    4227             :     /*      Handle RPC data written to TIFF RPCCoefficient tag, RPB file,   */
    4228             :     /*      RPCTEXT file or PAM.                                            */
    4229             :     /* -------------------------------------------------------------------- */
    4230        9615 :     char **papszRPCMD = poSrcDS->GetMetadata(MD_DOMAIN_RPC);
    4231        9615 :     if (papszRPCMD != nullptr)
    4232             :     {
    4233          32 :         bool bRPCSerializedOtherWay = false;
    4234             : 
    4235          32 :         if (eProfile == GTiffProfile::GDALGEOTIFF)
    4236             :         {
    4237          20 :             if (!bWriteOnlyInPAMIfNeeded)
    4238          11 :                 GTiffDatasetWriteRPCTag(l_hTIFF, papszRPCMD);
    4239          20 :             bRPCSerializedOtherWay = true;
    4240             :         }
    4241             : 
    4242             :         // Write RPB file if explicitly asked, or if a non GDAL specific
    4243             :         // profile is selected and RPCTXT is not asked.
    4244             :         bool bRPBExplicitlyAsked =
    4245          32 :             CPLFetchBool(papszCreationOptions, "RPB", false);
    4246             :         bool bRPBExplicitlyDenied =
    4247          32 :             !CPLFetchBool(papszCreationOptions, "RPB", true);
    4248          44 :         if ((eProfile != GTiffProfile::GDALGEOTIFF &&
    4249          12 :              !CPLFetchBool(papszCreationOptions, "RPCTXT", false) &&
    4250          44 :              !bRPBExplicitlyDenied) ||
    4251             :             bRPBExplicitlyAsked)
    4252             :         {
    4253           8 :             if (!bWriteOnlyInPAMIfNeeded)
    4254           4 :                 GDALWriteRPBFile(pszTIFFFilename, papszRPCMD);
    4255           8 :             bRPCSerializedOtherWay = true;
    4256             :         }
    4257             : 
    4258          32 :         if (CPLFetchBool(papszCreationOptions, "RPCTXT", false))
    4259             :         {
    4260           2 :             if (!bWriteOnlyInPAMIfNeeded)
    4261           1 :                 GDALWriteRPCTXTFile(pszTIFFFilename, papszRPCMD);
    4262           2 :             bRPCSerializedOtherWay = true;
    4263             :         }
    4264             : 
    4265          32 :         if (!bRPCSerializedOtherWay && bWriteOnlyInPAMIfNeeded && bSrcIsGeoTIFF)
    4266           1 :             cpl::down_cast<GTiffDataset *>(poSrcDS)
    4267           1 :                 ->GDALPamDataset::SetMetadata(papszRPCMD, MD_DOMAIN_RPC);
    4268             :     }
    4269        9615 : }
    4270             : 
    4271             : /************************************************************************/
    4272             : /*                           WriteMetadata()                            */
    4273             : /************************************************************************/
    4274             : 
    4275        7621 : bool GTiffDataset::WriteMetadata(GDALDataset *poSrcDS, TIFF *l_hTIFF,
    4276             :                                  bool bSrcIsGeoTIFF, GTiffProfile eProfile,
    4277             :                                  const char *pszTIFFFilename,
    4278             :                                  CSLConstList papszCreationOptions,
    4279             :                                  bool bExcludeRPBandIMGFileWriting)
    4280             : 
    4281             : {
    4282             :     /* -------------------------------------------------------------------- */
    4283             :     /*      Convert all the remaining metadata into a simple XML            */
    4284             :     /*      format.                                                         */
    4285             :     /* -------------------------------------------------------------------- */
    4286        7621 :     CPLXMLNode *psRoot = nullptr;
    4287        7621 :     CPLXMLNode *psTail = nullptr;
    4288             : 
    4289             :     const char *pszCopySrcMDD =
    4290        7621 :         CSLFetchNameValueDef(papszCreationOptions, "COPY_SRC_MDD", "AUTO");
    4291             :     char **papszSrcMDD =
    4292        7621 :         CSLFetchNameValueMultiple(papszCreationOptions, "SRC_MDD");
    4293             : 
    4294        7621 :     if (bSrcIsGeoTIFF)
    4295             :     {
    4296        5605 :         GTiffDataset *poSrcDSGTiff = cpl::down_cast<GTiffDataset *>(poSrcDS);
    4297        5605 :         assert(poSrcDSGTiff);
    4298        5605 :         WriteMDMetadata(&poSrcDSGTiff->m_oGTiffMDMD, l_hTIFF, &psRoot, &psTail,
    4299             :                         0, eProfile);
    4300             :     }
    4301             :     else
    4302             :     {
    4303        2016 :         if (EQUAL(pszCopySrcMDD, "AUTO") || CPLTestBool(pszCopySrcMDD) ||
    4304             :             papszSrcMDD)
    4305             :         {
    4306        4026 :             GDALMultiDomainMetadata l_oMDMD;
    4307        2013 :             CSLConstList papszMD = poSrcDS->GetMetadata();
    4308        2017 :             if (CSLCount(papszMD) > 0 &&
    4309           4 :                 (!papszSrcMDD || CSLFindString(papszSrcMDD, "") >= 0 ||
    4310           2 :                  CSLFindString(papszSrcMDD, "_DEFAULT_") >= 0))
    4311             :             {
    4312        1546 :                 l_oMDMD.SetMetadata(papszMD);
    4313             :             }
    4314             : 
    4315        2013 :             if ((!EQUAL(pszCopySrcMDD, "AUTO") && CPLTestBool(pszCopySrcMDD)) ||
    4316             :                 papszSrcMDD)
    4317             :             {
    4318           9 :                 char **papszDomainList = poSrcDS->GetMetadataDomainList();
    4319          39 :                 for (CSLConstList papszIter = papszDomainList;
    4320          39 :                      papszIter && *papszIter; ++papszIter)
    4321             :                 {
    4322          30 :                     const char *pszDomain = *papszIter;
    4323          46 :                     if (pszDomain[0] != 0 &&
    4324          16 :                         (!papszSrcMDD ||
    4325          16 :                          CSLFindString(papszSrcMDD, pszDomain) >= 0))
    4326             :                     {
    4327          12 :                         l_oMDMD.SetMetadata(poSrcDS->GetMetadata(pszDomain),
    4328             :                                             pszDomain);
    4329             :                     }
    4330             :                 }
    4331           9 :                 CSLDestroy(papszDomainList);
    4332             :             }
    4333             : 
    4334        2013 :             WriteMDMetadata(&l_oMDMD, l_hTIFF, &psRoot, &psTail, 0, eProfile);
    4335             :         }
    4336             :     }
    4337             : 
    4338        7621 :     if (!bExcludeRPBandIMGFileWriting)
    4339             :     {
    4340        7615 :         WriteRPC(poSrcDS, l_hTIFF, bSrcIsGeoTIFF, eProfile, pszTIFFFilename,
    4341             :                  papszCreationOptions);
    4342             : 
    4343             :         /* --------------------------------------------------------------------
    4344             :          */
    4345             :         /*      Handle metadata data written to an IMD file. */
    4346             :         /* --------------------------------------------------------------------
    4347             :          */
    4348        7615 :         char **papszIMDMD = poSrcDS->GetMetadata(MD_DOMAIN_IMD);
    4349        7615 :         if (papszIMDMD != nullptr)
    4350             :         {
    4351          20 :             GDALWriteIMDFile(pszTIFFFilename, papszIMDMD);
    4352             :         }
    4353             :     }
    4354             : 
    4355        7621 :     uint16_t nPhotometric = 0;
    4356        7621 :     if (!TIFFGetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, &(nPhotometric)))
    4357           1 :         nPhotometric = PHOTOMETRIC_MINISBLACK;
    4358             : 
    4359        7621 :     const bool bStandardColorInterp = GTIFFIsStandardColorInterpretation(
    4360             :         GDALDataset::ToHandle(poSrcDS), nPhotometric, papszCreationOptions);
    4361             : 
    4362             :     /* -------------------------------------------------------------------- */
    4363             :     /*      We also need to address band specific metadata, and special     */
    4364             :     /*      "role" metadata.                                                */
    4365             :     /* -------------------------------------------------------------------- */
    4366      314951 :     for (int nBand = 1; nBand <= poSrcDS->GetRasterCount(); ++nBand)
    4367             :     {
    4368      307330 :         GDALRasterBand *poBand = poSrcDS->GetRasterBand(nBand);
    4369             : 
    4370      307330 :         if (bSrcIsGeoTIFF)
    4371             :         {
    4372             :             GTiffRasterBand *poSrcBandGTiff =
    4373      302467 :                 cpl::down_cast<GTiffRasterBand *>(poBand);
    4374      302467 :             assert(poSrcBandGTiff);
    4375      302467 :             WriteMDMetadata(&poSrcBandGTiff->m_oGTiffMDMD, l_hTIFF, &psRoot,
    4376             :                             &psTail, nBand, eProfile);
    4377             :         }
    4378             :         else
    4379             :         {
    4380        9726 :             GDALMultiDomainMetadata l_oMDMD;
    4381        4863 :             bool bOMDMDSet = false;
    4382             : 
    4383        4863 :             if (EQUAL(pszCopySrcMDD, "AUTO") && !papszSrcMDD)
    4384             :             {
    4385       14553 :                 for (const char *pszDomain : {"", "IMAGERY"})
    4386             :                 {
    4387        9702 :                     if (CSLConstList papszMD = poBand->GetMetadata(pszDomain))
    4388             :                     {
    4389          89 :                         if (papszMD[0])
    4390             :                         {
    4391          89 :                             bOMDMDSet = true;
    4392          89 :                             l_oMDMD.SetMetadata(papszMD, pszDomain);
    4393             :                         }
    4394             :                     }
    4395        4851 :                 }
    4396             :             }
    4397          12 :             else if (CPLTestBool(pszCopySrcMDD) || papszSrcMDD)
    4398             :             {
    4399           9 :                 char **papszDomainList = poBand->GetMetadataDomainList();
    4400           3 :                 for (const char *pszDomain :
    4401          15 :                      cpl::Iterate(CSLConstList(papszDomainList)))
    4402             :                 {
    4403           9 :                     if (pszDomain[0] != 0 &&
    4404           5 :                         !EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
    4405           2 :                         (!papszSrcMDD ||
    4406           2 :                          CSLFindString(papszSrcMDD, pszDomain) >= 0))
    4407             :                     {
    4408           2 :                         bOMDMDSet = true;
    4409           2 :                         l_oMDMD.SetMetadata(poBand->GetMetadata(pszDomain),
    4410             :                                             pszDomain);
    4411             :                     }
    4412             :                 }
    4413           9 :                 CSLDestroy(papszDomainList);
    4414             :             }
    4415             : 
    4416        4863 :             if (bOMDMDSet)
    4417             :             {
    4418          91 :                 WriteMDMetadata(&l_oMDMD, l_hTIFF, &psRoot, &psTail, nBand,
    4419             :                                 eProfile);
    4420             :             }
    4421             :         }
    4422             : 
    4423      307330 :         const double dfOffset = poBand->GetOffset();
    4424      307330 :         const double dfScale = poBand->GetScale();
    4425      307330 :         bool bGeoTIFFScaleOffsetInZ = false;
    4426      307330 :         GDALGeoTransform gt;
    4427             :         // Check if we have already encoded scale/offset in the GeoTIFF tags
    4428      313062 :         if (poSrcDS->GetGeoTransform(gt) == CE_None && gt[2] == 0.0 &&
    4429        5720 :             gt[4] == 0.0 && gt[5] < 0.0 && poSrcDS->GetSpatialRef() &&
    4430      313069 :             poSrcDS->GetSpatialRef()->IsVertical() &&
    4431           7 :             poSrcDS->GetRasterCount() == 1)
    4432             :         {
    4433           7 :             bGeoTIFFScaleOffsetInZ = true;
    4434             :         }
    4435             : 
    4436      307330 :         if ((dfOffset != 0.0 || dfScale != 1.0) && !bGeoTIFFScaleOffsetInZ)
    4437             :         {
    4438          25 :             char szValue[128] = {};
    4439             : 
    4440          25 :             CPLsnprintf(szValue, sizeof(szValue), "%.17g", dfOffset);
    4441          25 :             AppendMetadataItem(&psRoot, &psTail, "OFFSET", szValue, nBand,
    4442             :                                "offset", "");
    4443          25 :             CPLsnprintf(szValue, sizeof(szValue), "%.17g", dfScale);
    4444          25 :             AppendMetadataItem(&psRoot, &psTail, "SCALE", szValue, nBand,
    4445             :                                "scale", "");
    4446             :         }
    4447             : 
    4448      307330 :         const char *pszUnitType = poBand->GetUnitType();
    4449      307330 :         if (pszUnitType != nullptr && pszUnitType[0] != '\0')
    4450             :         {
    4451          37 :             bool bWriteUnit = true;
    4452          37 :             auto poSRS = poSrcDS->GetSpatialRef();
    4453          37 :             if (poSRS && poSRS->IsCompound())
    4454             :             {
    4455           2 :                 const char *pszVertUnit = nullptr;
    4456           2 :                 poSRS->GetTargetLinearUnits("COMPD_CS|VERT_CS", &pszVertUnit);
    4457           2 :                 if (pszVertUnit && EQUAL(pszVertUnit, pszUnitType))
    4458             :                 {
    4459           2 :                     bWriteUnit = false;
    4460             :                 }
    4461             :             }
    4462          37 :             if (bWriteUnit)
    4463             :             {
    4464          35 :                 AppendMetadataItem(&psRoot, &psTail, "UNITTYPE", pszUnitType,
    4465             :                                    nBand, "unittype", "");
    4466             :             }
    4467             :         }
    4468             : 
    4469      307330 :         if (strlen(poBand->GetDescription()) > 0)
    4470             :         {
    4471          15 :             AppendMetadataItem(&psRoot, &psTail, "DESCRIPTION",
    4472          15 :                                poBand->GetDescription(), nBand, "description",
    4473             :                                "");
    4474             :         }
    4475             : 
    4476      307544 :         if (!bStandardColorInterp &&
    4477         214 :             !(nBand <= 3 && EQUAL(CSLFetchNameValueDef(papszCreationOptions,
    4478             :                                                        "PHOTOMETRIC", ""),
    4479             :                                   "RGB")))
    4480             :         {
    4481         247 :             AppendMetadataItem(&psRoot, &psTail, "COLORINTERP",
    4482             :                                GDALGetColorInterpretationName(
    4483         247 :                                    poBand->GetColorInterpretation()),
    4484             :                                nBand, "colorinterp", "");
    4485             :         }
    4486             :     }
    4487             : 
    4488        7621 :     CSLDestroy(papszSrcMDD);
    4489             : 
    4490             :     const char *pszTilingSchemeName =
    4491        7621 :         CSLFetchNameValue(papszCreationOptions, "@TILING_SCHEME_NAME");
    4492        7621 :     if (pszTilingSchemeName)
    4493             :     {
    4494          23 :         AppendMetadataItem(&psRoot, &psTail, "NAME", pszTilingSchemeName, 0,
    4495             :                            nullptr, "TILING_SCHEME");
    4496             : 
    4497          23 :         const char *pszZoomLevel = CSLFetchNameValue(
    4498             :             papszCreationOptions, "@TILING_SCHEME_ZOOM_LEVEL");
    4499          23 :         if (pszZoomLevel)
    4500             :         {
    4501          23 :             AppendMetadataItem(&psRoot, &psTail, "ZOOM_LEVEL", pszZoomLevel, 0,
    4502             :                                nullptr, "TILING_SCHEME");
    4503             :         }
    4504             : 
    4505          23 :         const char *pszAlignedLevels = CSLFetchNameValue(
    4506             :             papszCreationOptions, "@TILING_SCHEME_ALIGNED_LEVELS");
    4507          23 :         if (pszAlignedLevels)
    4508             :         {
    4509           4 :             AppendMetadataItem(&psRoot, &psTail, "ALIGNED_LEVELS",
    4510             :                                pszAlignedLevels, 0, nullptr, "TILING_SCHEME");
    4511             :         }
    4512             :     }
    4513             : 
    4514             :     /* -------------------------------------------------------------------- */
    4515             :     /*      Write information about some codecs.                            */
    4516             :     /* -------------------------------------------------------------------- */
    4517        7621 :     if (CPLTestBool(
    4518             :             CPLGetConfigOption("GTIFF_WRITE_IMAGE_STRUCTURE_METADATA", "YES")))
    4519             :     {
    4520             :         const char *pszTileInterleave =
    4521        7616 :             CSLFetchNameValue(papszCreationOptions, "@TILE_INTERLEAVE");
    4522        7616 :         if (pszTileInterleave && CPLTestBool(pszTileInterleave))
    4523             :         {
    4524           7 :             AppendMetadataItem(&psRoot, &psTail, "INTERLEAVE", "TILE", 0,
    4525             :                                nullptr, "IMAGE_STRUCTURE");
    4526             :         }
    4527             : 
    4528             :         const char *pszCompress =
    4529        7616 :             CSLFetchNameValue(papszCreationOptions, "COMPRESS");
    4530        7616 :         if (pszCompress && EQUAL(pszCompress, "WEBP"))
    4531             :         {
    4532          31 :             if (GTiffGetWebPLossless(papszCreationOptions))
    4533             :             {
    4534           6 :                 AppendMetadataItem(&psRoot, &psTail,
    4535             :                                    "COMPRESSION_REVERSIBILITY", "LOSSLESS", 0,
    4536             :                                    nullptr, "IMAGE_STRUCTURE");
    4537             :             }
    4538             :             else
    4539             :             {
    4540          25 :                 AppendMetadataItem(
    4541             :                     &psRoot, &psTail, "WEBP_LEVEL",
    4542          25 :                     CPLSPrintf("%d", GTiffGetWebPLevel(papszCreationOptions)),
    4543             :                     0, nullptr, "IMAGE_STRUCTURE");
    4544             :             }
    4545             :         }
    4546        7585 :         else if (pszCompress && STARTS_WITH_CI(pszCompress, "LERC"))
    4547             :         {
    4548             :             const double dfMaxZError =
    4549          97 :                 GTiffGetLERCMaxZError(papszCreationOptions);
    4550             :             const double dfMaxZErrorOverview =
    4551          97 :                 GTiffGetLERCMaxZErrorOverview(papszCreationOptions);
    4552          97 :             if (dfMaxZError == 0.0 && dfMaxZErrorOverview == 0.0)
    4553             :             {
    4554          83 :                 AppendMetadataItem(&psRoot, &psTail,
    4555             :                                    "COMPRESSION_REVERSIBILITY", "LOSSLESS", 0,
    4556             :                                    nullptr, "IMAGE_STRUCTURE");
    4557             :             }
    4558             :             else
    4559             :             {
    4560          14 :                 AppendMetadataItem(&psRoot, &psTail, "MAX_Z_ERROR",
    4561             :                                    CSLFetchNameValueDef(papszCreationOptions,
    4562             :                                                         "MAX_Z_ERROR", ""),
    4563             :                                    0, nullptr, "IMAGE_STRUCTURE");
    4564          14 :                 if (dfMaxZError != dfMaxZErrorOverview)
    4565             :                 {
    4566           3 :                     AppendMetadataItem(
    4567             :                         &psRoot, &psTail, "MAX_Z_ERROR_OVERVIEW",
    4568             :                         CSLFetchNameValueDef(papszCreationOptions,
    4569             :                                              "MAX_Z_ERROR_OVERVIEW", ""),
    4570             :                         0, nullptr, "IMAGE_STRUCTURE");
    4571             :                 }
    4572          97 :             }
    4573             :         }
    4574             : #if HAVE_JXL
    4575        7488 :         else if (pszCompress && EQUAL(pszCompress, "JXL"))
    4576             :         {
    4577          98 :             float fDistance = 0.0f;
    4578          98 :             if (GTiffGetJXLLossless(papszCreationOptions))
    4579             :             {
    4580          80 :                 AppendMetadataItem(&psRoot, &psTail,
    4581             :                                    "COMPRESSION_REVERSIBILITY", "LOSSLESS", 0,
    4582             :                                    nullptr, "IMAGE_STRUCTURE");
    4583             :             }
    4584             :             else
    4585             :             {
    4586          18 :                 fDistance = GTiffGetJXLDistance(papszCreationOptions);
    4587          18 :                 AppendMetadataItem(&psRoot, &psTail, "JXL_DISTANCE",
    4588             :                                    CPLSPrintf("%f", fDistance), 0, nullptr,
    4589             :                                    "IMAGE_STRUCTURE");
    4590             :             }
    4591             :             const float fAlphaDistance =
    4592          98 :                 GTiffGetJXLAlphaDistance(papszCreationOptions);
    4593          98 :             if (fAlphaDistance >= 0.0f && fAlphaDistance != fDistance)
    4594             :             {
    4595           2 :                 AppendMetadataItem(&psRoot, &psTail, "JXL_ALPHA_DISTANCE",
    4596             :                                    CPLSPrintf("%f", fAlphaDistance), 0, nullptr,
    4597             :                                    "IMAGE_STRUCTURE");
    4598             :             }
    4599          98 :             AppendMetadataItem(
    4600             :                 &psRoot, &psTail, "JXL_EFFORT",
    4601             :                 CPLSPrintf("%d", GTiffGetJXLEffort(papszCreationOptions)), 0,
    4602             :                 nullptr, "IMAGE_STRUCTURE");
    4603             :         }
    4604             : #endif
    4605             :     }
    4606             : 
    4607             :     /* -------------------------------------------------------------------- */
    4608             :     /*      Write out the generic XML metadata if there is any.             */
    4609             :     /* -------------------------------------------------------------------- */
    4610        7621 :     if (psRoot != nullptr)
    4611             :     {
    4612         616 :         bool bRet = true;
    4613             : 
    4614         616 :         if (eProfile == GTiffProfile::GDALGEOTIFF)
    4615             :         {
    4616         599 :             char *pszXML_MD = CPLSerializeXMLTree(psRoot);
    4617         599 :             TIFFSetField(l_hTIFF, TIFFTAG_GDAL_METADATA, pszXML_MD);
    4618         599 :             CPLFree(pszXML_MD);
    4619             :         }
    4620             :         else
    4621             :         {
    4622          17 :             if (bSrcIsGeoTIFF)
    4623          11 :                 cpl::down_cast<GTiffDataset *>(poSrcDS)->PushMetadataToPam();
    4624             :             else
    4625           6 :                 bRet = false;
    4626             :         }
    4627             : 
    4628         616 :         CPLDestroyXMLNode(psRoot);
    4629             : 
    4630         616 :         return bRet;
    4631             :     }
    4632             : 
    4633             :     // If we have no more metadata but it existed before,
    4634             :     // remove the GDAL_METADATA tag.
    4635        7005 :     if (eProfile == GTiffProfile::GDALGEOTIFF)
    4636             :     {
    4637        6981 :         char *pszText = nullptr;
    4638        6981 :         if (TIFFGetField(l_hTIFF, TIFFTAG_GDAL_METADATA, &pszText))
    4639             :         {
    4640           6 :             TIFFUnsetField(l_hTIFF, TIFFTAG_GDAL_METADATA);
    4641             :         }
    4642             :     }
    4643             : 
    4644        7005 :     return true;
    4645             : }
    4646             : 
    4647             : /************************************************************************/
    4648             : /*                         PushMetadataToPam()                          */
    4649             : /*                                                                      */
    4650             : /*      When producing a strict profile TIFF or if our aggregate        */
    4651             : /*      metadata is too big for a single tiff tag we may end up         */
    4652             : /*      needing to write it via the PAM mechanisms.  This method        */
    4653             : /*      copies all the appropriate metadata into the PAM level          */
    4654             : /*      metadata object but with special care to avoid copying          */
    4655             : /*      metadata handled in other ways in TIFF format.                  */
    4656             : /************************************************************************/
    4657             : 
    4658          20 : void GTiffDataset::PushMetadataToPam()
    4659             : 
    4660             : {
    4661          20 :     if (GetPamFlags() & GPF_DISABLED)
    4662           0 :         return;
    4663             : 
    4664          20 :     const bool bStandardColorInterp = GTIFFIsStandardColorInterpretation(
    4665          20 :         GDALDataset::ToHandle(this), m_nPhotometric, m_papszCreationOptions);
    4666             : 
    4667          66 :     for (int nBand = 0; nBand <= GetRasterCount(); ++nBand)
    4668             :     {
    4669          46 :         GDALMultiDomainMetadata *poSrcMDMD = nullptr;
    4670          46 :         GTiffRasterBand *poBand = nullptr;
    4671             : 
    4672          46 :         if (nBand == 0)
    4673             :         {
    4674          20 :             poSrcMDMD = &(this->m_oGTiffMDMD);
    4675             :         }
    4676             :         else
    4677             :         {
    4678          26 :             poBand = cpl::down_cast<GTiffRasterBand *>(GetRasterBand(nBand));
    4679          26 :             poSrcMDMD = &(poBand->m_oGTiffMDMD);
    4680             :         }
    4681             : 
    4682             :         /* --------------------------------------------------------------------
    4683             :          */
    4684             :         /*      Loop over the available domains. */
    4685             :         /* --------------------------------------------------------------------
    4686             :          */
    4687          46 :         CSLConstList papszDomainList = poSrcMDMD->GetDomainList();
    4688          96 :         for (int iDomain = 0; papszDomainList && papszDomainList[iDomain];
    4689             :              ++iDomain)
    4690             :         {
    4691          50 :             char **papszMD = poSrcMDMD->GetMetadata(papszDomainList[iDomain]);
    4692             : 
    4693          50 :             if (EQUAL(papszDomainList[iDomain], MD_DOMAIN_RPC) ||
    4694          50 :                 EQUAL(papszDomainList[iDomain], MD_DOMAIN_IMD) ||
    4695          50 :                 EQUAL(papszDomainList[iDomain], "_temporary_") ||
    4696          50 :                 EQUAL(papszDomainList[iDomain], "IMAGE_STRUCTURE") ||
    4697          30 :                 EQUAL(papszDomainList[iDomain], "COLOR_PROFILE"))
    4698          20 :                 continue;
    4699             : 
    4700          30 :             papszMD = CSLDuplicate(papszMD);
    4701             : 
    4702         105 :             for (int i = CSLCount(papszMD) - 1; i >= 0; --i)
    4703             :             {
    4704          75 :                 if (STARTS_WITH_CI(papszMD[i], "TIFFTAG_") ||
    4705          75 :                     EQUALN(papszMD[i], GDALMD_AREA_OR_POINT,
    4706             :                            strlen(GDALMD_AREA_OR_POINT)))
    4707           4 :                     papszMD = CSLRemoveStrings(papszMD, i, 1, nullptr);
    4708             :             }
    4709             : 
    4710          30 :             if (nBand == 0)
    4711          16 :                 GDALPamDataset::SetMetadata(papszMD, papszDomainList[iDomain]);
    4712             :             else
    4713          14 :                 poBand->GDALPamRasterBand::SetMetadata(
    4714          14 :                     papszMD, papszDomainList[iDomain]);
    4715             : 
    4716          30 :             CSLDestroy(papszMD);
    4717             :         }
    4718             : 
    4719             :         /* --------------------------------------------------------------------
    4720             :          */
    4721             :         /*      Handle some "special domain" stuff. */
    4722             :         /* --------------------------------------------------------------------
    4723             :          */
    4724          46 :         if (poBand != nullptr)
    4725             :         {
    4726          26 :             poBand->GDALPamRasterBand::SetOffset(poBand->GetOffset());
    4727          26 :             poBand->GDALPamRasterBand::SetScale(poBand->GetScale());
    4728          26 :             poBand->GDALPamRasterBand::SetUnitType(poBand->GetUnitType());
    4729          26 :             poBand->GDALPamRasterBand::SetDescription(poBand->GetDescription());
    4730          26 :             if (!bStandardColorInterp)
    4731             :             {
    4732           3 :                 poBand->GDALPamRasterBand::SetColorInterpretation(
    4733           3 :                     poBand->GetColorInterpretation());
    4734             :             }
    4735             :         }
    4736             :     }
    4737          20 :     MarkPamDirty();
    4738             : }
    4739             : 
    4740             : /************************************************************************/
    4741             : /*                         WriteNoDataValue()                           */
    4742             : /************************************************************************/
    4743             : 
    4744         459 : void GTiffDataset::WriteNoDataValue(TIFF *hTIFF, double dfNoData)
    4745             : 
    4746             : {
    4747         918 :     CPLString osVal(GTiffFormatGDALNoDataTagValue(dfNoData));
    4748         459 :     TIFFSetField(hTIFF, TIFFTAG_GDAL_NODATA, osVal.c_str());
    4749         459 : }
    4750             : 
    4751           2 : void GTiffDataset::WriteNoDataValue(TIFF *hTIFF, int64_t nNoData)
    4752             : 
    4753             : {
    4754           2 :     TIFFSetField(hTIFF, TIFFTAG_GDAL_NODATA,
    4755             :                  CPLSPrintf(CPL_FRMT_GIB, static_cast<GIntBig>(nNoData)));
    4756           2 : }
    4757             : 
    4758           2 : void GTiffDataset::WriteNoDataValue(TIFF *hTIFF, uint64_t nNoData)
    4759             : 
    4760             : {
    4761           2 :     TIFFSetField(hTIFF, TIFFTAG_GDAL_NODATA,
    4762             :                  CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nNoData)));
    4763           2 : }
    4764             : 
    4765             : /************************************************************************/
    4766             : /*                         UnsetNoDataValue()                           */
    4767             : /************************************************************************/
    4768             : 
    4769          14 : void GTiffDataset::UnsetNoDataValue(TIFF *l_hTIFF)
    4770             : 
    4771             : {
    4772          14 :     TIFFUnsetField(l_hTIFF, TIFFTAG_GDAL_NODATA);
    4773          14 : }
    4774             : 
    4775             : /************************************************************************/
    4776             : /*                             SaveICCProfile()                         */
    4777             : /*                                                                      */
    4778             : /*      Save ICC Profile or colorimetric data into file                 */
    4779             : /* pDS:                                                                 */
    4780             : /*      Dataset that contains the metadata with the ICC or colorimetric */
    4781             : /*      data. If this argument is specified, all other arguments are    */
    4782             : /*      ignored. Set them to NULL or 0.                                 */
    4783             : /* hTIFF:                                                               */
    4784             : /*      Pointer to TIFF handle. Only needed if pDS is NULL or           */
    4785             : /*      pDS->m_hTIFF is NULL.                                             */
    4786             : /* papszParamList:                                                       */
    4787             : /*      Options containing the ICC profile or colorimetric metadata.    */
    4788             : /*      Ignored if pDS is not NULL.                                     */
    4789             : /* nBitsPerSample:                                                      */
    4790             : /*      Bits per sample. Ignored if pDS is not NULL.                    */
    4791             : /************************************************************************/
    4792             : 
    4793        9433 : void GTiffDataset::SaveICCProfile(GTiffDataset *pDS, TIFF *l_hTIFF,
    4794             :                                   char **papszParamList,
    4795             :                                   uint32_t l_nBitsPerSample)
    4796             : {
    4797        9433 :     if ((pDS != nullptr) && (pDS->eAccess != GA_Update))
    4798           0 :         return;
    4799             : 
    4800        9433 :     if (l_hTIFF == nullptr)
    4801             :     {
    4802           2 :         if (pDS == nullptr)
    4803           0 :             return;
    4804             : 
    4805           2 :         l_hTIFF = pDS->m_hTIFF;
    4806           2 :         if (l_hTIFF == nullptr)
    4807           0 :             return;
    4808             :     }
    4809             : 
    4810        9433 :     if ((papszParamList == nullptr) && (pDS == nullptr))
    4811        4651 :         return;
    4812             : 
    4813             :     const char *pszICCProfile =
    4814             :         (pDS != nullptr)
    4815        4782 :             ? pDS->GetMetadataItem("SOURCE_ICC_PROFILE", "COLOR_PROFILE")
    4816        4780 :             : CSLFetchNameValue(papszParamList, "SOURCE_ICC_PROFILE");
    4817        4782 :     if (pszICCProfile != nullptr)
    4818             :     {
    4819           8 :         char *pEmbedBuffer = CPLStrdup(pszICCProfile);
    4820             :         int32_t nEmbedLen =
    4821           8 :             CPLBase64DecodeInPlace(reinterpret_cast<GByte *>(pEmbedBuffer));
    4822             : 
    4823           8 :         TIFFSetField(l_hTIFF, TIFFTAG_ICCPROFILE, nEmbedLen, pEmbedBuffer);
    4824             : 
    4825           8 :         CPLFree(pEmbedBuffer);
    4826             :     }
    4827             :     else
    4828             :     {
    4829             :         // Output colorimetric data.
    4830        4774 :         float pCHR[6] = {};     // Primaries.
    4831        4774 :         uint16_t pTXR[6] = {};  // Transfer range.
    4832        4774 :         const char *pszCHRNames[] = {"SOURCE_PRIMARIES_RED",
    4833             :                                      "SOURCE_PRIMARIES_GREEN",
    4834             :                                      "SOURCE_PRIMARIES_BLUE"};
    4835        4774 :         const char *pszTXRNames[] = {"TIFFTAG_TRANSFERRANGE_BLACK",
    4836             :                                      "TIFFTAG_TRANSFERRANGE_WHITE"};
    4837             : 
    4838             :         // Output chromacities.
    4839        4774 :         bool bOutputCHR = true;
    4840        4789 :         for (int i = 0; i < 3 && bOutputCHR; ++i)
    4841             :         {
    4842             :             const char *pszColorProfile =
    4843             :                 (pDS != nullptr)
    4844        4784 :                     ? pDS->GetMetadataItem(pszCHRNames[i], "COLOR_PROFILE")
    4845        4781 :                     : CSLFetchNameValue(papszParamList, pszCHRNames[i]);
    4846        4784 :             if (pszColorProfile == nullptr)
    4847             :             {
    4848        4769 :                 bOutputCHR = false;
    4849        4769 :                 break;
    4850             :             }
    4851             : 
    4852             :             const CPLStringList aosTokens(CSLTokenizeString2(
    4853             :                 pszColorProfile, ",",
    4854             :                 CSLT_ALLOWEMPTYTOKENS | CSLT_STRIPLEADSPACES |
    4855          15 :                     CSLT_STRIPENDSPACES));
    4856             : 
    4857          15 :             if (aosTokens.size() != 3)
    4858             :             {
    4859           0 :                 bOutputCHR = false;
    4860           0 :                 break;
    4861             :             }
    4862             : 
    4863          60 :             for (int j = 0; j < 3; ++j)
    4864             :             {
    4865          45 :                 float v = static_cast<float>(CPLAtof(aosTokens[j]));
    4866             : 
    4867          45 :                 if (j == 2)
    4868             :                 {
    4869             :                     // Last term of xyY color must be 1.0.
    4870          15 :                     if (v != 1.0)
    4871             :                     {
    4872           0 :                         bOutputCHR = false;
    4873           0 :                         break;
    4874             :                     }
    4875             :                 }
    4876             :                 else
    4877             :                 {
    4878          30 :                     pCHR[i * 2 + j] = v;
    4879             :                 }
    4880             :             }
    4881             :         }
    4882             : 
    4883        4774 :         if (bOutputCHR)
    4884             :         {
    4885           5 :             TIFFSetField(l_hTIFF, TIFFTAG_PRIMARYCHROMATICITIES, pCHR);
    4886             :         }
    4887             : 
    4888             :         // Output whitepoint.
    4889             :         const char *pszSourceWhitePoint =
    4890             :             (pDS != nullptr)
    4891        4774 :                 ? pDS->GetMetadataItem("SOURCE_WHITEPOINT", "COLOR_PROFILE")
    4892        4773 :                 : CSLFetchNameValue(papszParamList, "SOURCE_WHITEPOINT");
    4893        4774 :         if (pszSourceWhitePoint != nullptr)
    4894             :         {
    4895             :             const CPLStringList aosTokens(CSLTokenizeString2(
    4896             :                 pszSourceWhitePoint, ",",
    4897             :                 CSLT_ALLOWEMPTYTOKENS | CSLT_STRIPLEADSPACES |
    4898          10 :                     CSLT_STRIPENDSPACES));
    4899             : 
    4900           5 :             bool bOutputWhitepoint = true;
    4901           5 :             float pWP[2] = {0.0f, 0.0f};  // Whitepoint
    4902           5 :             if (aosTokens.size() != 3)
    4903             :             {
    4904           0 :                 bOutputWhitepoint = false;
    4905             :             }
    4906             :             else
    4907             :             {
    4908          20 :                 for (int j = 0; j < 3; ++j)
    4909             :                 {
    4910          15 :                     const float v = static_cast<float>(CPLAtof(aosTokens[j]));
    4911             : 
    4912          15 :                     if (j == 2)
    4913             :                     {
    4914             :                         // Last term of xyY color must be 1.0.
    4915           5 :                         if (v != 1.0)
    4916             :                         {
    4917           0 :                             bOutputWhitepoint = false;
    4918           0 :                             break;
    4919             :                         }
    4920             :                     }
    4921             :                     else
    4922             :                     {
    4923          10 :                         pWP[j] = v;
    4924             :                     }
    4925             :                 }
    4926             :             }
    4927             : 
    4928           5 :             if (bOutputWhitepoint)
    4929             :             {
    4930           5 :                 TIFFSetField(l_hTIFF, TIFFTAG_WHITEPOINT, pWP);
    4931             :             }
    4932             :         }
    4933             : 
    4934             :         // Set transfer function metadata.
    4935             :         char const *pszTFRed =
    4936             :             (pDS != nullptr)
    4937        4774 :                 ? pDS->GetMetadataItem("TIFFTAG_TRANSFERFUNCTION_RED",
    4938             :                                        "COLOR_PROFILE")
    4939        4773 :                 : CSLFetchNameValue(papszParamList,
    4940        4774 :                                     "TIFFTAG_TRANSFERFUNCTION_RED");
    4941             : 
    4942             :         char const *pszTFGreen =
    4943             :             (pDS != nullptr)
    4944        4774 :                 ? pDS->GetMetadataItem("TIFFTAG_TRANSFERFUNCTION_GREEN",
    4945             :                                        "COLOR_PROFILE")
    4946        4773 :                 : CSLFetchNameValue(papszParamList,
    4947        4774 :                                     "TIFFTAG_TRANSFERFUNCTION_GREEN");
    4948             : 
    4949             :         char const *pszTFBlue =
    4950             :             (pDS != nullptr)
    4951        4774 :                 ? pDS->GetMetadataItem("TIFFTAG_TRANSFERFUNCTION_BLUE",
    4952             :                                        "COLOR_PROFILE")
    4953        4773 :                 : CSLFetchNameValue(papszParamList,
    4954        4774 :                                     "TIFFTAG_TRANSFERFUNCTION_BLUE");
    4955             : 
    4956        4774 :         if ((pszTFRed != nullptr) && (pszTFGreen != nullptr) &&
    4957             :             (pszTFBlue != nullptr))
    4958             :         {
    4959             :             // Get length of table.
    4960           4 :             const int nTransferFunctionLength =
    4961           4 :                 1 << ((pDS != nullptr) ? pDS->m_nBitsPerSample
    4962             :                                        : l_nBitsPerSample);
    4963             : 
    4964             :             const CPLStringList aosTokensRed(CSLTokenizeString2(
    4965             :                 pszTFRed, ",",
    4966             :                 CSLT_ALLOWEMPTYTOKENS | CSLT_STRIPLEADSPACES |
    4967           8 :                     CSLT_STRIPENDSPACES));
    4968             :             const CPLStringList aosTokensGreen(CSLTokenizeString2(
    4969             :                 pszTFGreen, ",",
    4970             :                 CSLT_ALLOWEMPTYTOKENS | CSLT_STRIPLEADSPACES |
    4971           8 :                     CSLT_STRIPENDSPACES));
    4972             :             const CPLStringList aosTokensBlue(CSLTokenizeString2(
    4973             :                 pszTFBlue, ",",
    4974             :                 CSLT_ALLOWEMPTYTOKENS | CSLT_STRIPLEADSPACES |
    4975           8 :                     CSLT_STRIPENDSPACES));
    4976             : 
    4977           4 :             if ((aosTokensRed.size() == nTransferFunctionLength) &&
    4978           8 :                 (aosTokensGreen.size() == nTransferFunctionLength) &&
    4979           4 :                 (aosTokensBlue.size() == nTransferFunctionLength))
    4980             :             {
    4981             :                 std::vector<uint16_t> anTransferFuncRed(
    4982           8 :                     nTransferFunctionLength);
    4983             :                 std::vector<uint16_t> anTransferFuncGreen(
    4984           8 :                     nTransferFunctionLength);
    4985             :                 std::vector<uint16_t> anTransferFuncBlue(
    4986           8 :                     nTransferFunctionLength);
    4987             : 
    4988             :                 // Convert our table in string format into int16_t format.
    4989        1028 :                 for (int i = 0; i < nTransferFunctionLength; ++i)
    4990             :                 {
    4991        2048 :                     anTransferFuncRed[i] =
    4992        1024 :                         static_cast<uint16_t>(atoi(aosTokensRed[i]));
    4993        2048 :                     anTransferFuncGreen[i] =
    4994        1024 :                         static_cast<uint16_t>(atoi(aosTokensGreen[i]));
    4995        1024 :                     anTransferFuncBlue[i] =
    4996        1024 :                         static_cast<uint16_t>(atoi(aosTokensBlue[i]));
    4997             :                 }
    4998             : 
    4999           4 :                 TIFFSetField(
    5000             :                     l_hTIFF, TIFFTAG_TRANSFERFUNCTION, anTransferFuncRed.data(),
    5001             :                     anTransferFuncGreen.data(), anTransferFuncBlue.data());
    5002             :             }
    5003             :         }
    5004             : 
    5005             :         // Output transfer range.
    5006        4774 :         bool bOutputTransferRange = true;
    5007        4774 :         for (int i = 0; (i < 2) && bOutputTransferRange; ++i)
    5008             :         {
    5009             :             const char *pszTXRVal =
    5010             :                 (pDS != nullptr)
    5011        4774 :                     ? pDS->GetMetadataItem(pszTXRNames[i], "COLOR_PROFILE")
    5012        4773 :                     : CSLFetchNameValue(papszParamList, pszTXRNames[i]);
    5013        4774 :             if (pszTXRVal == nullptr)
    5014             :             {
    5015        4774 :                 bOutputTransferRange = false;
    5016        4774 :                 break;
    5017             :             }
    5018             : 
    5019             :             const CPLStringList aosTokens(CSLTokenizeString2(
    5020             :                 pszTXRVal, ",",
    5021             :                 CSLT_ALLOWEMPTYTOKENS | CSLT_STRIPLEADSPACES |
    5022           0 :                     CSLT_STRIPENDSPACES));
    5023             : 
    5024           0 :             if (aosTokens.size() != 3)
    5025             :             {
    5026           0 :                 bOutputTransferRange = false;
    5027           0 :                 break;
    5028             :             }
    5029             : 
    5030           0 :             for (int j = 0; j < 3; ++j)
    5031             :             {
    5032           0 :                 pTXR[i + j * 2] = static_cast<uint16_t>(atoi(aosTokens[j]));
    5033             :             }
    5034             :         }
    5035             : 
    5036        4774 :         if (bOutputTransferRange)
    5037             :         {
    5038           0 :             const int TIFFTAG_TRANSFERRANGE = 0x0156;
    5039           0 :             TIFFSetField(l_hTIFF, TIFFTAG_TRANSFERRANGE, pTXR);
    5040             :         }
    5041             :     }
    5042             : }
    5043             : 
    5044       16957 : static signed char GTiffGetLZMAPreset(char **papszOptions)
    5045             : {
    5046       16957 :     int nLZMAPreset = -1;
    5047       16957 :     const char *pszValue = CSLFetchNameValue(papszOptions, "LZMA_PRESET");
    5048       16957 :     if (pszValue != nullptr)
    5049             :     {
    5050          20 :         nLZMAPreset = atoi(pszValue);
    5051          20 :         if (!(nLZMAPreset >= 0 && nLZMAPreset <= 9))
    5052             :         {
    5053           0 :             CPLError(CE_Warning, CPLE_IllegalArg,
    5054             :                      "LZMA_PRESET=%s value not recognised, ignoring.",
    5055             :                      pszValue);
    5056           0 :             nLZMAPreset = -1;
    5057             :         }
    5058             :     }
    5059       16957 :     return static_cast<signed char>(nLZMAPreset);
    5060             : }
    5061             : 
    5062       16957 : static signed char GTiffGetZSTDPreset(char **papszOptions)
    5063             : {
    5064       16957 :     int nZSTDLevel = -1;
    5065       16957 :     const char *pszValue = CSLFetchNameValue(papszOptions, "ZSTD_LEVEL");
    5066       16957 :     if (pszValue != nullptr)
    5067             :     {
    5068          24 :         nZSTDLevel = atoi(pszValue);
    5069          24 :         if (!(nZSTDLevel >= 1 && nZSTDLevel <= 22))
    5070             :         {
    5071           0 :             CPLError(CE_Warning, CPLE_IllegalArg,
    5072             :                      "ZSTD_LEVEL=%s value not recognised, ignoring.", pszValue);
    5073           0 :             nZSTDLevel = -1;
    5074             :         }
    5075             :     }
    5076       16957 :     return static_cast<signed char>(nZSTDLevel);
    5077             : }
    5078             : 
    5079       16957 : static signed char GTiffGetZLevel(char **papszOptions)
    5080             : {
    5081       16957 :     int nZLevel = -1;
    5082       16957 :     const char *pszValue = CSLFetchNameValue(papszOptions, "ZLEVEL");
    5083       16957 :     if (pszValue != nullptr)
    5084             :     {
    5085          44 :         nZLevel = atoi(pszValue);
    5086             : #ifdef TIFFTAG_DEFLATE_SUBCODEC
    5087          44 :         constexpr int nMaxLevel = 12;
    5088             : #ifndef LIBDEFLATE_SUPPORT
    5089             :         if (nZLevel > 9 && nZLevel <= nMaxLevel)
    5090             :         {
    5091             :             CPLDebug("GTiff",
    5092             :                      "ZLEVEL=%d not supported in a non-libdeflate enabled "
    5093             :                      "libtiff build. Capping to 9",
    5094             :                      nZLevel);
    5095             :             nZLevel = 9;
    5096             :         }
    5097             : #endif
    5098             : #else
    5099             :         constexpr int nMaxLevel = 9;
    5100             : #endif
    5101          44 :         if (nZLevel < 1 || nZLevel > nMaxLevel)
    5102             :         {
    5103           0 :             CPLError(CE_Warning, CPLE_IllegalArg,
    5104             :                      "ZLEVEL=%s value not recognised, ignoring.", pszValue);
    5105           0 :             nZLevel = -1;
    5106             :         }
    5107             :     }
    5108       16957 :     return static_cast<signed char>(nZLevel);
    5109             : }
    5110             : 
    5111       16957 : static signed char GTiffGetJpegQuality(char **papszOptions)
    5112             : {
    5113       16957 :     int nJpegQuality = -1;
    5114       16957 :     const char *pszValue = CSLFetchNameValue(papszOptions, "JPEG_QUALITY");
    5115       16957 :     if (pszValue != nullptr)
    5116             :     {
    5117        1939 :         nJpegQuality = atoi(pszValue);
    5118        1939 :         if (nJpegQuality < 1 || nJpegQuality > 100)
    5119             :         {
    5120           0 :             CPLError(CE_Warning, CPLE_IllegalArg,
    5121             :                      "JPEG_QUALITY=%s value not recognised, ignoring.",
    5122             :                      pszValue);
    5123           0 :             nJpegQuality = -1;
    5124             :         }
    5125             :     }
    5126       16957 :     return static_cast<signed char>(nJpegQuality);
    5127             : }
    5128             : 
    5129       16957 : static signed char GTiffGetJpegTablesMode(char **papszOptions)
    5130             : {
    5131       16957 :     return static_cast<signed char>(atoi(
    5132             :         CSLFetchNameValueDef(papszOptions, "JPEGTABLESMODE",
    5133       16957 :                              CPLSPrintf("%d", knGTIFFJpegTablesModeDefault))));
    5134             : }
    5135             : 
    5136             : /************************************************************************/
    5137             : /*                        GetDiscardLsbOption()                         */
    5138             : /************************************************************************/
    5139             : 
    5140        7465 : static GTiffDataset::MaskOffset *GetDiscardLsbOption(TIFF *hTIFF,
    5141             :                                                      char **papszOptions)
    5142             : {
    5143        7465 :     const char *pszBits = CSLFetchNameValue(papszOptions, "DISCARD_LSB");
    5144        7465 :     if (pszBits == nullptr)
    5145        7343 :         return nullptr;
    5146             : 
    5147         122 :     uint16_t nPhotometric = 0;
    5148         122 :     TIFFGetFieldDefaulted(hTIFF, TIFFTAG_PHOTOMETRIC, &nPhotometric);
    5149             : 
    5150         122 :     uint16_t nBitsPerSample = 0;
    5151         122 :     if (!TIFFGetField(hTIFF, TIFFTAG_BITSPERSAMPLE, &nBitsPerSample))
    5152           0 :         nBitsPerSample = 1;
    5153             : 
    5154         122 :     uint16_t nSamplesPerPixel = 0;
    5155         122 :     if (!TIFFGetField(hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSamplesPerPixel))
    5156           0 :         nSamplesPerPixel = 1;
    5157             : 
    5158         122 :     uint16_t nSampleFormat = 0;
    5159         122 :     if (!TIFFGetField(hTIFF, TIFFTAG_SAMPLEFORMAT, &nSampleFormat))
    5160           0 :         nSampleFormat = SAMPLEFORMAT_UINT;
    5161             : 
    5162         122 :     if (nPhotometric == PHOTOMETRIC_PALETTE)
    5163             :     {
    5164           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    5165             :                  "DISCARD_LSB ignored on a paletted image");
    5166           1 :         return nullptr;
    5167             :     }
    5168         121 :     if (!(nBitsPerSample == 8 || nBitsPerSample == 16 || nBitsPerSample == 32 ||
    5169          13 :           nBitsPerSample == 64))
    5170             :     {
    5171           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    5172             :                  "DISCARD_LSB ignored on non 8, 16, 32 or 64 bits images");
    5173           1 :         return nullptr;
    5174             :     }
    5175             : 
    5176         240 :     const CPLStringList aosTokens(CSLTokenizeString2(pszBits, ",", 0));
    5177         120 :     const int nTokens = aosTokens.size();
    5178         120 :     GTiffDataset::MaskOffset *panMaskOffsetLsb = nullptr;
    5179         120 :     if (nTokens == 1 || nTokens == nSamplesPerPixel)
    5180             :     {
    5181             :         panMaskOffsetLsb = static_cast<GTiffDataset::MaskOffset *>(
    5182         119 :             CPLCalloc(nSamplesPerPixel, sizeof(GTiffDataset::MaskOffset)));
    5183         374 :         for (int i = 0; i < nSamplesPerPixel; ++i)
    5184             :         {
    5185         255 :             const int nBits = atoi(aosTokens[nTokens == 1 ? 0 : i]);
    5186         510 :             const int nMaxBits = (nSampleFormat == SAMPLEFORMAT_IEEEFP)
    5187         510 :                                      ? ((nBitsPerSample == 16)   ? 11 - 1
    5188          78 :                                         : (nBitsPerSample == 32) ? 23 - 1
    5189          26 :                                         : (nBitsPerSample == 64) ? 53 - 1
    5190             :                                                                  : 0)
    5191         203 :                                  : nSampleFormat == SAMPLEFORMAT_INT
    5192         203 :                                      ? nBitsPerSample - 2
    5193         119 :                                      : nBitsPerSample - 1;
    5194             : 
    5195         255 :             if (nBits < 0 || nBits > nMaxBits)
    5196             :             {
    5197           0 :                 CPLError(
    5198             :                     CE_Warning, CPLE_AppDefined,
    5199             :                     "DISCARD_LSB ignored: values should be in [0,%d] range",
    5200             :                     nMaxBits);
    5201           0 :                 VSIFree(panMaskOffsetLsb);
    5202           0 :                 return nullptr;
    5203             :             }
    5204         255 :             panMaskOffsetLsb[i].nMask =
    5205         255 :                 ~((static_cast<uint64_t>(1) << nBits) - 1);
    5206         255 :             if (nBits > 1)
    5207             :             {
    5208         249 :                 panMaskOffsetLsb[i].nRoundUpBitTest = static_cast<uint64_t>(1)
    5209         249 :                                                       << (nBits - 1);
    5210             :             }
    5211         119 :         }
    5212             :     }
    5213             :     else
    5214             :     {
    5215           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    5216             :                  "DISCARD_LSB ignored: wrong number of components");
    5217             :     }
    5218         120 :     return panMaskOffsetLsb;
    5219             : }
    5220             : 
    5221        7465 : void GTiffDataset::GetDiscardLsbOption(char **papszOptions)
    5222             : {
    5223        7465 :     m_panMaskOffsetLsb = ::GetDiscardLsbOption(m_hTIFF, papszOptions);
    5224        7465 : }
    5225             : 
    5226             : /************************************************************************/
    5227             : /*                             GetProfile()                             */
    5228             : /************************************************************************/
    5229             : 
    5230       17008 : static GTiffProfile GetProfile(const char *pszProfile)
    5231             : {
    5232       17008 :     GTiffProfile eProfile = GTiffProfile::GDALGEOTIFF;
    5233       17008 :     if (pszProfile != nullptr)
    5234             :     {
    5235          70 :         if (EQUAL(pszProfile, szPROFILE_BASELINE))
    5236          50 :             eProfile = GTiffProfile::BASELINE;
    5237          20 :         else if (EQUAL(pszProfile, szPROFILE_GeoTIFF))
    5238          18 :             eProfile = GTiffProfile::GEOTIFF;
    5239           2 :         else if (!EQUAL(pszProfile, szPROFILE_GDALGeoTIFF))
    5240             :         {
    5241           0 :             CPLError(CE_Warning, CPLE_NotSupported,
    5242             :                      "Unsupported value for PROFILE: %s", pszProfile);
    5243             :         }
    5244             :     }
    5245       17008 :     return eProfile;
    5246             : }
    5247             : 
    5248             : /************************************************************************/
    5249             : /*                            GTiffCreate()                             */
    5250             : /*                                                                      */
    5251             : /*      Shared functionality between GTiffDataset::Create() and         */
    5252             : /*      GTiffCreateCopy() for creating TIFF file based on a set of      */
    5253             : /*      options and a configuration.                                    */
    5254             : /************************************************************************/
    5255             : 
    5256        9511 : TIFF *GTiffDataset::CreateLL(const char *pszFilename, int nXSize, int nYSize,
    5257             :                              int l_nBands, GDALDataType eType,
    5258             :                              double dfExtraSpaceForOverviews,
    5259             :                              int nColorTableMultiplier, char **papszParamList,
    5260             :                              VSILFILE **pfpL, CPLString &l_osTmpFilename,
    5261             :                              bool bCreateCopy, bool &bTileInterleavingOut)
    5262             : 
    5263             : {
    5264        9511 :     bTileInterleavingOut = false;
    5265             : 
    5266        9511 :     GTiffOneTimeInit();
    5267             : 
    5268             :     /* -------------------------------------------------------------------- */
    5269             :     /*      Blow on a few errors.                                           */
    5270             :     /* -------------------------------------------------------------------- */
    5271        9511 :     if (nXSize < 1 || nYSize < 1 || l_nBands < 1)
    5272             :     {
    5273           1 :         ReportError(
    5274             :             pszFilename, CE_Failure, CPLE_AppDefined,
    5275             :             "Attempt to create %dx%dx%d TIFF file, but width, height and bands"
    5276             :             "must be positive.",
    5277             :             nXSize, nYSize, l_nBands);
    5278             : 
    5279           1 :         return nullptr;
    5280             :     }
    5281             : 
    5282        9510 :     if (l_nBands > 65535)
    5283             :     {
    5284           1 :         ReportError(pszFilename, CE_Failure, CPLE_AppDefined,
    5285             :                     "Attempt to create %dx%dx%d TIFF file, but bands "
    5286             :                     "must be lesser or equal to 65535.",
    5287             :                     nXSize, nYSize, l_nBands);
    5288             : 
    5289           1 :         return nullptr;
    5290             :     }
    5291             : 
    5292             :     /* -------------------------------------------------------------------- */
    5293             :     /*      Setup values based on options.                                  */
    5294             :     /* -------------------------------------------------------------------- */
    5295             :     const GTiffProfile eProfile =
    5296        9509 :         GetProfile(CSLFetchNameValue(papszParamList, "PROFILE"));
    5297             : 
    5298        9509 :     const bool bTiled = CPLFetchBool(papszParamList, "TILED", false);
    5299             : 
    5300        9509 :     int l_nBlockXSize = 0;
    5301        9509 :     if (const char *pszValue = CSLFetchNameValue(papszParamList, "BLOCKXSIZE"))
    5302             :     {
    5303         378 :         l_nBlockXSize = atoi(pszValue);
    5304         378 :         if (l_nBlockXSize < 0)
    5305             :         {
    5306           0 :             ReportError(pszFilename, CE_Failure, CPLE_IllegalArg,
    5307             :                         "Invalid value for BLOCKXSIZE");
    5308           0 :             return nullptr;
    5309             :         }
    5310         378 :         if (!bTiled)
    5311             :         {
    5312          10 :             ReportError(pszFilename, CE_Warning, CPLE_IllegalArg,
    5313             :                         "BLOCKXSIZE can only be used with TILED=YES");
    5314             :         }
    5315         368 :         else if (l_nBlockXSize % 16 != 0)
    5316             :         {
    5317           1 :             ReportError(pszFilename, CE_Failure, CPLE_IllegalArg,
    5318             :                         "BLOCKXSIZE must be a multiple of 16");
    5319           1 :             return nullptr;
    5320             :         }
    5321             :     }
    5322             : 
    5323        9508 :     int l_nBlockYSize = 0;
    5324        9508 :     if (const char *pszValue = CSLFetchNameValue(papszParamList, "BLOCKYSIZE"))
    5325             :     {
    5326        2490 :         l_nBlockYSize = atoi(pszValue);
    5327        2490 :         if (l_nBlockYSize < 0)
    5328             :         {
    5329           0 :             ReportError(pszFilename, CE_Failure, CPLE_IllegalArg,
    5330             :                         "Invalid value for BLOCKYSIZE");
    5331           0 :             return nullptr;
    5332             :         }
    5333        2490 :         if (bTiled && (l_nBlockYSize % 16 != 0))
    5334             :         {
    5335           2 :             ReportError(pszFilename, CE_Failure, CPLE_IllegalArg,
    5336             :                         "BLOCKYSIZE must be a multiple of 16");
    5337           2 :             return nullptr;
    5338             :         }
    5339             :     }
    5340             : 
    5341        9506 :     if (bTiled)
    5342             :     {
    5343         691 :         if (l_nBlockXSize == 0)
    5344         325 :             l_nBlockXSize = 256;
    5345             : 
    5346         691 :         if (l_nBlockYSize == 0)
    5347         325 :             l_nBlockYSize = 256;
    5348             :     }
    5349             : 
    5350        9506 :     int nPlanar = 0;
    5351             : 
    5352             :     // Hidden @TILE_INTERLEAVE=YES parameter used by the COG driver
    5353        9506 :     if (bCreateCopy && CPLTestBool(CSLFetchNameValueDef(
    5354             :                            papszParamList, "@TILE_INTERLEAVE", "NO")))
    5355             :     {
    5356           7 :         bTileInterleavingOut = true;
    5357           7 :         nPlanar = PLANARCONFIG_SEPARATE;
    5358             :     }
    5359             :     else
    5360             :     {
    5361        9499 :         if (const char *pszValue =
    5362        9499 :                 CSLFetchNameValue(papszParamList, "INTERLEAVE"))
    5363             :         {
    5364        1510 :             if (EQUAL(pszValue, "PIXEL"))
    5365         364 :                 nPlanar = PLANARCONFIG_CONTIG;
    5366        1146 :             else if (EQUAL(pszValue, "BAND"))
    5367             :             {
    5368        1145 :                 nPlanar = PLANARCONFIG_SEPARATE;
    5369             :             }
    5370           1 :             else if (EQUAL(pszValue, "BAND"))
    5371             :             {
    5372           0 :                 nPlanar = PLANARCONFIG_SEPARATE;
    5373             :             }
    5374             :             else
    5375             :             {
    5376           1 :                 ReportError(
    5377             :                     pszFilename, CE_Failure, CPLE_IllegalArg,
    5378             :                     "INTERLEAVE=%s unsupported, value must be PIXEL or BAND.",
    5379             :                     pszValue);
    5380           1 :                 return nullptr;
    5381             :             }
    5382             :         }
    5383             :         else
    5384             :         {
    5385        7989 :             nPlanar = PLANARCONFIG_CONTIG;
    5386             :         }
    5387             :     }
    5388             : 
    5389        9505 :     int l_nCompression = COMPRESSION_NONE;
    5390        9505 :     if (const char *pszValue = CSLFetchNameValue(papszParamList, "COMPRESS"))
    5391             :     {
    5392        3241 :         l_nCompression = GTIFFGetCompressionMethod(pszValue, "COMPRESS");
    5393        3241 :         if (l_nCompression < 0)
    5394           0 :             return nullptr;
    5395             :     }
    5396             : 
    5397        9505 :     constexpr int JPEG_MAX_DIMENSION = 65500;  // Defined in jpeglib.h
    5398        9505 :     constexpr int WEBP_MAX_DIMENSION = 16383;
    5399             : 
    5400             :     const struct
    5401             :     {
    5402             :         int nCodecID;
    5403             :         const char *pszCodecName;
    5404             :         int nMaxDim;
    5405        9505 :     } asLimitations[] = {
    5406             :         {COMPRESSION_JPEG, "JPEG", JPEG_MAX_DIMENSION},
    5407             :         {COMPRESSION_WEBP, "WEBP", WEBP_MAX_DIMENSION},
    5408             :     };
    5409             : 
    5410       28503 :     for (const auto &sLimitation : asLimitations)
    5411             :     {
    5412       19006 :         if (l_nCompression == sLimitation.nCodecID && !bTiled &&
    5413        2078 :             nXSize > sLimitation.nMaxDim)
    5414             :         {
    5415           2 :             ReportError(
    5416             :                 pszFilename, CE_Failure, CPLE_IllegalArg,
    5417             :                 "COMPRESS=%s is only compatible of un-tiled images whose "
    5418             :                 "width is lesser or equal to %d pixels. "
    5419             :                 "To overcome this limitation, set the TILED=YES creation "
    5420             :                 "option.",
    5421           2 :                 sLimitation.pszCodecName, sLimitation.nMaxDim);
    5422           2 :             return nullptr;
    5423             :         }
    5424       19004 :         else if (l_nCompression == sLimitation.nCodecID && bTiled &&
    5425          52 :                  l_nBlockXSize > sLimitation.nMaxDim)
    5426             :         {
    5427           2 :             ReportError(pszFilename, CE_Failure, CPLE_IllegalArg,
    5428             :                         "COMPRESS=%s is only compatible of tiled images whose "
    5429             :                         "BLOCKXSIZE is lesser or equal to %d pixels.",
    5430           2 :                         sLimitation.pszCodecName, sLimitation.nMaxDim);
    5431           2 :             return nullptr;
    5432             :         }
    5433       19002 :         else if (l_nCompression == sLimitation.nCodecID &&
    5434        2126 :                  l_nBlockYSize > sLimitation.nMaxDim)
    5435             :         {
    5436           4 :             ReportError(pszFilename, CE_Failure, CPLE_IllegalArg,
    5437             :                         "COMPRESS=%s is only compatible of images whose "
    5438             :                         "BLOCKYSIZE is lesser or equal to %d pixels. "
    5439             :                         "To overcome this limitation, set the TILED=YES "
    5440             :                         "creation option",
    5441           4 :                         sLimitation.pszCodecName, sLimitation.nMaxDim);
    5442           4 :             return nullptr;
    5443             :         }
    5444             :     }
    5445             : 
    5446             :     /* -------------------------------------------------------------------- */
    5447             :     /*      How many bits per sample?  We have a special case if NBITS      */
    5448             :     /*      specified for GDT_Byte, GDT_UInt16, GDT_UInt32.                 */
    5449             :     /* -------------------------------------------------------------------- */
    5450        9497 :     int l_nBitsPerSample = GDALGetDataTypeSizeBits(eType);
    5451        9497 :     if (CSLFetchNameValue(papszParamList, "NBITS") != nullptr)
    5452             :     {
    5453        1751 :         int nMinBits = 0;
    5454        1751 :         int nMaxBits = 0;
    5455        1751 :         l_nBitsPerSample = atoi(CSLFetchNameValue(papszParamList, "NBITS"));
    5456        1751 :         if (eType == GDT_Byte)
    5457             :         {
    5458         531 :             nMinBits = 1;
    5459         531 :             nMaxBits = 8;
    5460             :         }
    5461        1220 :         else if (eType == GDT_UInt16)
    5462             :         {
    5463        1202 :             nMinBits = 9;
    5464        1202 :             nMaxBits = 16;
    5465             :         }
    5466          18 :         else if (eType == GDT_UInt32)
    5467             :         {
    5468          14 :             nMinBits = 17;
    5469          14 :             nMaxBits = 32;
    5470             :         }
    5471           4 :         else if (eType == GDT_Float32)
    5472             :         {
    5473           4 :             if (l_nBitsPerSample != 16 && l_nBitsPerSample != 32)
    5474             :             {
    5475           1 :                 ReportError(pszFilename, CE_Warning, CPLE_NotSupported,
    5476             :                             "Only NBITS=16 is supported for data type Float32");
    5477           1 :                 l_nBitsPerSample = GDALGetDataTypeSizeBits(eType);
    5478             :             }
    5479             :         }
    5480             :         else
    5481             :         {
    5482           0 :             ReportError(pszFilename, CE_Warning, CPLE_NotSupported,
    5483             :                         "NBITS is not supported for data type %s",
    5484             :                         GDALGetDataTypeName(eType));
    5485           0 :             l_nBitsPerSample = GDALGetDataTypeSizeBits(eType);
    5486             :         }
    5487             : 
    5488        1751 :         if (nMinBits != 0)
    5489             :         {
    5490        1747 :             if (l_nBitsPerSample < nMinBits)
    5491             :             {
    5492           2 :                 ReportError(
    5493             :                     pszFilename, CE_Warning, CPLE_AppDefined,
    5494             :                     "NBITS=%d is invalid for data type %s. Using NBITS=%d",
    5495             :                     l_nBitsPerSample, GDALGetDataTypeName(eType), nMinBits);
    5496           2 :                 l_nBitsPerSample = nMinBits;
    5497             :             }
    5498        1745 :             else if (l_nBitsPerSample > nMaxBits)
    5499             :             {
    5500           3 :                 ReportError(
    5501             :                     pszFilename, CE_Warning, CPLE_AppDefined,
    5502             :                     "NBITS=%d is invalid for data type %s. Using NBITS=%d",
    5503             :                     l_nBitsPerSample, GDALGetDataTypeName(eType), nMaxBits);
    5504           3 :                 l_nBitsPerSample = nMaxBits;
    5505             :             }
    5506             :         }
    5507             :     }
    5508             : 
    5509             : #ifdef HAVE_JXL
    5510        9497 :     if ((l_nCompression == COMPRESSION_JXL ||
    5511         103 :          l_nCompression == COMPRESSION_JXL_DNG_1_7) &&
    5512         102 :         eType != GDT_Float16 && eType != GDT_Float32)
    5513             :     {
    5514             :         // Reflects tif_jxl's GetJXLDataType()
    5515          82 :         if (eType != GDT_Byte && eType != GDT_UInt16)
    5516             :         {
    5517           1 :             ReportError(pszFilename, CE_Failure, CPLE_NotSupported,
    5518             :                         "Data type %s not supported for JXL compression. Only "
    5519             :                         "Byte, UInt16, Float16, Float32 are supported",
    5520             :                         GDALGetDataTypeName(eType));
    5521           2 :             return nullptr;
    5522             :         }
    5523             : 
    5524             :         const struct
    5525             :         {
    5526             :             GDALDataType eDT;
    5527             :             int nBitsPerSample;
    5528          81 :         } asSupportedDTBitsPerSample[] = {
    5529             :             {GDT_Byte, 8},
    5530             :             {GDT_UInt16, 16},
    5531             :         };
    5532             : 
    5533         241 :         for (const auto &sSupportedDTBitsPerSample : asSupportedDTBitsPerSample)
    5534             :         {
    5535         161 :             if (eType == sSupportedDTBitsPerSample.eDT &&
    5536          81 :                 l_nBitsPerSample != sSupportedDTBitsPerSample.nBitsPerSample)
    5537             :             {
    5538           1 :                 ReportError(
    5539             :                     pszFilename, CE_Failure, CPLE_NotSupported,
    5540             :                     "Bits per sample=%d not supported for JXL compression. "
    5541             :                     "Only %d is supported for %s data type.",
    5542           1 :                     l_nBitsPerSample, sSupportedDTBitsPerSample.nBitsPerSample,
    5543             :                     GDALGetDataTypeName(eType));
    5544           1 :                 return nullptr;
    5545             :             }
    5546             :         }
    5547             :     }
    5548             : #endif
    5549             : 
    5550        9495 :     int nPredictor = PREDICTOR_NONE;
    5551        9495 :     const char *pszPredictor = CSLFetchNameValue(papszParamList, "PREDICTOR");
    5552        9495 :     if (pszPredictor)
    5553             :     {
    5554          29 :         nPredictor = atoi(pszPredictor);
    5555             :     }
    5556             : 
    5557        9495 :     if (nPredictor != PREDICTOR_NONE &&
    5558          16 :         l_nCompression != COMPRESSION_ADOBE_DEFLATE &&
    5559           2 :         l_nCompression != COMPRESSION_LZW &&
    5560           2 :         l_nCompression != COMPRESSION_LZMA &&
    5561             :         l_nCompression != COMPRESSION_ZSTD)
    5562             :     {
    5563           1 :         ReportError(pszFilename, CE_Warning, CPLE_NotSupported,
    5564             :                     "PREDICTOR option is ignored for COMPRESS=%s. "
    5565             :                     "Only valid for DEFLATE, LZW, LZMA or ZSTD",
    5566             :                     CSLFetchNameValueDef(papszParamList, "COMPRESS", "NONE"));
    5567             :     }
    5568             : 
    5569             :     // Do early checks as libtiff will only error out when starting to write.
    5570        9522 :     else if (nPredictor != PREDICTOR_NONE &&
    5571          28 :              CPLTestBool(
    5572             :                  CPLGetConfigOption("GDAL_GTIFF_PREDICTOR_CHECKS", "YES")))
    5573             :     {
    5574             : #if (TIFFLIB_VERSION > 20210416) || defined(INTERNAL_LIBTIFF)
    5575             : #define HAVE_PREDICTOR_2_FOR_64BIT
    5576             : #endif
    5577          28 :         if (nPredictor == 2)
    5578             :         {
    5579          23 :             if (l_nBitsPerSample != 8 && l_nBitsPerSample != 16 &&
    5580             :                 l_nBitsPerSample != 32
    5581             : #ifdef HAVE_PREDICTOR_2_FOR_64BIT
    5582           2 :                 && l_nBitsPerSample != 64
    5583             : #endif
    5584             :             )
    5585             :             {
    5586             : #if !defined(HAVE_PREDICTOR_2_FOR_64BIT)
    5587             :                 if (l_nBitsPerSample == 64)
    5588             :                 {
    5589             :                     ReportError(pszFilename, CE_Failure, CPLE_AppDefined,
    5590             :                                 "PREDICTOR=2 is supported on 64 bit samples "
    5591             :                                 "starting with libtiff > 4.3.0.");
    5592             :                 }
    5593             :                 else
    5594             : #endif
    5595             :                 {
    5596           2 :                     const int nBITSHint = (l_nBitsPerSample < 8)    ? 8
    5597           1 :                                           : (l_nBitsPerSample < 16) ? 16
    5598           0 :                                           : (l_nBitsPerSample < 32) ? 32
    5599             :                                                                     : 64;
    5600           1 :                     ReportError(pszFilename, CE_Failure, CPLE_AppDefined,
    5601             : #ifdef HAVE_PREDICTOR_2_FOR_64BIT
    5602             :                                 "PREDICTOR=2 is only supported with 8/16/32/64 "
    5603             :                                 "bit samples. You can specify the NBITS=%d "
    5604             :                                 "creation option to promote to the closest "
    5605             :                                 "supported bits per sample value.",
    5606             : #else
    5607             :                                 "PREDICTOR=2 is only supported with 8/16/32 "
    5608             :                                 "bit samples. You can specify the NBITS=%d "
    5609             :                                 "creation option to promote to the closest "
    5610             :                                 "supported bits per sample value.",
    5611             : #endif
    5612             :                                 nBITSHint);
    5613             :                 }
    5614           1 :                 return nullptr;
    5615             :             }
    5616             :         }
    5617           5 :         else if (nPredictor == 3)
    5618             :         {
    5619           4 :             if (eType != GDT_Float32 && eType != GDT_Float64)
    5620             :             {
    5621           1 :                 ReportError(
    5622             :                     pszFilename, CE_Failure, CPLE_AppDefined,
    5623             :                     "PREDICTOR=3 is only supported with Float32 or Float64.");
    5624           1 :                 return nullptr;
    5625             :             }
    5626             :         }
    5627             :         else
    5628             :         {
    5629           1 :             ReportError(pszFilename, CE_Failure, CPLE_AppDefined,
    5630             :                         "PREDICTOR=%s is not supported.", pszPredictor);
    5631           1 :             return nullptr;
    5632             :         }
    5633             :     }
    5634             : 
    5635        9492 :     const int l_nZLevel = GTiffGetZLevel(papszParamList);
    5636        9492 :     const int l_nLZMAPreset = GTiffGetLZMAPreset(papszParamList);
    5637        9492 :     const int l_nZSTDLevel = GTiffGetZSTDPreset(papszParamList);
    5638        9492 :     const int l_nWebPLevel = GTiffGetWebPLevel(papszParamList);
    5639        9492 :     const bool l_bWebPLossless = GTiffGetWebPLossless(papszParamList);
    5640        9492 :     const int l_nJpegQuality = GTiffGetJpegQuality(papszParamList);
    5641        9492 :     const int l_nJpegTablesMode = GTiffGetJpegTablesMode(papszParamList);
    5642        9492 :     const double l_dfMaxZError = GTiffGetLERCMaxZError(papszParamList);
    5643             : #if HAVE_JXL
    5644        9492 :     const bool l_bJXLLossless = GTiffGetJXLLossless(papszParamList);
    5645        9492 :     const uint32_t l_nJXLEffort = GTiffGetJXLEffort(papszParamList);
    5646        9492 :     const float l_fJXLDistance = GTiffGetJXLDistance(papszParamList);
    5647        9492 :     const float l_fJXLAlphaDistance = GTiffGetJXLAlphaDistance(papszParamList);
    5648             : #endif
    5649             :     /* -------------------------------------------------------------------- */
    5650             :     /*      Streaming related code                                          */
    5651             :     /* -------------------------------------------------------------------- */
    5652       18984 :     const CPLString osOriFilename(pszFilename);
    5653       18984 :     bool bStreaming = strcmp(pszFilename, "/vsistdout/") == 0 ||
    5654        9492 :                       CPLFetchBool(papszParamList, "STREAMABLE_OUTPUT", false);
    5655             : #ifdef S_ISFIFO
    5656        9492 :     if (!bStreaming)
    5657             :     {
    5658             :         VSIStatBufL sStat;
    5659        9480 :         if (VSIStatExL(pszFilename, &sStat,
    5660       10360 :                        VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0 &&
    5661         880 :             S_ISFIFO(sStat.st_mode))
    5662             :         {
    5663           0 :             bStreaming = true;
    5664             :         }
    5665             :     }
    5666             : #endif
    5667        9492 :     if (bStreaming && !EQUAL("NONE", CSLFetchNameValueDef(papszParamList,
    5668             :                                                           "COMPRESS", "NONE")))
    5669             :     {
    5670           1 :         ReportError(pszFilename, CE_Failure, CPLE_NotSupported,
    5671             :                     "Streaming only supported to uncompressed TIFF");
    5672           1 :         return nullptr;
    5673             :     }
    5674        9491 :     if (bStreaming && CPLFetchBool(papszParamList, "SPARSE_OK", false))
    5675             :     {
    5676           1 :         ReportError(pszFilename, CE_Failure, CPLE_NotSupported,
    5677             :                     "Streaming not supported with SPARSE_OK");
    5678           1 :         return nullptr;
    5679             :     }
    5680             :     const bool bCopySrcOverviews =
    5681        9490 :         CPLFetchBool(papszParamList, "COPY_SRC_OVERVIEWS", false);
    5682        9490 :     if (bStreaming && bCopySrcOverviews)
    5683             :     {
    5684           1 :         ReportError(pszFilename, CE_Failure, CPLE_NotSupported,
    5685             :                     "Streaming not supported with COPY_SRC_OVERVIEWS");
    5686           1 :         return nullptr;
    5687             :     }
    5688        9489 :     if (bStreaming)
    5689             :     {
    5690           9 :         l_osTmpFilename = VSIMemGenerateHiddenFilename("vsistdout.tif");
    5691           9 :         pszFilename = l_osTmpFilename.c_str();
    5692             :     }
    5693             : 
    5694             :     /* -------------------------------------------------------------------- */
    5695             :     /*      Compute the uncompressed size.                                  */
    5696             :     /* -------------------------------------------------------------------- */
    5697        9489 :     const unsigned nTileXCount =
    5698        9489 :         bTiled ? DIV_ROUND_UP(nXSize, l_nBlockXSize) : 0;
    5699        9489 :     const unsigned nTileYCount =
    5700        9489 :         bTiled ? DIV_ROUND_UP(nYSize, l_nBlockYSize) : 0;
    5701             :     const double dfUncompressedImageSize =
    5702        9489 :         (bTiled ? (static_cast<double>(nTileXCount) * nTileYCount *
    5703         687 :                    l_nBlockXSize * l_nBlockYSize)
    5704        8802 :                 : (nXSize * static_cast<double>(nYSize))) *
    5705        9489 :             l_nBands * GDALGetDataTypeSizeBytes(eType) +
    5706        9489 :         dfExtraSpaceForOverviews;
    5707             : 
    5708             :     /* -------------------------------------------------------------------- */
    5709             :     /*      Should the file be created as a bigtiff file?                   */
    5710             :     /* -------------------------------------------------------------------- */
    5711        9489 :     const char *pszBIGTIFF = CSLFetchNameValue(papszParamList, "BIGTIFF");
    5712             : 
    5713        9489 :     if (pszBIGTIFF == nullptr)
    5714        9067 :         pszBIGTIFF = "IF_NEEDED";
    5715             : 
    5716        9489 :     bool bCreateBigTIFF = false;
    5717        9489 :     if (EQUAL(pszBIGTIFF, "IF_NEEDED"))
    5718             :     {
    5719        9068 :         if (l_nCompression == COMPRESSION_NONE &&
    5720             :             dfUncompressedImageSize > 4200000000.0)
    5721          17 :             bCreateBigTIFF = true;
    5722             :     }
    5723         421 :     else if (EQUAL(pszBIGTIFF, "IF_SAFER"))
    5724             :     {
    5725         401 :         if (dfUncompressedImageSize > 2000000000.0)
    5726           1 :             bCreateBigTIFF = true;
    5727             :     }
    5728             :     else
    5729             :     {
    5730          20 :         bCreateBigTIFF = CPLTestBool(pszBIGTIFF);
    5731          20 :         if (!bCreateBigTIFF && l_nCompression == COMPRESSION_NONE &&
    5732             :             dfUncompressedImageSize > 4200000000.0)
    5733             :         {
    5734           2 :             ReportError(pszFilename, CE_Failure, CPLE_NotSupported,
    5735             :                         "The TIFF file will be larger than 4GB, so BigTIFF is "
    5736             :                         "necessary.  Creation failed.");
    5737           2 :             return nullptr;
    5738             :         }
    5739             :     }
    5740             : 
    5741        9487 :     if (bCreateBigTIFF)
    5742          34 :         CPLDebug("GTiff", "File being created as a BigTIFF.");
    5743             : 
    5744             :     /* -------------------------------------------------------------------- */
    5745             :     /*      Sanity check.                                                   */
    5746             :     /* -------------------------------------------------------------------- */
    5747        9487 :     if (bTiled)
    5748             :     {
    5749             :         // libtiff implementation limitation
    5750         687 :         if (nTileXCount > 0x80000000U / (bCreateBigTIFF ? 8 : 4) / nTileYCount)
    5751             :         {
    5752           3 :             ReportError(pszFilename, CE_Failure, CPLE_NotSupported,
    5753             :                         "File too large regarding tile size. This would result "
    5754             :                         "in a file with tile arrays larger than 2GB");
    5755           3 :             return nullptr;
    5756             :         }
    5757             :     }
    5758             : 
    5759             :     /* -------------------------------------------------------------------- */
    5760             :     /*      Check free space (only for big, non sparse)                     */
    5761             :     /* -------------------------------------------------------------------- */
    5762        9484 :     const double dfLikelyFloorOfFinalSize =
    5763             :         l_nCompression == COMPRESSION_NONE
    5764        9484 :             ? dfUncompressedImageSize
    5765             :             :
    5766             :             /* For compressed, we target 1% as the most optimistic reduction factor! */
    5767             :             0.01 * dfUncompressedImageSize;
    5768        9505 :     if (dfLikelyFloorOfFinalSize >= 1e9 &&
    5769          21 :         !CPLFetchBool(papszParamList, "SPARSE_OK", false) &&
    5770           4 :         osOriFilename != "/vsistdout/" &&
    5771        9509 :         osOriFilename != "/vsistdout_redirect/" &&
    5772           4 :         CPLTestBool(CPLGetConfigOption("CHECK_DISK_FREE_SPACE", "TRUE")))
    5773             :     {
    5774             :         const GIntBig nFreeDiskSpace =
    5775           3 :             VSIGetDiskFreeSpace(CPLGetDirnameSafe(pszFilename).c_str());
    5776           3 :         if (nFreeDiskSpace >= 0 && nFreeDiskSpace < dfLikelyFloorOfFinalSize)
    5777             :         {
    5778           6 :             ReportError(
    5779             :                 pszFilename, CE_Failure, CPLE_FileIO,
    5780             :                 "Free disk space available is %s, "
    5781             :                 "whereas %s are %s necessary. "
    5782             :                 "You can disable this check by defining the "
    5783             :                 "CHECK_DISK_FREE_SPACE configuration option to FALSE.",
    5784           4 :                 CPLFormatReadableFileSize(static_cast<uint64_t>(nFreeDiskSpace))
    5785             :                     .c_str(),
    5786           4 :                 CPLFormatReadableFileSize(dfLikelyFloorOfFinalSize).c_str(),
    5787             :                 l_nCompression == COMPRESSION_NONE
    5788             :                     ? "at least"
    5789             :                     : "likely at least (probably more)");
    5790           2 :             return nullptr;
    5791             :         }
    5792             :     }
    5793             : 
    5794             :     /* -------------------------------------------------------------------- */
    5795             :     /*      Check if the user wishes a particular endianness                */
    5796             :     /* -------------------------------------------------------------------- */
    5797             : 
    5798        9482 :     int eEndianness = ENDIANNESS_NATIVE;
    5799        9482 :     const char *pszEndianness = CSLFetchNameValue(papszParamList, "ENDIANNESS");
    5800        9482 :     if (pszEndianness == nullptr)
    5801        9419 :         pszEndianness = CPLGetConfigOption("GDAL_TIFF_ENDIANNESS", nullptr);
    5802        9482 :     if (pszEndianness != nullptr)
    5803             :     {
    5804         123 :         if (EQUAL(pszEndianness, "LITTLE"))
    5805             :         {
    5806          36 :             eEndianness = ENDIANNESS_LITTLE;
    5807             :         }
    5808          87 :         else if (EQUAL(pszEndianness, "BIG"))
    5809             :         {
    5810           1 :             eEndianness = ENDIANNESS_BIG;
    5811             :         }
    5812          86 :         else if (EQUAL(pszEndianness, "INVERTED"))
    5813             :         {
    5814             : #ifdef CPL_LSB
    5815          82 :             eEndianness = ENDIANNESS_BIG;
    5816             : #else
    5817             :             eEndianness = ENDIANNESS_LITTLE;
    5818             : #endif
    5819             :         }
    5820           4 :         else if (!EQUAL(pszEndianness, "NATIVE"))
    5821             :         {
    5822           1 :             ReportError(pszFilename, CE_Warning, CPLE_NotSupported,
    5823             :                         "ENDIANNESS=%s not supported. Defaulting to NATIVE",
    5824             :                         pszEndianness);
    5825             :         }
    5826             :     }
    5827             : 
    5828             :     /* -------------------------------------------------------------------- */
    5829             :     /*      Try opening the dataset.                                        */
    5830             :     /* -------------------------------------------------------------------- */
    5831             : 
    5832             :     const bool bAppend =
    5833        9482 :         CPLFetchBool(papszParamList, "APPEND_SUBDATASET", false);
    5834             : 
    5835        9482 :     char szOpeningFlag[5] = {};
    5836        9482 :     strcpy(szOpeningFlag, bAppend ? "r+" : "w+");
    5837        9482 :     if (bCreateBigTIFF)
    5838          31 :         strcat(szOpeningFlag, "8");
    5839        9482 :     if (eEndianness == ENDIANNESS_BIG)
    5840          83 :         strcat(szOpeningFlag, "b");
    5841        9399 :     else if (eEndianness == ENDIANNESS_LITTLE)
    5842          36 :         strcat(szOpeningFlag, "l");
    5843             : 
    5844        9482 :     VSIErrorReset();
    5845        9482 :     const bool bOnlyVisibleAtCloseTime = CPLTestBool(CSLFetchNameValueDef(
    5846             :         papszParamList, "@CREATE_ONLY_VISIBLE_AT_CLOSE_TIME", "NO"));
    5847             :     VSILFILE *l_fpL =
    5848          30 :         bOnlyVisibleAtCloseTime && !bAppend
    5849        9512 :             ? VSIFileManager::GetHandler(pszFilename)
    5850          30 :                   ->CreateOnlyVisibleAtCloseTime(pszFilename, true, nullptr)
    5851        9452 :             : VSIFOpenExL(pszFilename, bAppend ? "r+b" : "w+b", true);
    5852        9482 :     if (l_fpL == nullptr)
    5853             :     {
    5854          21 :         VSIToCPLErrorWithMsg(CE_Failure, CPLE_OpenFailed,
    5855          42 :                              std::string("Attempt to create new tiff file `")
    5856          21 :                                  .append(pszFilename)
    5857          21 :                                  .append("' failed")
    5858             :                                  .c_str());
    5859          21 :         return nullptr;
    5860             :     }
    5861        9461 :     TIFF *l_hTIFF = VSI_TIFFOpen(pszFilename, szOpeningFlag, l_fpL);
    5862        9461 :     if (l_hTIFF == nullptr)
    5863             :     {
    5864           2 :         if (CPLGetLastErrorNo() == 0)
    5865           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
    5866             :                      "Attempt to create new tiff file `%s' "
    5867             :                      "failed in XTIFFOpen().",
    5868             :                      pszFilename);
    5869           2 :         l_fpL->CancelCreation();
    5870           2 :         CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
    5871           2 :         return nullptr;
    5872             :     }
    5873             : 
    5874        9459 :     if (bAppend)
    5875             :     {
    5876             : #if !(defined(INTERNAL_LIBTIFF) || TIFFLIB_VERSION > 20240911)
    5877             :         // This is a bit of a hack to cause (*tif->tif_cleanup)(tif); to be
    5878             :         // called. See https://trac.osgeo.org/gdal/ticket/2055
    5879             :         // Fixed in libtiff > 4.7.0
    5880             :         TIFFSetField(l_hTIFF, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
    5881             :         TIFFFreeDirectory(l_hTIFF);
    5882             : #endif
    5883           6 :         TIFFCreateDirectory(l_hTIFF);
    5884             :     }
    5885             : 
    5886             :     /* -------------------------------------------------------------------- */
    5887             :     /*      Do we have a custom pixel type (just used for signed byte now). */
    5888             :     /* -------------------------------------------------------------------- */
    5889        9459 :     const char *pszPixelType = CSLFetchNameValue(papszParamList, "PIXELTYPE");
    5890        9459 :     if (pszPixelType == nullptr)
    5891        9451 :         pszPixelType = "";
    5892        9459 :     if (eType == GDT_Byte && EQUAL(pszPixelType, "SIGNEDBYTE"))
    5893             :     {
    5894           8 :         CPLError(CE_Warning, CPLE_AppDefined,
    5895             :                  "Using PIXELTYPE=SIGNEDBYTE with Byte data type is deprecated "
    5896             :                  "(but still works). "
    5897             :                  "Using Int8 data type instead is now recommended.");
    5898             :     }
    5899             : 
    5900             :     /* -------------------------------------------------------------------- */
    5901             :     /*      Setup some standard flags.                                      */
    5902             :     /* -------------------------------------------------------------------- */
    5903        9459 :     TIFFSetField(l_hTIFF, TIFFTAG_IMAGEWIDTH, nXSize);
    5904        9459 :     TIFFSetField(l_hTIFF, TIFFTAG_IMAGELENGTH, nYSize);
    5905        9459 :     TIFFSetField(l_hTIFF, TIFFTAG_BITSPERSAMPLE, l_nBitsPerSample);
    5906             : 
    5907        9459 :     uint16_t l_nSampleFormat = 0;
    5908        9459 :     if ((eType == GDT_Byte && EQUAL(pszPixelType, "SIGNEDBYTE")) ||
    5909        9316 :         eType == GDT_Int8 || eType == GDT_Int16 || eType == GDT_Int32 ||
    5910             :         eType == GDT_Int64)
    5911         771 :         l_nSampleFormat = SAMPLEFORMAT_INT;
    5912        8688 :     else if (eType == GDT_CInt16 || eType == GDT_CInt32)
    5913         355 :         l_nSampleFormat = SAMPLEFORMAT_COMPLEXINT;
    5914        8333 :     else if (eType == GDT_Float16 || eType == GDT_Float32 ||
    5915             :              eType == GDT_Float64)
    5916        1064 :         l_nSampleFormat = SAMPLEFORMAT_IEEEFP;
    5917        7269 :     else if (eType == GDT_CFloat16 || eType == GDT_CFloat32 ||
    5918             :              eType == GDT_CFloat64)
    5919         462 :         l_nSampleFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
    5920             :     else
    5921        6807 :         l_nSampleFormat = SAMPLEFORMAT_UINT;
    5922             : 
    5923        9459 :     TIFFSetField(l_hTIFF, TIFFTAG_SAMPLEFORMAT, l_nSampleFormat);
    5924        9459 :     TIFFSetField(l_hTIFF, TIFFTAG_SAMPLESPERPIXEL, l_nBands);
    5925        9459 :     TIFFSetField(l_hTIFF, TIFFTAG_PLANARCONFIG, nPlanar);
    5926             : 
    5927             :     /* -------------------------------------------------------------------- */
    5928             :     /*      Setup Photometric Interpretation. Take this value from the user */
    5929             :     /*      passed option or guess correct value otherwise.                 */
    5930             :     /* -------------------------------------------------------------------- */
    5931        9459 :     int nSamplesAccountedFor = 1;
    5932        9459 :     bool bForceColorTable = false;
    5933             : 
    5934        9459 :     if (const char *pszValue = CSLFetchNameValue(papszParamList, "PHOTOMETRIC"))
    5935             :     {
    5936        1892 :         if (EQUAL(pszValue, "MINISBLACK"))
    5937          14 :             TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
    5938        1878 :         else if (EQUAL(pszValue, "MINISWHITE"))
    5939             :         {
    5940           2 :             TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
    5941             :         }
    5942        1876 :         else if (EQUAL(pszValue, "PALETTE"))
    5943             :         {
    5944           5 :             if (eType == GDT_Byte || eType == GDT_UInt16)
    5945             :             {
    5946           4 :                 TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
    5947           4 :                 nSamplesAccountedFor = 1;
    5948           4 :                 bForceColorTable = true;
    5949             :             }
    5950             :             else
    5951             :             {
    5952           1 :                 ReportError(
    5953             :                     pszFilename, CE_Warning, CPLE_AppDefined,
    5954             :                     "PHOTOMETRIC=PALETTE only compatible with Byte or UInt16");
    5955             :             }
    5956             :         }
    5957        1871 :         else if (EQUAL(pszValue, "RGB"))
    5958             :         {
    5959        1127 :             TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
    5960        1127 :             nSamplesAccountedFor = 3;
    5961             :         }
    5962         744 :         else if (EQUAL(pszValue, "CMYK"))
    5963             :         {
    5964          10 :             TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_SEPARATED);
    5965          10 :             nSamplesAccountedFor = 4;
    5966             :         }
    5967         734 :         else if (EQUAL(pszValue, "YCBCR"))
    5968             :         {
    5969             :             // Because of subsampling, setting YCBCR without JPEG compression
    5970             :             // leads to a crash currently. Would need to make
    5971             :             // GTiffRasterBand::IWriteBlock() aware of subsampling so that it
    5972             :             // doesn't overrun buffer size returned by libtiff.
    5973         733 :             if (l_nCompression != COMPRESSION_JPEG)
    5974             :             {
    5975           1 :                 ReportError(
    5976             :                     pszFilename, CE_Failure, CPLE_NotSupported,
    5977             :                     "Currently, PHOTOMETRIC=YCBCR requires COMPRESS=JPEG");
    5978           1 :                 XTIFFClose(l_hTIFF);
    5979           1 :                 l_fpL->CancelCreation();
    5980           1 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
    5981           1 :                 return nullptr;
    5982             :             }
    5983             : 
    5984         732 :             if (nPlanar == PLANARCONFIG_SEPARATE)
    5985             :             {
    5986           1 :                 ReportError(pszFilename, CE_Failure, CPLE_NotSupported,
    5987             :                             "PHOTOMETRIC=YCBCR requires INTERLEAVE=PIXEL");
    5988           1 :                 XTIFFClose(l_hTIFF);
    5989           1 :                 l_fpL->CancelCreation();
    5990           1 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
    5991           1 :                 return nullptr;
    5992             :             }
    5993             : 
    5994             :             // YCBCR strictly requires 3 bands. Not less, not more Issue an
    5995             :             // explicit error message as libtiff one is a bit cryptic:
    5996             :             // TIFFVStripSize64:Invalid td_samplesperpixel value.
    5997         731 :             if (l_nBands != 3)
    5998             :             {
    5999           1 :                 ReportError(
    6000             :                     pszFilename, CE_Failure, CPLE_NotSupported,
    6001             :                     "PHOTOMETRIC=YCBCR not supported on a %d-band raster: "
    6002             :                     "only compatible of a 3-band (RGB) raster",
    6003             :                     l_nBands);
    6004           1 :                 XTIFFClose(l_hTIFF);
    6005           1 :                 l_fpL->CancelCreation();
    6006           1 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
    6007           1 :                 return nullptr;
    6008             :             }
    6009             : 
    6010         730 :             TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
    6011         730 :             nSamplesAccountedFor = 3;
    6012             : 
    6013             :             // Explicitly register the subsampling so that JPEGFixupTags
    6014             :             // is a no-op (helps for cloud optimized geotiffs)
    6015         730 :             TIFFSetField(l_hTIFF, TIFFTAG_YCBCRSUBSAMPLING, 2, 2);
    6016             :         }
    6017           1 :         else if (EQUAL(pszValue, "CIELAB"))
    6018             :         {
    6019           0 :             TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CIELAB);
    6020           0 :             nSamplesAccountedFor = 3;
    6021             :         }
    6022           1 :         else if (EQUAL(pszValue, "ICCLAB"))
    6023             :         {
    6024           0 :             TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_ICCLAB);
    6025           0 :             nSamplesAccountedFor = 3;
    6026             :         }
    6027           1 :         else if (EQUAL(pszValue, "ITULAB"))
    6028             :         {
    6029           0 :             TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_ITULAB);
    6030           0 :             nSamplesAccountedFor = 3;
    6031             :         }
    6032             :         else
    6033             :         {
    6034           1 :             ReportError(pszFilename, CE_Warning, CPLE_IllegalArg,
    6035             :                         "PHOTOMETRIC=%s value not recognised, ignoring.  "
    6036             :                         "Set the Photometric Interpretation as MINISBLACK.",
    6037             :                         pszValue);
    6038           1 :             TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
    6039             :         }
    6040             : 
    6041        1889 :         if (l_nBands < nSamplesAccountedFor)
    6042             :         {
    6043           1 :             ReportError(pszFilename, CE_Warning, CPLE_IllegalArg,
    6044             :                         "PHOTOMETRIC=%s value does not correspond to number "
    6045             :                         "of bands (%d), ignoring.  "
    6046             :                         "Set the Photometric Interpretation as MINISBLACK.",
    6047             :                         pszValue, l_nBands);
    6048           1 :             TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
    6049             :         }
    6050             :     }
    6051             :     else
    6052             :     {
    6053             :         // If image contains 3 or 4 bands and datatype is Byte then we will
    6054             :         // assume it is RGB. In all other cases assume it is MINISBLACK.
    6055        7567 :         if (l_nBands == 3 && eType == GDT_Byte)
    6056             :         {
    6057         312 :             TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
    6058         312 :             nSamplesAccountedFor = 3;
    6059             :         }
    6060        7255 :         else if (l_nBands == 4 && eType == GDT_Byte)
    6061             :         {
    6062             :             uint16_t v[1] = {
    6063         717 :                 GTiffGetAlphaValue(CSLFetchNameValue(papszParamList, "ALPHA"),
    6064         717 :                                    DEFAULT_ALPHA_TYPE)};
    6065             : 
    6066         717 :             TIFFSetField(l_hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
    6067         717 :             TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
    6068         717 :             nSamplesAccountedFor = 4;
    6069             :         }
    6070             :         else
    6071             :         {
    6072        6538 :             TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
    6073        6538 :             nSamplesAccountedFor = 1;
    6074             :         }
    6075             :     }
    6076             : 
    6077             :     /* -------------------------------------------------------------------- */
    6078             :     /*      If there are extra samples, we need to mark them with an        */
    6079             :     /*      appropriate extrasamples definition here.                       */
    6080             :     /* -------------------------------------------------------------------- */
    6081        9456 :     if (l_nBands > nSamplesAccountedFor)
    6082             :     {
    6083        1320 :         const int nExtraSamples = l_nBands - nSamplesAccountedFor;
    6084             : 
    6085             :         uint16_t *v = static_cast<uint16_t *>(
    6086        1320 :             CPLMalloc(sizeof(uint16_t) * nExtraSamples));
    6087             : 
    6088        1320 :         v[0] = GTiffGetAlphaValue(CSLFetchNameValue(papszParamList, "ALPHA"),
    6089             :                                   EXTRASAMPLE_UNSPECIFIED);
    6090             : 
    6091      297582 :         for (int i = 1; i < nExtraSamples; ++i)
    6092      296262 :             v[i] = EXTRASAMPLE_UNSPECIFIED;
    6093             : 
    6094        1320 :         TIFFSetField(l_hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples, v);
    6095             : 
    6096        1320 :         CPLFree(v);
    6097             :     }
    6098             : 
    6099             :     // Set the ICC color profile.
    6100        9456 :     if (eProfile != GTiffProfile::BASELINE)
    6101             :     {
    6102        9431 :         SaveICCProfile(nullptr, l_hTIFF, papszParamList, l_nBitsPerSample);
    6103             :     }
    6104             : 
    6105             :     // Set the compression method before asking the default strip size
    6106             :     // This is useful when translating to a JPEG-In-TIFF file where
    6107             :     // the default strip size is 8 or 16 depending on the photometric value.
    6108        9456 :     TIFFSetField(l_hTIFF, TIFFTAG_COMPRESSION, l_nCompression);
    6109             : 
    6110        9456 :     if (l_nCompression == COMPRESSION_LERC)
    6111             :     {
    6112             :         const char *pszCompress =
    6113          97 :             CSLFetchNameValueDef(papszParamList, "COMPRESS", "");
    6114          97 :         if (EQUAL(pszCompress, "LERC_DEFLATE"))
    6115             :         {
    6116          16 :             TIFFSetField(l_hTIFF, TIFFTAG_LERC_ADD_COMPRESSION,
    6117             :                          LERC_ADD_COMPRESSION_DEFLATE);
    6118             :         }
    6119          81 :         else if (EQUAL(pszCompress, "LERC_ZSTD"))
    6120             :         {
    6121          14 :             if (TIFFSetField(l_hTIFF, TIFFTAG_LERC_ADD_COMPRESSION,
    6122          14 :                              LERC_ADD_COMPRESSION_ZSTD) != 1)
    6123             :             {
    6124           0 :                 XTIFFClose(l_hTIFF);
    6125           0 :                 l_fpL->CancelCreation();
    6126           0 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
    6127           0 :                 return nullptr;
    6128             :             }
    6129             :         }
    6130             :     }
    6131             :     // TODO later: take into account LERC version
    6132             : 
    6133             :     /* -------------------------------------------------------------------- */
    6134             :     /*      Setup tiling/stripping flags.                                   */
    6135             :     /* -------------------------------------------------------------------- */
    6136        9456 :     if (bTiled)
    6137             :     {
    6138        1354 :         if (!TIFFSetField(l_hTIFF, TIFFTAG_TILEWIDTH, l_nBlockXSize) ||
    6139         677 :             !TIFFSetField(l_hTIFF, TIFFTAG_TILELENGTH, l_nBlockYSize))
    6140             :         {
    6141           0 :             XTIFFClose(l_hTIFF);
    6142           0 :             l_fpL->CancelCreation();
    6143           0 :             CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
    6144           0 :             return nullptr;
    6145             :         }
    6146             :     }
    6147             :     else
    6148             :     {
    6149        8779 :         const uint32_t l_nRowsPerStrip = std::min(
    6150             :             nYSize, l_nBlockYSize == 0
    6151        8779 :                         ? static_cast<int>(TIFFDefaultStripSize(l_hTIFF, 0))
    6152        8779 :                         : l_nBlockYSize);
    6153             : 
    6154        8779 :         TIFFSetField(l_hTIFF, TIFFTAG_ROWSPERSTRIP, l_nRowsPerStrip);
    6155             :     }
    6156             : 
    6157             :     /* -------------------------------------------------------------------- */
    6158             :     /*      Set compression related tags.                                   */
    6159             :     /* -------------------------------------------------------------------- */
    6160        9456 :     if (GTIFFSupportsPredictor(l_nCompression))
    6161         859 :         TIFFSetField(l_hTIFF, TIFFTAG_PREDICTOR, nPredictor);
    6162        9456 :     if (l_nCompression == COMPRESSION_ADOBE_DEFLATE ||
    6163             :         l_nCompression == COMPRESSION_LERC)
    6164             :     {
    6165         276 :         GTiffSetDeflateSubCodec(l_hTIFF);
    6166             : 
    6167         276 :         if (l_nZLevel != -1)
    6168          22 :             TIFFSetField(l_hTIFF, TIFFTAG_ZIPQUALITY, l_nZLevel);
    6169             :     }
    6170        9456 :     if (l_nCompression == COMPRESSION_JPEG && l_nJpegQuality != -1)
    6171        1905 :         TIFFSetField(l_hTIFF, TIFFTAG_JPEGQUALITY, l_nJpegQuality);
    6172        9456 :     if (l_nCompression == COMPRESSION_LZMA && l_nLZMAPreset != -1)
    6173          10 :         TIFFSetField(l_hTIFF, TIFFTAG_LZMAPRESET, l_nLZMAPreset);
    6174        9456 :     if ((l_nCompression == COMPRESSION_ZSTD ||
    6175         153 :          l_nCompression == COMPRESSION_LERC) &&
    6176             :         l_nZSTDLevel != -1)
    6177          12 :         TIFFSetField(l_hTIFF, TIFFTAG_ZSTD_LEVEL, l_nZSTDLevel);
    6178        9456 :     if (l_nCompression == COMPRESSION_LERC)
    6179             :     {
    6180          97 :         TIFFSetField(l_hTIFF, TIFFTAG_LERC_MAXZERROR, l_dfMaxZError);
    6181             :     }
    6182             : #if HAVE_JXL
    6183        9456 :     if (l_nCompression == COMPRESSION_JXL ||
    6184             :         l_nCompression == COMPRESSION_JXL_DNG_1_7)
    6185             :     {
    6186         101 :         TIFFSetField(l_hTIFF, TIFFTAG_JXL_LOSSYNESS,
    6187             :                      l_bJXLLossless ? JXL_LOSSLESS : JXL_LOSSY);
    6188         101 :         TIFFSetField(l_hTIFF, TIFFTAG_JXL_EFFORT, l_nJXLEffort);
    6189         101 :         TIFFSetField(l_hTIFF, TIFFTAG_JXL_DISTANCE, l_fJXLDistance);
    6190         101 :         TIFFSetField(l_hTIFF, TIFFTAG_JXL_ALPHA_DISTANCE, l_fJXLAlphaDistance);
    6191             :     }
    6192             : #endif
    6193        9456 :     if (l_nCompression == COMPRESSION_WEBP)
    6194          33 :         TIFFSetField(l_hTIFF, TIFFTAG_WEBP_LEVEL, l_nWebPLevel);
    6195        9456 :     if (l_nCompression == COMPRESSION_WEBP && l_bWebPLossless)
    6196           7 :         TIFFSetField(l_hTIFF, TIFFTAG_WEBP_LOSSLESS, 1);
    6197             : 
    6198        9456 :     if (l_nCompression == COMPRESSION_JPEG)
    6199        2087 :         TIFFSetField(l_hTIFF, TIFFTAG_JPEGTABLESMODE, l_nJpegTablesMode);
    6200             : 
    6201             :     /* -------------------------------------------------------------------- */
    6202             :     /*      If we forced production of a file with photometric=palette,     */
    6203             :     /*      we need to push out a default color table.                      */
    6204             :     /* -------------------------------------------------------------------- */
    6205        9456 :     if (bForceColorTable)
    6206             :     {
    6207           4 :         const int nColors = eType == GDT_Byte ? 256 : 65536;
    6208             : 
    6209             :         unsigned short *panTRed = static_cast<unsigned short *>(
    6210           4 :             CPLMalloc(sizeof(unsigned short) * nColors));
    6211             :         unsigned short *panTGreen = static_cast<unsigned short *>(
    6212           4 :             CPLMalloc(sizeof(unsigned short) * nColors));
    6213             :         unsigned short *panTBlue = static_cast<unsigned short *>(
    6214           4 :             CPLMalloc(sizeof(unsigned short) * nColors));
    6215             : 
    6216        1028 :         for (int iColor = 0; iColor < nColors; ++iColor)
    6217             :         {
    6218        1024 :             if (eType == GDT_Byte)
    6219             :             {
    6220        1024 :                 panTRed[iColor] = GTiffDataset::ClampCTEntry(
    6221             :                     iColor, 1, iColor, nColorTableMultiplier);
    6222        1024 :                 panTGreen[iColor] = GTiffDataset::ClampCTEntry(
    6223             :                     iColor, 2, iColor, nColorTableMultiplier);
    6224        1024 :                 panTBlue[iColor] = GTiffDataset::ClampCTEntry(
    6225             :                     iColor, 3, iColor, nColorTableMultiplier);
    6226             :             }
    6227             :             else
    6228             :             {
    6229           0 :                 panTRed[iColor] = static_cast<unsigned short>(iColor);
    6230           0 :                 panTGreen[iColor] = static_cast<unsigned short>(iColor);
    6231           0 :                 panTBlue[iColor] = static_cast<unsigned short>(iColor);
    6232             :             }
    6233             :         }
    6234             : 
    6235           4 :         TIFFSetField(l_hTIFF, TIFFTAG_COLORMAP, panTRed, panTGreen, panTBlue);
    6236             : 
    6237           4 :         CPLFree(panTRed);
    6238           4 :         CPLFree(panTGreen);
    6239           4 :         CPLFree(panTBlue);
    6240             :     }
    6241             : 
    6242             :     // This trick
    6243             :     // creates a temporary in-memory file and fetches its JPEG tables so that
    6244             :     // we can directly set them, before tif_jpeg.c compute them at the first
    6245             :     // strip/tile writing, which is too late, since we have already crystalized
    6246             :     // the directory. This way we avoid a directory rewriting.
    6247       11543 :     if (l_nCompression == COMPRESSION_JPEG &&
    6248        2087 :         CPLTestBool(
    6249             :             CSLFetchNameValueDef(papszParamList, "WRITE_JPEGTABLE_TAG", "YES")))
    6250             :     {
    6251        1014 :         GTiffWriteJPEGTables(
    6252             :             l_hTIFF, CSLFetchNameValue(papszParamList, "PHOTOMETRIC"),
    6253             :             CSLFetchNameValue(papszParamList, "JPEG_QUALITY"),
    6254             :             CSLFetchNameValue(papszParamList, "JPEGTABLESMODE"));
    6255             :     }
    6256             : 
    6257        9456 :     *pfpL = l_fpL;
    6258             : 
    6259        9456 :     return l_hTIFF;
    6260             : }
    6261             : 
    6262             : /************************************************************************/
    6263             : /*                            GuessJPEGQuality()                        */
    6264             : /*                                                                      */
    6265             : /*      Guess JPEG quality from JPEGTABLES tag.                         */
    6266             : /************************************************************************/
    6267             : 
    6268        3915 : static const GByte *GTIFFFindNextTable(const GByte *paby, GByte byMarker,
    6269             :                                        int nLen, int *pnLenTable)
    6270             : {
    6271        8097 :     for (int i = 0; i + 1 < nLen;)
    6272             :     {
    6273        8097 :         if (paby[i] != 0xFF)
    6274           0 :             return nullptr;
    6275        8097 :         ++i;
    6276        8097 :         if (paby[i] == 0xD8)
    6277             :         {
    6278        3156 :             ++i;
    6279        3156 :             continue;
    6280             :         }
    6281        4941 :         if (i + 2 >= nLen)
    6282         859 :             return nullptr;
    6283        4082 :         int nMarkerLen = paby[i + 1] * 256 + paby[i + 2];
    6284        4082 :         if (i + 1 + nMarkerLen >= nLen)
    6285           0 :             return nullptr;
    6286        4082 :         if (paby[i] == byMarker)
    6287             :         {
    6288        3056 :             if (pnLenTable)
    6289        2499 :                 *pnLenTable = nMarkerLen;
    6290        3056 :             return paby + i + 1;
    6291             :         }
    6292        1026 :         i += 1 + nMarkerLen;
    6293             :     }
    6294           0 :     return nullptr;
    6295             : }
    6296             : 
    6297             : constexpr GByte MARKER_HUFFMAN_TABLE = 0xC4;
    6298             : constexpr GByte MARKER_QUANT_TABLE = 0xDB;
    6299             : 
    6300             : // We assume that if there are several quantization tables, they are
    6301             : // in the same order. Which is a reasonable assumption for updating
    6302             : // a file generated by ourselves.
    6303         904 : static bool GTIFFQuantizationTablesEqual(const GByte *paby1, int nLen1,
    6304             :                                          const GByte *paby2, int nLen2)
    6305             : {
    6306         904 :     bool bFound = false;
    6307             :     while (true)
    6308             :     {
    6309         945 :         int nLenTable1 = 0;
    6310         945 :         int nLenTable2 = 0;
    6311             :         const GByte *paby1New =
    6312         945 :             GTIFFFindNextTable(paby1, MARKER_QUANT_TABLE, nLen1, &nLenTable1);
    6313             :         const GByte *paby2New =
    6314         945 :             GTIFFFindNextTable(paby2, MARKER_QUANT_TABLE, nLen2, &nLenTable2);
    6315         945 :         if (paby1New == nullptr && paby2New == nullptr)
    6316         904 :             return bFound;
    6317         911 :         if (paby1New == nullptr || paby2New == nullptr)
    6318           0 :             return false;
    6319         911 :         if (nLenTable1 != nLenTable2)
    6320         207 :             return false;
    6321         704 :         if (memcmp(paby1New, paby2New, nLenTable1) != 0)
    6322         663 :             return false;
    6323          41 :         paby1New += nLenTable1;
    6324          41 :         paby2New += nLenTable2;
    6325          41 :         nLen1 -= static_cast<int>(paby1New - paby1);
    6326          41 :         nLen2 -= static_cast<int>(paby2New - paby2);
    6327          41 :         paby1 = paby1New;
    6328          41 :         paby2 = paby2New;
    6329          41 :         bFound = true;
    6330          41 :     }
    6331             : }
    6332             : 
    6333             : // Guess the JPEG quality by comparing against the MD5Sum of precomputed
    6334             : // quantization tables
    6335         422 : static int GuessJPEGQualityFromMD5(const uint8_t md5JPEGQuantTable[][16],
    6336             :                                    const GByte *const pabyJPEGTable,
    6337             :                                    int nJPEGTableSize)
    6338             : {
    6339         422 :     int nRemainingLen = nJPEGTableSize;
    6340         422 :     const GByte *pabyCur = pabyJPEGTable;
    6341             : 
    6342             :     struct CPLMD5Context context;
    6343         422 :     CPLMD5Init(&context);
    6344             : 
    6345             :     while (true)
    6346             :     {
    6347        1099 :         int nLenTable = 0;
    6348        1099 :         const GByte *pabyNew = GTIFFFindNextTable(pabyCur, MARKER_QUANT_TABLE,
    6349             :                                                   nRemainingLen, &nLenTable);
    6350        1099 :         if (pabyNew == nullptr)
    6351         422 :             break;
    6352         677 :         CPLMD5Update(&context, pabyNew, nLenTable);
    6353         677 :         pabyNew += nLenTable;
    6354         677 :         nRemainingLen -= static_cast<int>(pabyNew - pabyCur);
    6355         677 :         pabyCur = pabyNew;
    6356         677 :     }
    6357             : 
    6358             :     GByte digest[16];
    6359         422 :     CPLMD5Final(digest, &context);
    6360             : 
    6361       29821 :     for (int i = 0; i < 100; i++)
    6362             :     {
    6363       29818 :         if (memcmp(md5JPEGQuantTable[i], digest, 16) == 0)
    6364             :         {
    6365         419 :             return i + 1;
    6366             :         }
    6367             :     }
    6368           3 :     return -1;
    6369             : }
    6370             : 
    6371         477 : int GTiffDataset::GuessJPEGQuality(bool &bOutHasQuantizationTable,
    6372             :                                    bool &bOutHasHuffmanTable)
    6373             : {
    6374         477 :     CPLAssert(m_nCompression == COMPRESSION_JPEG);
    6375         477 :     uint32_t nJPEGTableSize = 0;
    6376         477 :     void *pJPEGTable = nullptr;
    6377         477 :     if (!TIFFGetField(m_hTIFF, TIFFTAG_JPEGTABLES, &nJPEGTableSize,
    6378             :                       &pJPEGTable))
    6379             :     {
    6380          14 :         bOutHasQuantizationTable = false;
    6381          14 :         bOutHasHuffmanTable = false;
    6382          14 :         return -1;
    6383             :     }
    6384             : 
    6385         463 :     bOutHasQuantizationTable =
    6386         463 :         GTIFFFindNextTable(static_cast<const GByte *>(pJPEGTable),
    6387             :                            MARKER_QUANT_TABLE, nJPEGTableSize,
    6388         463 :                            nullptr) != nullptr;
    6389         463 :     bOutHasHuffmanTable =
    6390         463 :         GTIFFFindNextTable(static_cast<const GByte *>(pJPEGTable),
    6391             :                            MARKER_HUFFMAN_TABLE, nJPEGTableSize,
    6392         463 :                            nullptr) != nullptr;
    6393         463 :     if (!bOutHasQuantizationTable)
    6394           7 :         return -1;
    6395             : 
    6396         456 :     if ((nBands == 1 && m_nBitsPerSample == 8) ||
    6397         395 :         (nBands == 3 && m_nBitsPerSample == 8 &&
    6398         349 :          m_nPhotometric == PHOTOMETRIC_RGB) ||
    6399         301 :         (nBands == 4 && m_nBitsPerSample == 8 &&
    6400          27 :          m_nPhotometric == PHOTOMETRIC_SEPARATED))
    6401             :     {
    6402         167 :         return GuessJPEGQualityFromMD5(md5JPEGQuantTable_generic_8bit,
    6403             :                                        static_cast<const GByte *>(pJPEGTable),
    6404         167 :                                        static_cast<int>(nJPEGTableSize));
    6405             :     }
    6406             : 
    6407         289 :     if (nBands == 3 && m_nBitsPerSample == 8 &&
    6408         255 :         m_nPhotometric == PHOTOMETRIC_YCBCR)
    6409             :     {
    6410             :         int nRet =
    6411         255 :             GuessJPEGQualityFromMD5(md5JPEGQuantTable_3_YCBCR_8bit,
    6412             :                                     static_cast<const GByte *>(pJPEGTable),
    6413             :                                     static_cast<int>(nJPEGTableSize));
    6414         255 :         if (nRet < 0)
    6415             :         {
    6416             :             // libjpeg 9e has modified the YCbCr quantization tables.
    6417             :             nRet =
    6418           0 :                 GuessJPEGQualityFromMD5(md5JPEGQuantTable_3_YCBCR_8bit_jpeg9e,
    6419             :                                         static_cast<const GByte *>(pJPEGTable),
    6420             :                                         static_cast<int>(nJPEGTableSize));
    6421             :         }
    6422         255 :         return nRet;
    6423             :     }
    6424             : 
    6425          34 :     char **papszLocalParameters = nullptr;
    6426             :     papszLocalParameters =
    6427          34 :         CSLSetNameValue(papszLocalParameters, "COMPRESS", "JPEG");
    6428          34 :     if (m_nPhotometric == PHOTOMETRIC_YCBCR)
    6429             :         papszLocalParameters =
    6430           7 :             CSLSetNameValue(papszLocalParameters, "PHOTOMETRIC", "YCBCR");
    6431          27 :     else if (m_nPhotometric == PHOTOMETRIC_SEPARATED)
    6432             :         papszLocalParameters =
    6433           0 :             CSLSetNameValue(papszLocalParameters, "PHOTOMETRIC", "CMYK");
    6434             :     papszLocalParameters =
    6435          34 :         CSLSetNameValue(papszLocalParameters, "BLOCKYSIZE", "16");
    6436          34 :     if (m_nBitsPerSample == 12)
    6437             :         papszLocalParameters =
    6438          16 :             CSLSetNameValue(papszLocalParameters, "NBITS", "12");
    6439             : 
    6440             :     const CPLString osTmpFilenameIn(
    6441          34 :         VSIMemGenerateHiddenFilename("gtiffdataset_guess_jpeg_quality_tmp"));
    6442             : 
    6443          34 :     int nRet = -1;
    6444         938 :     for (int nQuality = 0; nQuality <= 100 && nRet < 0; ++nQuality)
    6445             :     {
    6446         904 :         VSILFILE *fpTmp = nullptr;
    6447         904 :         if (nQuality == 0)
    6448             :             papszLocalParameters =
    6449          34 :                 CSLSetNameValue(papszLocalParameters, "JPEG_QUALITY", "75");
    6450             :         else
    6451             :             papszLocalParameters =
    6452         870 :                 CSLSetNameValue(papszLocalParameters, "JPEG_QUALITY",
    6453             :                                 CPLSPrintf("%d", nQuality));
    6454             : 
    6455         904 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    6456         904 :         CPLString osTmp;
    6457             :         bool bTileInterleaving;
    6458        1808 :         TIFF *hTIFFTmp = CreateLL(
    6459         904 :             osTmpFilenameIn, 16, 16, (nBands <= 4) ? nBands : 1,
    6460             :             GetRasterBand(1)->GetRasterDataType(), 0.0, 0, papszLocalParameters,
    6461             :             &fpTmp, osTmp, /* bCreateCopy=*/false, bTileInterleaving);
    6462         904 :         CPLPopErrorHandler();
    6463         904 :         if (!hTIFFTmp)
    6464             :         {
    6465           0 :             break;
    6466             :         }
    6467             : 
    6468         904 :         TIFFWriteCheck(hTIFFTmp, FALSE, "CreateLL");
    6469         904 :         TIFFWriteDirectory(hTIFFTmp);
    6470         904 :         TIFFSetDirectory(hTIFFTmp, 0);
    6471             :         // Now reset jpegcolormode.
    6472        1196 :         if (m_nPhotometric == PHOTOMETRIC_YCBCR &&
    6473         292 :             CPLTestBool(CPLGetConfigOption("CONVERT_YCBCR_TO_RGB", "YES")))
    6474             :         {
    6475         292 :             TIFFSetField(hTIFFTmp, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
    6476             :         }
    6477             : 
    6478         904 :         GByte abyZeroData[(16 * 16 * 4 * 3) / 2] = {};
    6479         904 :         const int nBlockSize =
    6480         904 :             (16 * 16 * ((nBands <= 4) ? nBands : 1) * m_nBitsPerSample) / 8;
    6481         904 :         TIFFWriteEncodedStrip(hTIFFTmp, 0, abyZeroData, nBlockSize);
    6482             : 
    6483         904 :         uint32_t nJPEGTableSizeTry = 0;
    6484         904 :         void *pJPEGTableTry = nullptr;
    6485         904 :         if (TIFFGetField(hTIFFTmp, TIFFTAG_JPEGTABLES, &nJPEGTableSizeTry,
    6486         904 :                          &pJPEGTableTry))
    6487             :         {
    6488         904 :             if (GTIFFQuantizationTablesEqual(
    6489             :                     static_cast<GByte *>(pJPEGTable), nJPEGTableSize,
    6490             :                     static_cast<GByte *>(pJPEGTableTry), nJPEGTableSizeTry))
    6491             :             {
    6492          34 :                 nRet = (nQuality == 0) ? 75 : nQuality;
    6493             :             }
    6494             :         }
    6495             : 
    6496         904 :         XTIFFClose(hTIFFTmp);
    6497         904 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpTmp));
    6498             :     }
    6499             : 
    6500          34 :     CSLDestroy(papszLocalParameters);
    6501          34 :     VSIUnlink(osTmpFilenameIn);
    6502             : 
    6503          34 :     return nRet;
    6504             : }
    6505             : 
    6506             : /************************************************************************/
    6507             : /*               SetJPEGQualityAndTablesModeFromFile()                  */
    6508             : /************************************************************************/
    6509             : 
    6510         165 : void GTiffDataset::SetJPEGQualityAndTablesModeFromFile(
    6511             :     int nQuality, bool bHasQuantizationTable, bool bHasHuffmanTable)
    6512             : {
    6513         165 :     if (nQuality > 0)
    6514             :     {
    6515         158 :         CPLDebug("GTiff", "Guessed JPEG quality to be %d", nQuality);
    6516         158 :         m_nJpegQuality = static_cast<signed char>(nQuality);
    6517         158 :         TIFFSetField(m_hTIFF, TIFFTAG_JPEGQUALITY, nQuality);
    6518             : 
    6519             :         // This means we will use the quantization tables from the
    6520             :         // JpegTables tag.
    6521         158 :         m_nJpegTablesMode = JPEGTABLESMODE_QUANT;
    6522             :     }
    6523             :     else
    6524             :     {
    6525           7 :         uint32_t nJPEGTableSize = 0;
    6526           7 :         void *pJPEGTable = nullptr;
    6527           7 :         if (!TIFFGetField(m_hTIFF, TIFFTAG_JPEGTABLES, &nJPEGTableSize,
    6528             :                           &pJPEGTable))
    6529             :         {
    6530           4 :             toff_t *panByteCounts = nullptr;
    6531           8 :             const int nBlockCount = m_nPlanarConfig == PLANARCONFIG_SEPARATE
    6532           4 :                                         ? m_nBlocksPerBand * nBands
    6533             :                                         : m_nBlocksPerBand;
    6534           4 :             if (TIFFIsTiled(m_hTIFF))
    6535           1 :                 TIFFGetField(m_hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts);
    6536             :             else
    6537           3 :                 TIFFGetField(m_hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts);
    6538             : 
    6539           4 :             bool bFoundNonEmptyBlock = false;
    6540           4 :             if (panByteCounts != nullptr)
    6541             :             {
    6542          56 :                 for (int iBlock = 0; iBlock < nBlockCount; ++iBlock)
    6543             :                 {
    6544          53 :                     if (panByteCounts[iBlock] != 0)
    6545             :                     {
    6546           1 :                         bFoundNonEmptyBlock = true;
    6547           1 :                         break;
    6548             :                     }
    6549             :                 }
    6550             :             }
    6551           4 :             if (bFoundNonEmptyBlock)
    6552             :             {
    6553           1 :                 CPLDebug("GTiff", "Could not guess JPEG quality. "
    6554             :                                   "JPEG tables are missing, so going in "
    6555             :                                   "TIFFTAG_JPEGTABLESMODE = 0/2 mode");
    6556             :                 // Write quantization tables in each strile.
    6557           1 :                 m_nJpegTablesMode = 0;
    6558             :             }
    6559             :         }
    6560             :         else
    6561             :         {
    6562           3 :             if (bHasQuantizationTable)
    6563             :             {
    6564             :                 // FIXME in libtiff: this is likely going to cause issues
    6565             :                 // since libtiff will reuse in each strile the number of
    6566             :                 // the global quantization table, which is invalid.
    6567           1 :                 CPLDebug("GTiff",
    6568             :                          "Could not guess JPEG quality although JPEG "
    6569             :                          "quantization tables are present, so going in "
    6570             :                          "TIFFTAG_JPEGTABLESMODE = 0/2 mode");
    6571             :             }
    6572             :             else
    6573             :             {
    6574           2 :                 CPLDebug("GTiff",
    6575             :                          "Could not guess JPEG quality since JPEG "
    6576             :                          "quantization tables are not present, so going in "
    6577             :                          "TIFFTAG_JPEGTABLESMODE = 0/2 mode");
    6578             :             }
    6579             : 
    6580             :             // Write quantization tables in each strile.
    6581           3 :             m_nJpegTablesMode = 0;
    6582             :         }
    6583             :     }
    6584         165 :     if (bHasHuffmanTable)
    6585             :     {
    6586             :         // If there are Huffman tables in header use them, otherwise
    6587             :         // if we use optimized tables, libtiff will currently reuse
    6588             :         // the number of the Huffman tables of the header for the
    6589             :         // optimized version of each strile, which is illegal.
    6590          23 :         m_nJpegTablesMode |= JPEGTABLESMODE_HUFF;
    6591             :     }
    6592         165 :     if (m_nJpegTablesMode >= 0)
    6593         163 :         TIFFSetField(m_hTIFF, TIFFTAG_JPEGTABLESMODE, m_nJpegTablesMode);
    6594         165 : }
    6595             : 
    6596             : /************************************************************************/
    6597             : /*                               Create()                               */
    6598             : /*                                                                      */
    6599             : /*      Create a new GeoTIFF or TIFF file.                              */
    6600             : /************************************************************************/
    6601             : 
    6602        5499 : GDALDataset *GTiffDataset::Create(const char *pszFilename, int nXSize,
    6603             :                                   int nYSize, int l_nBands, GDALDataType eType,
    6604             :                                   char **papszParamList)
    6605             : 
    6606             : {
    6607        5499 :     VSILFILE *l_fpL = nullptr;
    6608       10998 :     CPLString l_osTmpFilename;
    6609             : 
    6610             :     const int nColorTableMultiplier = std::max(
    6611       10998 :         1,
    6612       10998 :         std::min(257,
    6613        5499 :                  atoi(CSLFetchNameValueDef(
    6614             :                      papszParamList, "COLOR_TABLE_MULTIPLIER",
    6615        5499 :                      CPLSPrintf("%d", DEFAULT_COLOR_TABLE_MULTIPLIER_257)))));
    6616             : 
    6617             :     /* -------------------------------------------------------------------- */
    6618             :     /*      Create the underlying TIFF file.                                */
    6619             :     /* -------------------------------------------------------------------- */
    6620             :     bool bTileInterleaving;
    6621             :     TIFF *l_hTIFF =
    6622        5499 :         CreateLL(pszFilename, nXSize, nYSize, l_nBands, eType, 0,
    6623             :                  nColorTableMultiplier, papszParamList, &l_fpL, l_osTmpFilename,
    6624             :                  /* bCreateCopy=*/false, bTileInterleaving);
    6625        5499 :     const bool bStreaming = !l_osTmpFilename.empty();
    6626             : 
    6627        5499 :     if (l_hTIFF == nullptr)
    6628          37 :         return nullptr;
    6629             : 
    6630             :     /* -------------------------------------------------------------------- */
    6631             :     /*      Create the new GTiffDataset object.                             */
    6632             :     /* -------------------------------------------------------------------- */
    6633        5462 :     GTiffDataset *poDS = new GTiffDataset();
    6634        5462 :     poDS->m_hTIFF = l_hTIFF;
    6635        5462 :     poDS->m_fpL = l_fpL;
    6636        5462 :     if (bStreaming)
    6637             :     {
    6638           4 :         poDS->m_bStreamingOut = true;
    6639           4 :         poDS->m_pszTmpFilename = CPLStrdup(l_osTmpFilename);
    6640           4 :         poDS->m_fpToWrite = VSIFOpenL(pszFilename, "wb");
    6641           4 :         if (poDS->m_fpToWrite == nullptr)
    6642             :         {
    6643           1 :             VSIUnlink(l_osTmpFilename);
    6644           1 :             delete poDS;
    6645           1 :             return nullptr;
    6646             :         }
    6647             :     }
    6648        5461 :     poDS->nRasterXSize = nXSize;
    6649        5461 :     poDS->nRasterYSize = nYSize;
    6650        5461 :     poDS->eAccess = GA_Update;
    6651             : 
    6652        5461 :     poDS->m_nColorTableMultiplier = nColorTableMultiplier;
    6653             : 
    6654        5461 :     poDS->m_bCrystalized = false;
    6655        5461 :     poDS->m_nSamplesPerPixel = static_cast<uint16_t>(l_nBands);
    6656        5461 :     poDS->m_pszFilename = CPLStrdup(pszFilename);
    6657             : 
    6658             :     // Don't try to load external metadata files (#6597).
    6659        5461 :     poDS->m_bIMDRPCMetadataLoaded = true;
    6660             : 
    6661             :     // Avoid premature crystalization that will cause directory re-writing if
    6662             :     // GetProjectionRef() or GetGeoTransform() are called on the newly created
    6663             :     // GeoTIFF.
    6664        5461 :     poDS->m_bLookedForProjection = true;
    6665             : 
    6666        5461 :     TIFFGetField(l_hTIFF, TIFFTAG_SAMPLEFORMAT, &(poDS->m_nSampleFormat));
    6667        5461 :     TIFFGetField(l_hTIFF, TIFFTAG_PLANARCONFIG, &(poDS->m_nPlanarConfig));
    6668             :     // Weird that we need this, but otherwise we get a Valgrind warning on
    6669             :     // tiff_write_124.
    6670        5461 :     if (!TIFFGetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, &(poDS->m_nPhotometric)))
    6671           1 :         poDS->m_nPhotometric = PHOTOMETRIC_MINISBLACK;
    6672        5461 :     TIFFGetField(l_hTIFF, TIFFTAG_BITSPERSAMPLE, &(poDS->m_nBitsPerSample));
    6673        5461 :     TIFFGetField(l_hTIFF, TIFFTAG_COMPRESSION, &(poDS->m_nCompression));
    6674             : 
    6675        5461 :     if (TIFFIsTiled(l_hTIFF))
    6676             :     {
    6677         341 :         TIFFGetField(l_hTIFF, TIFFTAG_TILEWIDTH, &(poDS->m_nBlockXSize));
    6678         341 :         TIFFGetField(l_hTIFF, TIFFTAG_TILELENGTH, &(poDS->m_nBlockYSize));
    6679             :     }
    6680             :     else
    6681             :     {
    6682        5120 :         if (!TIFFGetField(l_hTIFF, TIFFTAG_ROWSPERSTRIP,
    6683             :                           &(poDS->m_nRowsPerStrip)))
    6684           0 :             poDS->m_nRowsPerStrip = 1;  // Dummy value.
    6685             : 
    6686        5120 :         poDS->m_nBlockXSize = nXSize;
    6687        5120 :         poDS->m_nBlockYSize =
    6688        5120 :             std::min(static_cast<int>(poDS->m_nRowsPerStrip), nYSize);
    6689             :     }
    6690             : 
    6691        5461 :     if (!poDS->ComputeBlocksPerColRowAndBand(l_nBands))
    6692             :     {
    6693           0 :         poDS->m_fpL->CancelCreation();
    6694           0 :         delete poDS;
    6695           0 :         return nullptr;
    6696             :     }
    6697             : 
    6698        5461 :     poDS->m_eProfile = GetProfile(CSLFetchNameValue(papszParamList, "PROFILE"));
    6699             : 
    6700             :     /* -------------------------------------------------------------------- */
    6701             :     /*      YCbCr JPEG compressed images should be translated on the fly    */
    6702             :     /*      to RGB by libtiff/libjpeg unless specifically requested         */
    6703             :     /*      otherwise.                                                      */
    6704             :     /* -------------------------------------------------------------------- */
    6705       10956 :     if (poDS->m_nCompression == COMPRESSION_JPEG &&
    6706        5482 :         poDS->m_nPhotometric == PHOTOMETRIC_YCBCR &&
    6707          21 :         CPLTestBool(CPLGetConfigOption("CONVERT_YCBCR_TO_RGB", "YES")))
    6708             :     {
    6709          21 :         int nColorMode = 0;
    6710             : 
    6711          21 :         poDS->SetMetadataItem("SOURCE_COLOR_SPACE", "YCbCr", "IMAGE_STRUCTURE");
    6712          42 :         if (!TIFFGetField(l_hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode) ||
    6713          21 :             nColorMode != JPEGCOLORMODE_RGB)
    6714          21 :             TIFFSetField(l_hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
    6715             :     }
    6716             : 
    6717        5461 :     if (poDS->m_nCompression == COMPRESSION_LERC)
    6718             :     {
    6719          26 :         uint32_t nLercParamCount = 0;
    6720          26 :         uint32_t *panLercParams = nullptr;
    6721          26 :         if (TIFFGetField(l_hTIFF, TIFFTAG_LERC_PARAMETERS, &nLercParamCount,
    6722          52 :                          &panLercParams) &&
    6723          26 :             nLercParamCount == 2)
    6724             :         {
    6725          26 :             memcpy(poDS->m_anLercAddCompressionAndVersion, panLercParams,
    6726             :                    sizeof(poDS->m_anLercAddCompressionAndVersion));
    6727             :         }
    6728             :     }
    6729             : 
    6730             :     /* -------------------------------------------------------------------- */
    6731             :     /*      Read palette back as a color table if it has one.               */
    6732             :     /* -------------------------------------------------------------------- */
    6733        5461 :     unsigned short *panRed = nullptr;
    6734        5461 :     unsigned short *panGreen = nullptr;
    6735        5461 :     unsigned short *panBlue = nullptr;
    6736             : 
    6737        5465 :     if (poDS->m_nPhotometric == PHOTOMETRIC_PALETTE &&
    6738           4 :         TIFFGetField(l_hTIFF, TIFFTAG_COLORMAP, &panRed, &panGreen, &panBlue))
    6739             :     {
    6740             : 
    6741           4 :         poDS->m_poColorTable = std::make_unique<GDALColorTable>();
    6742             : 
    6743           4 :         const int nColorCount = 1 << poDS->m_nBitsPerSample;
    6744             : 
    6745        1028 :         for (int iColor = nColorCount - 1; iColor >= 0; iColor--)
    6746             :         {
    6747        1024 :             const GDALColorEntry oEntry = {
    6748        1024 :                 static_cast<short>(panRed[iColor] / nColorTableMultiplier),
    6749        1024 :                 static_cast<short>(panGreen[iColor] / nColorTableMultiplier),
    6750        1024 :                 static_cast<short>(panBlue[iColor] / nColorTableMultiplier),
    6751        1024 :                 static_cast<short>(255)};
    6752             : 
    6753        1024 :             poDS->m_poColorTable->SetColorEntry(iColor, &oEntry);
    6754             :         }
    6755             :     }
    6756             : 
    6757             :     /* -------------------------------------------------------------------- */
    6758             :     /*      Do we want to ensure all blocks get written out on close to     */
    6759             :     /*      avoid sparse files?                                             */
    6760             :     /* -------------------------------------------------------------------- */
    6761        5461 :     if (!CPLFetchBool(papszParamList, "SPARSE_OK", false))
    6762        5351 :         poDS->m_bFillEmptyTilesAtClosing = true;
    6763             : 
    6764        5461 :     poDS->m_bWriteEmptyTiles =
    6765        6225 :         bStreaming || (poDS->m_nCompression != COMPRESSION_NONE &&
    6766         764 :                        poDS->m_bFillEmptyTilesAtClosing);
    6767             :     // Only required for people writing non-compressed striped files in the
    6768             :     // right order and wanting all tstrips to be written in the same order
    6769             :     // so that the end result can be memory mapped without knowledge of each
    6770             :     // strip offset.
    6771        5461 :     if (CPLTestBool(CSLFetchNameValueDef(
    6772       10922 :             papszParamList, "WRITE_EMPTY_TILES_SYNCHRONOUSLY", "FALSE")) ||
    6773        5461 :         CPLTestBool(CSLFetchNameValueDef(
    6774             :             papszParamList, "@WRITE_EMPTY_TILES_SYNCHRONOUSLY", "FALSE")))
    6775             :     {
    6776          19 :         poDS->m_bWriteEmptyTiles = true;
    6777             :     }
    6778             : 
    6779             :     /* -------------------------------------------------------------------- */
    6780             :     /*      Preserve creation options for consulting later (for instance    */
    6781             :     /*      to decide if a TFW file should be written).                     */
    6782             :     /* -------------------------------------------------------------------- */
    6783        5461 :     poDS->m_papszCreationOptions = CSLDuplicate(papszParamList);
    6784             : 
    6785        5461 :     poDS->m_nZLevel = GTiffGetZLevel(papszParamList);
    6786        5461 :     poDS->m_nLZMAPreset = GTiffGetLZMAPreset(papszParamList);
    6787        5461 :     poDS->m_nZSTDLevel = GTiffGetZSTDPreset(papszParamList);
    6788        5461 :     poDS->m_nWebPLevel = GTiffGetWebPLevel(papszParamList);
    6789        5461 :     poDS->m_bWebPLossless = GTiffGetWebPLossless(papszParamList);
    6790        5463 :     if (poDS->m_nWebPLevel != 100 && poDS->m_bWebPLossless &&
    6791           2 :         CSLFetchNameValue(papszParamList, "WEBP_LEVEL"))
    6792             :     {
    6793           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    6794             :                  "WEBP_LEVEL is specified, but WEBP_LOSSLESS=YES. "
    6795             :                  "WEBP_LEVEL will be ignored.");
    6796             :     }
    6797        5461 :     poDS->m_nJpegQuality = GTiffGetJpegQuality(papszParamList);
    6798        5461 :     poDS->m_nJpegTablesMode = GTiffGetJpegTablesMode(papszParamList);
    6799        5461 :     poDS->m_dfMaxZError = GTiffGetLERCMaxZError(papszParamList);
    6800        5461 :     poDS->m_dfMaxZErrorOverview = GTiffGetLERCMaxZErrorOverview(papszParamList);
    6801             : #if HAVE_JXL
    6802        5461 :     poDS->m_bJXLLossless = GTiffGetJXLLossless(papszParamList);
    6803        5461 :     poDS->m_nJXLEffort = GTiffGetJXLEffort(papszParamList);
    6804        5461 :     poDS->m_fJXLDistance = GTiffGetJXLDistance(papszParamList);
    6805        5461 :     poDS->m_fJXLAlphaDistance = GTiffGetJXLAlphaDistance(papszParamList);
    6806             : #endif
    6807        5461 :     poDS->InitCreationOrOpenOptions(true, papszParamList);
    6808             : 
    6809             :     /* -------------------------------------------------------------------- */
    6810             :     /*      Create band information objects.                                */
    6811             :     /* -------------------------------------------------------------------- */
    6812      307669 :     for (int iBand = 0; iBand < l_nBands; ++iBand)
    6813             :     {
    6814      302208 :         if (poDS->m_nBitsPerSample == 8 || poDS->m_nBitsPerSample == 16 ||
    6815        2584 :             poDS->m_nBitsPerSample == 32 || poDS->m_nBitsPerSample == 64 ||
    6816         237 :             poDS->m_nBitsPerSample == 128)
    6817             :         {
    6818      302143 :             poDS->SetBand(iBand + 1, new GTiffRasterBand(poDS, iBand + 1));
    6819             :         }
    6820             :         else
    6821             :         {
    6822          65 :             poDS->SetBand(iBand + 1, new GTiffOddBitsBand(poDS, iBand + 1));
    6823         130 :             poDS->GetRasterBand(iBand + 1)->SetMetadataItem(
    6824         130 :                 "NBITS", CPLString().Printf("%d", poDS->m_nBitsPerSample),
    6825          65 :                 "IMAGE_STRUCTURE");
    6826             :         }
    6827             :     }
    6828             : 
    6829        5461 :     poDS->GetDiscardLsbOption(papszParamList);
    6830             : 
    6831        5461 :     if (poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG && l_nBands != 1)
    6832         786 :         poDS->SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
    6833             :     else
    6834        4675 :         poDS->SetMetadataItem("INTERLEAVE", "BAND", "IMAGE_STRUCTURE");
    6835             : 
    6836        5461 :     poDS->oOvManager.Initialize(poDS, pszFilename);
    6837             : 
    6838        5461 :     return poDS;
    6839             : }
    6840             : 
    6841             : /************************************************************************/
    6842             : /*                           CopyImageryAndMask()                       */
    6843             : /************************************************************************/
    6844             : 
    6845         302 : CPLErr GTiffDataset::CopyImageryAndMask(GTiffDataset *poDstDS,
    6846             :                                         GDALDataset *poSrcDS,
    6847             :                                         GDALRasterBand *poSrcMaskBand,
    6848             :                                         GDALProgressFunc pfnProgress,
    6849             :                                         void *pProgressData)
    6850             : {
    6851         302 :     CPLErr eErr = CE_None;
    6852             : 
    6853         302 :     const auto eType = poDstDS->GetRasterBand(1)->GetRasterDataType();
    6854         302 :     const int nDataTypeSize = GDALGetDataTypeSizeBytes(eType);
    6855         302 :     const int l_nBands = poDstDS->GetRasterCount();
    6856             :     GByte *pBlockBuffer = static_cast<GByte *>(
    6857         302 :         VSI_MALLOC3_VERBOSE(poDstDS->m_nBlockXSize, poDstDS->m_nBlockYSize,
    6858             :                             cpl::fits_on<int>(l_nBands * nDataTypeSize)));
    6859         302 :     if (pBlockBuffer == nullptr)
    6860             :     {
    6861           0 :         eErr = CE_Failure;
    6862             :     }
    6863         302 :     const int nYSize = poDstDS->nRasterYSize;
    6864         302 :     const int nXSize = poDstDS->nRasterXSize;
    6865             :     const bool bIsOddBand =
    6866         302 :         dynamic_cast<GTiffOddBitsBand *>(poDstDS->GetRasterBand(1)) != nullptr;
    6867             : 
    6868         302 :     if (poDstDS->m_poMaskDS)
    6869             :     {
    6870          63 :         CPLAssert(poDstDS->m_poMaskDS->m_nBlockXSize == poDstDS->m_nBlockXSize);
    6871          63 :         CPLAssert(poDstDS->m_poMaskDS->m_nBlockYSize == poDstDS->m_nBlockYSize);
    6872             :     }
    6873             : 
    6874         302 :     if (poDstDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE &&
    6875          58 :         !poDstDS->m_bTileInterleave)
    6876             :     {
    6877          45 :         int iBlock = 0;
    6878          90 :         const int nBlocks = poDstDS->m_nBlocksPerBand *
    6879          45 :                             (l_nBands + (poDstDS->m_poMaskDS ? 1 : 0));
    6880         195 :         for (int i = 0; eErr == CE_None && i < l_nBands; i++)
    6881             :         {
    6882         345 :             for (int iY = 0, nYBlock = 0; iY < nYSize && eErr == CE_None;
    6883         195 :                  iY = ((nYSize - iY < poDstDS->m_nBlockYSize)
    6884         195 :                            ? nYSize
    6885          59 :                            : iY + poDstDS->m_nBlockYSize),
    6886             :                      nYBlock++)
    6887             :             {
    6888             :                 const int nReqYSize =
    6889         195 :                     std::min(nYSize - iY, poDstDS->m_nBlockYSize);
    6890         495 :                 for (int iX = 0, nXBlock = 0; iX < nXSize && eErr == CE_None;
    6891         300 :                      iX = ((nXSize - iX < poDstDS->m_nBlockXSize)
    6892         300 :                                ? nXSize
    6893         155 :                                : iX + poDstDS->m_nBlockXSize),
    6894             :                          nXBlock++)
    6895             :                 {
    6896             :                     const int nReqXSize =
    6897         300 :                         std::min(nXSize - iX, poDstDS->m_nBlockXSize);
    6898         300 :                     if (nReqXSize < poDstDS->m_nBlockXSize ||
    6899         155 :                         nReqYSize < poDstDS->m_nBlockYSize)
    6900             :                     {
    6901         190 :                         memset(pBlockBuffer, 0,
    6902         190 :                                static_cast<size_t>(poDstDS->m_nBlockXSize) *
    6903         190 :                                    poDstDS->m_nBlockYSize * nDataTypeSize);
    6904             :                     }
    6905         300 :                     eErr = poSrcDS->GetRasterBand(i + 1)->RasterIO(
    6906             :                         GF_Read, iX, iY, nReqXSize, nReqYSize, pBlockBuffer,
    6907             :                         nReqXSize, nReqYSize, eType, nDataTypeSize,
    6908         300 :                         static_cast<GSpacing>(nDataTypeSize) *
    6909         300 :                             poDstDS->m_nBlockXSize,
    6910             :                         nullptr);
    6911         300 :                     if (eErr == CE_None)
    6912             :                     {
    6913         300 :                         eErr = poDstDS->WriteEncodedTileOrStrip(
    6914             :                             iBlock, pBlockBuffer, false);
    6915             :                     }
    6916             : 
    6917         300 :                     iBlock++;
    6918         600 :                     if (pfnProgress &&
    6919         300 :                         !pfnProgress(static_cast<double>(iBlock) / nBlocks,
    6920             :                                      nullptr, pProgressData))
    6921             :                     {
    6922           0 :                         eErr = CE_Failure;
    6923             :                     }
    6924             : 
    6925         300 :                     if (poDstDS->m_bWriteError)
    6926           0 :                         eErr = CE_Failure;
    6927             :                 }
    6928             :             }
    6929             :         }
    6930          45 :         if (poDstDS->m_poMaskDS && eErr == CE_None)
    6931             :         {
    6932           6 :             int iBlockMask = 0;
    6933          17 :             for (int iY = 0, nYBlock = 0; iY < nYSize && eErr == CE_None;
    6934          11 :                  iY = ((nYSize - iY < poDstDS->m_nBlockYSize)
    6935          11 :                            ? nYSize
    6936           5 :                            : iY + poDstDS->m_nBlockYSize),
    6937             :                      nYBlock++)
    6938             :             {
    6939             :                 const int nReqYSize =
    6940          11 :                     std::min(nYSize - iY, poDstDS->m_nBlockYSize);
    6941          49 :                 for (int iX = 0, nXBlock = 0; iX < nXSize && eErr == CE_None;
    6942          38 :                      iX = ((nXSize - iX < poDstDS->m_nBlockXSize)
    6943          38 :                                ? nXSize
    6944          30 :                                : iX + poDstDS->m_nBlockXSize),
    6945             :                          nXBlock++)
    6946             :                 {
    6947             :                     const int nReqXSize =
    6948          38 :                         std::min(nXSize - iX, poDstDS->m_nBlockXSize);
    6949          38 :                     if (nReqXSize < poDstDS->m_nBlockXSize ||
    6950          30 :                         nReqYSize < poDstDS->m_nBlockYSize)
    6951             :                     {
    6952          16 :                         memset(pBlockBuffer, 0,
    6953          16 :                                static_cast<size_t>(poDstDS->m_nBlockXSize) *
    6954          16 :                                    poDstDS->m_nBlockYSize);
    6955             :                     }
    6956          76 :                     eErr = poSrcMaskBand->RasterIO(
    6957             :                         GF_Read, iX, iY, nReqXSize, nReqYSize, pBlockBuffer,
    6958             :                         nReqXSize, nReqYSize, GDT_Byte, 1,
    6959          38 :                         poDstDS->m_nBlockXSize, nullptr);
    6960          38 :                     if (eErr == CE_None)
    6961             :                     {
    6962             :                         // Avoid any attempt to load from disk
    6963          38 :                         poDstDS->m_poMaskDS->m_nLoadedBlock = iBlockMask;
    6964             :                         eErr =
    6965          38 :                             poDstDS->m_poMaskDS->GetRasterBand(1)->WriteBlock(
    6966             :                                 nXBlock, nYBlock, pBlockBuffer);
    6967          38 :                         if (eErr == CE_None)
    6968          38 :                             eErr = poDstDS->m_poMaskDS->FlushBlockBuf();
    6969             :                     }
    6970             : 
    6971          38 :                     iBlockMask++;
    6972          76 :                     if (pfnProgress &&
    6973          38 :                         !pfnProgress(static_cast<double>(iBlock + iBlockMask) /
    6974             :                                          nBlocks,
    6975             :                                      nullptr, pProgressData))
    6976             :                     {
    6977           0 :                         eErr = CE_Failure;
    6978             :                     }
    6979             : 
    6980          38 :                     if (poDstDS->m_poMaskDS->m_bWriteError)
    6981           0 :                         eErr = CE_Failure;
    6982             :                 }
    6983             :             }
    6984          45 :         }
    6985             :     }
    6986             :     else
    6987             :     {
    6988         257 :         int iBlock = 0;
    6989         257 :         const int nBlocks = poDstDS->m_nBlocksPerBand;
    6990        7005 :         for (int iY = 0, nYBlock = 0; iY < nYSize && eErr == CE_None;
    6991        6748 :              iY = ((nYSize - iY < poDstDS->m_nBlockYSize)
    6992        6748 :                        ? nYSize
    6993        6566 :                        : iY + poDstDS->m_nBlockYSize),
    6994             :                  nYBlock++)
    6995             :         {
    6996        6748 :             const int nReqYSize = std::min(nYSize - iY, poDstDS->m_nBlockYSize);
    6997       26405 :             for (int iX = 0, nXBlock = 0; iX < nXSize && eErr == CE_None;
    6998       19657 :                  iX = ((nXSize - iX < poDstDS->m_nBlockXSize)
    6999       19657 :                            ? nXSize
    7000       19404 :                            : iX + poDstDS->m_nBlockXSize),
    7001             :                      nXBlock++)
    7002             :             {
    7003             :                 const int nReqXSize =
    7004       19657 :                     std::min(nXSize - iX, poDstDS->m_nBlockXSize);
    7005       19657 :                 if (nReqXSize < poDstDS->m_nBlockXSize ||
    7006       19404 :                     nReqYSize < poDstDS->m_nBlockYSize)
    7007             :                 {
    7008         413 :                     memset(pBlockBuffer, 0,
    7009         413 :                            static_cast<size_t>(poDstDS->m_nBlockXSize) *
    7010         413 :                                poDstDS->m_nBlockYSize * l_nBands *
    7011         413 :                                nDataTypeSize);
    7012             :                 }
    7013             : 
    7014       19657 :                 if (poDstDS->m_bTileInterleave)
    7015             :                 {
    7016         114 :                     eErr = poSrcDS->RasterIO(
    7017             :                         GF_Read, iX, iY, nReqXSize, nReqYSize, pBlockBuffer,
    7018             :                         nReqXSize, nReqYSize, eType, l_nBands, nullptr,
    7019             :                         nDataTypeSize,
    7020          57 :                         static_cast<GSpacing>(nDataTypeSize) *
    7021          57 :                             poDstDS->m_nBlockXSize,
    7022          57 :                         static_cast<GSpacing>(nDataTypeSize) *
    7023          57 :                             poDstDS->m_nBlockXSize * poDstDS->m_nBlockYSize,
    7024             :                         nullptr);
    7025          57 :                     if (eErr == CE_None)
    7026             :                     {
    7027         228 :                         for (int i = 0; eErr == CE_None && i < l_nBands; i++)
    7028             :                         {
    7029         171 :                             eErr = poDstDS->WriteEncodedTileOrStrip(
    7030         171 :                                 iBlock + i * poDstDS->m_nBlocksPerBand,
    7031         171 :                                 pBlockBuffer + static_cast<size_t>(i) *
    7032         171 :                                                    poDstDS->m_nBlockXSize *
    7033         171 :                                                    poDstDS->m_nBlockYSize *
    7034         171 :                                                    nDataTypeSize,
    7035             :                                 false);
    7036             :                         }
    7037             :                     }
    7038             :                 }
    7039       19600 :                 else if (!bIsOddBand)
    7040             :                 {
    7041       39078 :                     eErr = poSrcDS->RasterIO(
    7042             :                         GF_Read, iX, iY, nReqXSize, nReqYSize, pBlockBuffer,
    7043             :                         nReqXSize, nReqYSize, eType, l_nBands, nullptr,
    7044       19539 :                         static_cast<GSpacing>(nDataTypeSize) * l_nBands,
    7045       19539 :                         static_cast<GSpacing>(nDataTypeSize) * l_nBands *
    7046       19539 :                             poDstDS->m_nBlockXSize,
    7047             :                         nDataTypeSize, nullptr);
    7048       19539 :                     if (eErr == CE_None)
    7049             :                     {
    7050       19538 :                         eErr = poDstDS->WriteEncodedTileOrStrip(
    7051             :                             iBlock, pBlockBuffer, false);
    7052             :                     }
    7053             :                 }
    7054             :                 else
    7055             :                 {
    7056             :                     // In the odd bit case, this is a bit messy to ensure
    7057             :                     // the strile gets written synchronously.
    7058             :                     // We load the content of the n-1 bands in the cache,
    7059             :                     // and for the last band we invoke WriteBlock() directly
    7060             :                     // We also force FlushBlockBuf()
    7061         122 :                     std::vector<GDALRasterBlock *> apoLockedBlocks;
    7062          91 :                     for (int i = 0; eErr == CE_None && i < l_nBands - 1; i++)
    7063             :                     {
    7064             :                         auto poBlock =
    7065          30 :                             poDstDS->GetRasterBand(i + 1)->GetLockedBlockRef(
    7066          30 :                                 nXBlock, nYBlock, TRUE);
    7067          30 :                         if (poBlock)
    7068             :                         {
    7069          60 :                             eErr = poSrcDS->GetRasterBand(i + 1)->RasterIO(
    7070             :                                 GF_Read, iX, iY, nReqXSize, nReqYSize,
    7071             :                                 poBlock->GetDataRef(), nReqXSize, nReqYSize,
    7072             :                                 eType, nDataTypeSize,
    7073          30 :                                 static_cast<GSpacing>(nDataTypeSize) *
    7074          30 :                                     poDstDS->m_nBlockXSize,
    7075             :                                 nullptr);
    7076          30 :                             poBlock->MarkDirty();
    7077          30 :                             apoLockedBlocks.emplace_back(poBlock);
    7078             :                         }
    7079             :                         else
    7080             :                         {
    7081           0 :                             eErr = CE_Failure;
    7082             :                         }
    7083             :                     }
    7084          61 :                     if (eErr == CE_None)
    7085             :                     {
    7086         122 :                         eErr = poSrcDS->GetRasterBand(l_nBands)->RasterIO(
    7087             :                             GF_Read, iX, iY, nReqXSize, nReqYSize, pBlockBuffer,
    7088             :                             nReqXSize, nReqYSize, eType, nDataTypeSize,
    7089          61 :                             static_cast<GSpacing>(nDataTypeSize) *
    7090          61 :                                 poDstDS->m_nBlockXSize,
    7091             :                             nullptr);
    7092             :                     }
    7093          61 :                     if (eErr == CE_None)
    7094             :                     {
    7095             :                         // Avoid any attempt to load from disk
    7096          61 :                         poDstDS->m_nLoadedBlock = iBlock;
    7097          61 :                         eErr = poDstDS->GetRasterBand(l_nBands)->WriteBlock(
    7098             :                             nXBlock, nYBlock, pBlockBuffer);
    7099          61 :                         if (eErr == CE_None)
    7100          61 :                             eErr = poDstDS->FlushBlockBuf();
    7101             :                     }
    7102          91 :                     for (auto poBlock : apoLockedBlocks)
    7103             :                     {
    7104          30 :                         poBlock->MarkClean();
    7105          30 :                         poBlock->DropLock();
    7106             :                     }
    7107             :                 }
    7108             : 
    7109       19657 :                 if (eErr == CE_None && poDstDS->m_poMaskDS)
    7110             :                 {
    7111        4669 :                     if (nReqXSize < poDstDS->m_nBlockXSize ||
    7112        4627 :                         nReqYSize < poDstDS->m_nBlockYSize)
    7113             :                     {
    7114          81 :                         memset(pBlockBuffer, 0,
    7115          81 :                                static_cast<size_t>(poDstDS->m_nBlockXSize) *
    7116          81 :                                    poDstDS->m_nBlockYSize);
    7117             :                     }
    7118        9338 :                     eErr = poSrcMaskBand->RasterIO(
    7119             :                         GF_Read, iX, iY, nReqXSize, nReqYSize, pBlockBuffer,
    7120             :                         nReqXSize, nReqYSize, GDT_Byte, 1,
    7121        4669 :                         poDstDS->m_nBlockXSize, nullptr);
    7122        4669 :                     if (eErr == CE_None)
    7123             :                     {
    7124             :                         // Avoid any attempt to load from disk
    7125        4669 :                         poDstDS->m_poMaskDS->m_nLoadedBlock = iBlock;
    7126             :                         eErr =
    7127        4669 :                             poDstDS->m_poMaskDS->GetRasterBand(1)->WriteBlock(
    7128             :                                 nXBlock, nYBlock, pBlockBuffer);
    7129        4669 :                         if (eErr == CE_None)
    7130        4669 :                             eErr = poDstDS->m_poMaskDS->FlushBlockBuf();
    7131             :                     }
    7132             :                 }
    7133       19657 :                 if (poDstDS->m_bWriteError)
    7134           6 :                     eErr = CE_Failure;
    7135             : 
    7136       19657 :                 iBlock++;
    7137       39314 :                 if (pfnProgress &&
    7138       19657 :                     !pfnProgress(static_cast<double>(iBlock) / nBlocks, nullptr,
    7139             :                                  pProgressData))
    7140             :                 {
    7141           0 :                     eErr = CE_Failure;
    7142             :                 }
    7143             :             }
    7144             :         }
    7145             :     }
    7146             : 
    7147         302 :     poDstDS->FlushCache(false);  // mostly to wait for thread completion
    7148         302 :     VSIFree(pBlockBuffer);
    7149             : 
    7150         302 :     return eErr;
    7151             : }
    7152             : 
    7153             : /************************************************************************/
    7154             : /*                             CreateCopy()                             */
    7155             : /************************************************************************/
    7156             : 
    7157        2040 : GDALDataset *GTiffDataset::CreateCopy(const char *pszFilename,
    7158             :                                       GDALDataset *poSrcDS, int bStrict,
    7159             :                                       char **papszOptions,
    7160             :                                       GDALProgressFunc pfnProgress,
    7161             :                                       void *pProgressData)
    7162             : 
    7163             : {
    7164        2040 :     if (poSrcDS->GetRasterCount() == 0)
    7165             :     {
    7166           2 :         ReportError(pszFilename, CE_Failure, CPLE_AppDefined,
    7167             :                     "Unable to export GeoTIFF files with zero bands.");
    7168           2 :         return nullptr;
    7169             :     }
    7170             : 
    7171        2038 :     GDALRasterBand *const poPBand = poSrcDS->GetRasterBand(1);
    7172        2038 :     GDALDataType eType = poPBand->GetRasterDataType();
    7173             : 
    7174             :     /* -------------------------------------------------------------------- */
    7175             :     /*      Check, whether all bands in input dataset has the same type.    */
    7176             :     /* -------------------------------------------------------------------- */
    7177        2038 :     const int l_nBands = poSrcDS->GetRasterCount();
    7178        4889 :     for (int iBand = 2; iBand <= l_nBands; ++iBand)
    7179             :     {
    7180        2851 :         if (eType != poSrcDS->GetRasterBand(iBand)->GetRasterDataType())
    7181             :         {
    7182           0 :             if (bStrict)
    7183             :             {
    7184           0 :                 ReportError(
    7185             :                     pszFilename, CE_Failure, CPLE_AppDefined,
    7186             :                     "Unable to export GeoTIFF file with different datatypes "
    7187             :                     "per different bands. All bands should have the same "
    7188             :                     "types in TIFF.");
    7189           0 :                 return nullptr;
    7190             :             }
    7191             :             else
    7192             :             {
    7193           0 :                 ReportError(
    7194             :                     pszFilename, CE_Warning, CPLE_AppDefined,
    7195             :                     "Unable to export GeoTIFF file with different datatypes "
    7196             :                     "per different bands. All bands should have the same "
    7197             :                     "types in TIFF.");
    7198             :             }
    7199             :         }
    7200             :     }
    7201             : 
    7202             :     /* -------------------------------------------------------------------- */
    7203             :     /*      Capture the profile.                                            */
    7204             :     /* -------------------------------------------------------------------- */
    7205             :     const GTiffProfile eProfile =
    7206        2038 :         GetProfile(CSLFetchNameValue(papszOptions, "PROFILE"));
    7207             : 
    7208        2038 :     const bool bGeoTIFF = eProfile != GTiffProfile::BASELINE;
    7209             : 
    7210             :     /* -------------------------------------------------------------------- */
    7211             :     /*      Special handling for NBITS.  Copy from band metadata if found.  */
    7212             :     /* -------------------------------------------------------------------- */
    7213        2038 :     char **papszCreateOptions = CSLDuplicate(papszOptions);
    7214             : 
    7215        2038 :     if (poPBand->GetMetadataItem("NBITS", "IMAGE_STRUCTURE") != nullptr &&
    7216        2055 :         atoi(poPBand->GetMetadataItem("NBITS", "IMAGE_STRUCTURE")) > 0 &&
    7217          17 :         CSLFetchNameValue(papszCreateOptions, "NBITS") == nullptr)
    7218             :     {
    7219           3 :         papszCreateOptions = CSLSetNameValue(
    7220             :             papszCreateOptions, "NBITS",
    7221           3 :             poPBand->GetMetadataItem("NBITS", "IMAGE_STRUCTURE"));
    7222             :     }
    7223             : 
    7224        2038 :     if (CSLFetchNameValue(papszOptions, "PIXELTYPE") == nullptr &&
    7225             :         eType == GDT_Byte)
    7226             :     {
    7227        1710 :         poPBand->EnablePixelTypeSignedByteWarning(false);
    7228             :         const char *pszPixelType =
    7229        1710 :             poPBand->GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    7230        1710 :         poPBand->EnablePixelTypeSignedByteWarning(true);
    7231        1710 :         if (pszPixelType)
    7232             :         {
    7233           1 :             papszCreateOptions =
    7234           1 :                 CSLSetNameValue(papszCreateOptions, "PIXELTYPE", pszPixelType);
    7235             :         }
    7236             :     }
    7237             : 
    7238             :     /* -------------------------------------------------------------------- */
    7239             :     /*      Color profile.  Copy from band metadata if found.              */
    7240             :     /* -------------------------------------------------------------------- */
    7241        2038 :     if (bGeoTIFF)
    7242             :     {
    7243        2021 :         const char *pszOptionsMD[] = {"SOURCE_ICC_PROFILE",
    7244             :                                       "SOURCE_PRIMARIES_RED",
    7245             :                                       "SOURCE_PRIMARIES_GREEN",
    7246             :                                       "SOURCE_PRIMARIES_BLUE",
    7247             :                                       "SOURCE_WHITEPOINT",
    7248             :                                       "TIFFTAG_TRANSFERFUNCTION_RED",
    7249             :                                       "TIFFTAG_TRANSFERFUNCTION_GREEN",
    7250             :                                       "TIFFTAG_TRANSFERFUNCTION_BLUE",
    7251             :                                       "TIFFTAG_TRANSFERRANGE_BLACK",
    7252             :                                       "TIFFTAG_TRANSFERRANGE_WHITE",
    7253             :                                       nullptr};
    7254             : 
    7255             :         // Copy all the tags.  Options will override tags in the source.
    7256        2021 :         int i = 0;
    7257       22211 :         while (pszOptionsMD[i] != nullptr)
    7258             :         {
    7259             :             char const *pszMD =
    7260       20192 :                 CSLFetchNameValue(papszOptions, pszOptionsMD[i]);
    7261       20192 :             if (pszMD == nullptr)
    7262             :                 pszMD =
    7263       20184 :                     poSrcDS->GetMetadataItem(pszOptionsMD[i], "COLOR_PROFILE");
    7264             : 
    7265       20192 :             if ((pszMD != nullptr) && !EQUAL(pszMD, ""))
    7266             :             {
    7267          16 :                 papszCreateOptions =
    7268          16 :                     CSLSetNameValue(papszCreateOptions, pszOptionsMD[i], pszMD);
    7269             : 
    7270             :                 // If an ICC profile exists, other tags are not needed.
    7271          16 :                 if (EQUAL(pszOptionsMD[i], "SOURCE_ICC_PROFILE"))
    7272           2 :                     break;
    7273             :             }
    7274             : 
    7275       20190 :             ++i;
    7276             :         }
    7277             :     }
    7278             : 
    7279        2038 :     double dfExtraSpaceForOverviews = 0;
    7280             :     const bool bCopySrcOverviews =
    7281        2038 :         CPLFetchBool(papszCreateOptions, "COPY_SRC_OVERVIEWS", false);
    7282        2038 :     std::unique_ptr<GDALDataset> poOvrDS;
    7283        2038 :     int nSrcOverviews = 0;
    7284        2038 :     if (bCopySrcOverviews)
    7285             :     {
    7286             :         const char *pszOvrDS =
    7287         187 :             CSLFetchNameValue(papszCreateOptions, "@OVERVIEW_DATASET");
    7288         187 :         if (pszOvrDS)
    7289             :         {
    7290             :             // Empty string is used by COG driver to indicate that we want
    7291             :             // to ignore source overviews.
    7292          40 :             if (!EQUAL(pszOvrDS, ""))
    7293             :             {
    7294          38 :                 poOvrDS.reset(GDALDataset::Open(pszOvrDS));
    7295          38 :                 if (!poOvrDS)
    7296             :                 {
    7297           0 :                     CSLDestroy(papszCreateOptions);
    7298           0 :                     return nullptr;
    7299             :                 }
    7300          38 :                 if (poOvrDS->GetRasterCount() != l_nBands)
    7301             :                 {
    7302           0 :                     CSLDestroy(papszCreateOptions);
    7303           0 :                     return nullptr;
    7304             :                 }
    7305          38 :                 nSrcOverviews =
    7306          38 :                     poOvrDS->GetRasterBand(1)->GetOverviewCount() + 1;
    7307             :             }
    7308             :         }
    7309             :         else
    7310             :         {
    7311         147 :             nSrcOverviews = poSrcDS->GetRasterBand(1)->GetOverviewCount();
    7312             :         }
    7313             : 
    7314             :         // Limit number of overviews if specified
    7315             :         const char *pszOverviewCount =
    7316         187 :             CSLFetchNameValue(papszCreateOptions, "@OVERVIEW_COUNT");
    7317         187 :         if (pszOverviewCount)
    7318           8 :             nSrcOverviews =
    7319           8 :                 std::max(0, std::min(nSrcOverviews, atoi(pszOverviewCount)));
    7320             : 
    7321         187 :         if (nSrcOverviews)
    7322             :         {
    7323         198 :             for (int j = 1; j <= l_nBands; ++j)
    7324             :             {
    7325             :                 const int nOtherBandOverviewCount =
    7326         131 :                     poOvrDS ? poOvrDS->GetRasterBand(j)->GetOverviewCount() + 1
    7327         181 :                             : poSrcDS->GetRasterBand(j)->GetOverviewCount();
    7328         131 :                 if (nOtherBandOverviewCount < nSrcOverviews)
    7329             :                 {
    7330           1 :                     ReportError(
    7331             :                         pszFilename, CE_Failure, CPLE_NotSupported,
    7332             :                         "COPY_SRC_OVERVIEWS cannot be used when the bands have "
    7333             :                         "not the same number of overview levels.");
    7334           1 :                     CSLDestroy(papszCreateOptions);
    7335           1 :                     return nullptr;
    7336             :                 }
    7337         392 :                 for (int i = 0; i < nSrcOverviews; ++i)
    7338             :                 {
    7339             :                     GDALRasterBand *poOvrBand =
    7340             :                         poOvrDS
    7341         372 :                             ? (i == 0 ? poOvrDS->GetRasterBand(j)
    7342         216 :                                       : poOvrDS->GetRasterBand(j)->GetOverview(
    7343         108 :                                             i - 1))
    7344         339 :                             : poSrcDS->GetRasterBand(j)->GetOverview(i);
    7345         264 :                     if (poOvrBand == nullptr)
    7346             :                     {
    7347           1 :                         ReportError(
    7348             :                             pszFilename, CE_Failure, CPLE_NotSupported,
    7349             :                             "COPY_SRC_OVERVIEWS cannot be used when one "
    7350             :                             "overview band is NULL.");
    7351           1 :                         CSLDestroy(papszCreateOptions);
    7352           1 :                         return nullptr;
    7353             :                     }
    7354             :                     GDALRasterBand *poOvrFirstBand =
    7355             :                         poOvrDS
    7356         371 :                             ? (i == 0 ? poOvrDS->GetRasterBand(1)
    7357         216 :                                       : poOvrDS->GetRasterBand(1)->GetOverview(
    7358         108 :                                             i - 1))
    7359         337 :                             : poSrcDS->GetRasterBand(1)->GetOverview(i);
    7360         525 :                     if (poOvrBand->GetXSize() != poOvrFirstBand->GetXSize() ||
    7361         262 :                         poOvrBand->GetYSize() != poOvrFirstBand->GetYSize())
    7362             :                     {
    7363           1 :                         ReportError(
    7364             :                             pszFilename, CE_Failure, CPLE_NotSupported,
    7365             :                             "COPY_SRC_OVERVIEWS cannot be used when the "
    7366             :                             "overview bands have not the same dimensions "
    7367             :                             "among bands.");
    7368           1 :                         CSLDestroy(papszCreateOptions);
    7369           1 :                         return nullptr;
    7370             :                     }
    7371             :                 }
    7372             :             }
    7373             : 
    7374         194 :             for (int i = 0; i < nSrcOverviews; ++i)
    7375             :             {
    7376             :                 GDALRasterBand *poOvrFirstBand =
    7377             :                     poOvrDS
    7378         207 :                         ? (i == 0
    7379          80 :                                ? poOvrDS->GetRasterBand(1)
    7380          42 :                                : poOvrDS->GetRasterBand(1)->GetOverview(i - 1))
    7381         174 :                         : poSrcDS->GetRasterBand(1)->GetOverview(i);
    7382         127 :                 dfExtraSpaceForOverviews +=
    7383         127 :                     static_cast<double>(poOvrFirstBand->GetXSize()) *
    7384         127 :                     poOvrFirstBand->GetYSize();
    7385             :             }
    7386          67 :             dfExtraSpaceForOverviews *=
    7387          67 :                 l_nBands * GDALGetDataTypeSizeBytes(eType);
    7388             :         }
    7389             :         else
    7390             :         {
    7391         117 :             CPLDebug("GTiff", "No source overviews to copy");
    7392             :         }
    7393             :     }
    7394             : 
    7395             : /* -------------------------------------------------------------------- */
    7396             : /*      Should we use optimized way of copying from an input JPEG       */
    7397             : /*      dataset?                                                        */
    7398             : /* -------------------------------------------------------------------- */
    7399             : 
    7400             : // TODO(schwehr): Refactor bDirectCopyFromJPEG to be a const.
    7401             : #if defined(HAVE_LIBJPEG) || defined(JPEG_DIRECT_COPY)
    7402        2035 :     bool bDirectCopyFromJPEG = false;
    7403             : #endif
    7404             : 
    7405             :     // Note: JPEG_DIRECT_COPY is not defined by default, because it is mainly
    7406             :     // useful for debugging purposes.
    7407             : #ifdef JPEG_DIRECT_COPY
    7408             :     if (CPLFetchBool(papszCreateOptions, "JPEG_DIRECT_COPY", false) &&
    7409             :         GTIFF_CanDirectCopyFromJPEG(poSrcDS, papszCreateOptions))
    7410             :     {
    7411             :         CPLDebug("GTiff", "Using special direct copy mode from a JPEG dataset");
    7412             : 
    7413             :         bDirectCopyFromJPEG = true;
    7414             :     }
    7415             : #endif
    7416             : 
    7417             : #ifdef HAVE_LIBJPEG
    7418        2035 :     bool bCopyFromJPEG = false;
    7419             : 
    7420             :     // When CreateCopy'ing() from a JPEG dataset, and asking for COMPRESS=JPEG,
    7421             :     // use DCT coefficients (unless other options are incompatible, like
    7422             :     // strip/tile dimensions, specifying JPEG_QUALITY option, incompatible
    7423             :     // PHOTOMETRIC with the source colorspace, etc.) to avoid the lossy steps
    7424             :     // involved by decompression/recompression.
    7425        4070 :     if (!bDirectCopyFromJPEG &&
    7426        2035 :         GTIFF_CanCopyFromJPEG(poSrcDS, papszCreateOptions))
    7427             :     {
    7428          12 :         CPLDebug("GTiff", "Using special copy mode from a JPEG dataset");
    7429             : 
    7430          12 :         bCopyFromJPEG = true;
    7431             :     }
    7432             : #endif
    7433             : 
    7434             :     /* -------------------------------------------------------------------- */
    7435             :     /*      If the source is RGB, then set the PHOTOMETRIC=RGB value        */
    7436             :     /* -------------------------------------------------------------------- */
    7437             : 
    7438             :     const bool bForcePhotometric =
    7439        2035 :         CSLFetchNameValue(papszOptions, "PHOTOMETRIC") != nullptr;
    7440             : 
    7441        1193 :     if (l_nBands >= 3 && !bForcePhotometric &&
    7442             : #ifdef HAVE_LIBJPEG
    7443        1155 :         !bCopyFromJPEG &&
    7444             : #endif
    7445        1149 :         poSrcDS->GetRasterBand(1)->GetColorInterpretation() == GCI_RedBand &&
    7446        4279 :         poSrcDS->GetRasterBand(2)->GetColorInterpretation() == GCI_GreenBand &&
    7447        1051 :         poSrcDS->GetRasterBand(3)->GetColorInterpretation() == GCI_BlueBand)
    7448             :     {
    7449        1045 :         papszCreateOptions =
    7450        1045 :             CSLSetNameValue(papszCreateOptions, "PHOTOMETRIC", "RGB");
    7451             :     }
    7452             : 
    7453             :     /* -------------------------------------------------------------------- */
    7454             :     /*      Create the file.                                                */
    7455             :     /* -------------------------------------------------------------------- */
    7456        2035 :     VSILFILE *l_fpL = nullptr;
    7457        4070 :     CPLString l_osTmpFilename;
    7458             : 
    7459        2035 :     const int nXSize = poSrcDS->GetRasterXSize();
    7460        2035 :     const int nYSize = poSrcDS->GetRasterYSize();
    7461             : 
    7462             :     const int nColorTableMultiplier = std::max(
    7463        4070 :         1,
    7464        4070 :         std::min(257,
    7465        2035 :                  atoi(CSLFetchNameValueDef(
    7466             :                      papszOptions, "COLOR_TABLE_MULTIPLIER",
    7467        2035 :                      CPLSPrintf("%d", DEFAULT_COLOR_TABLE_MULTIPLIER_257)))));
    7468             : 
    7469        2035 :     bool bTileInterleaving = false;
    7470        2035 :     TIFF *l_hTIFF = CreateLL(pszFilename, nXSize, nYSize, l_nBands, eType,
    7471             :                              dfExtraSpaceForOverviews, nColorTableMultiplier,
    7472             :                              papszCreateOptions, &l_fpL, l_osTmpFilename,
    7473             :                              /* bCreateCopy = */ true, bTileInterleaving);
    7474        2035 :     const bool bStreaming = !l_osTmpFilename.empty();
    7475             : 
    7476        2035 :     CSLDestroy(papszCreateOptions);
    7477        2035 :     papszCreateOptions = nullptr;
    7478             : 
    7479        2035 :     if (l_hTIFF == nullptr)
    7480             :     {
    7481          18 :         if (bStreaming)
    7482           0 :             VSIUnlink(l_osTmpFilename);
    7483          18 :         return nullptr;
    7484             :     }
    7485             : 
    7486        2017 :     uint16_t l_nPlanarConfig = 0;
    7487        2017 :     TIFFGetField(l_hTIFF, TIFFTAG_PLANARCONFIG, &l_nPlanarConfig);
    7488             : 
    7489        2017 :     uint16_t l_nCompression = 0;
    7490             : 
    7491        2017 :     if (!TIFFGetField(l_hTIFF, TIFFTAG_COMPRESSION, &(l_nCompression)))
    7492           0 :         l_nCompression = COMPRESSION_NONE;
    7493             : 
    7494             :     /* -------------------------------------------------------------------- */
    7495             :     /*      Set the alpha channel if we find one.                           */
    7496             :     /* -------------------------------------------------------------------- */
    7497        2017 :     uint16_t *extraSamples = nullptr;
    7498        2017 :     uint16_t nExtraSamples = 0;
    7499        2017 :     if (TIFFGetField(l_hTIFF, TIFFTAG_EXTRASAMPLES, &nExtraSamples,
    7500        2264 :                      &extraSamples) &&
    7501         247 :         nExtraSamples > 0)
    7502             :     {
    7503             :         // We need to allocate a new array as (current) libtiff
    7504             :         // versions will not like that we reuse the array we got from
    7505             :         // TIFFGetField().
    7506             :         uint16_t *pasNewExtraSamples = static_cast<uint16_t *>(
    7507         247 :             CPLMalloc(nExtraSamples * sizeof(uint16_t)));
    7508         247 :         memcpy(pasNewExtraSamples, extraSamples,
    7509         247 :                nExtraSamples * sizeof(uint16_t));
    7510         247 :         const char *pszAlpha = CPLGetConfigOption(
    7511             :             "GTIFF_ALPHA", CSLFetchNameValue(papszOptions, "ALPHA"));
    7512             :         const uint16_t nAlpha =
    7513         247 :             GTiffGetAlphaValue(pszAlpha, DEFAULT_ALPHA_TYPE);
    7514         247 :         const int nBaseSamples = l_nBands - nExtraSamples;
    7515         843 :         for (int iExtraBand = nBaseSamples + 1; iExtraBand <= l_nBands;
    7516             :              iExtraBand++)
    7517             :         {
    7518         596 :             if (poSrcDS->GetRasterBand(iExtraBand)->GetColorInterpretation() ==
    7519             :                 GCI_AlphaBand)
    7520             :             {
    7521         140 :                 pasNewExtraSamples[iExtraBand - nBaseSamples - 1] = nAlpha;
    7522         140 :                 if (!pszAlpha)
    7523             :                 {
    7524             :                     // Use the ALPHA metadata item from the source band, when
    7525             :                     // present, if no explicit ALPHA creation option
    7526         276 :                     pasNewExtraSamples[iExtraBand - nBaseSamples - 1] =
    7527         138 :                         GTiffGetAlphaValue(
    7528         138 :                             poSrcDS->GetRasterBand(iExtraBand)
    7529         138 :                                 ->GetMetadataItem("ALPHA", "IMAGE_STRUCTURE"),
    7530             :                             nAlpha);
    7531             :                 }
    7532             :             }
    7533             :         }
    7534         247 :         TIFFSetField(l_hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples,
    7535             :                      pasNewExtraSamples);
    7536             : 
    7537         247 :         CPLFree(pasNewExtraSamples);
    7538             :     }
    7539             : 
    7540             :     /* -------------------------------------------------------------------- */
    7541             :     /*      If the output is jpeg compressed, and the input is RGB make     */
    7542             :     /*      sure we note that.                                              */
    7543             :     /* -------------------------------------------------------------------- */
    7544             : 
    7545        2017 :     if (l_nCompression == COMPRESSION_JPEG)
    7546             :     {
    7547         134 :         if (l_nBands >= 3 &&
    7548          58 :             (poSrcDS->GetRasterBand(1)->GetColorInterpretation() ==
    7549           0 :              GCI_YCbCr_YBand) &&
    7550           0 :             (poSrcDS->GetRasterBand(2)->GetColorInterpretation() ==
    7551         134 :              GCI_YCbCr_CbBand) &&
    7552           0 :             (poSrcDS->GetRasterBand(3)->GetColorInterpretation() ==
    7553             :              GCI_YCbCr_CrBand))
    7554             :         {
    7555             :             // Do nothing.
    7556             :         }
    7557             :         else
    7558             :         {
    7559             :             // Assume RGB if it is not explicitly YCbCr.
    7560          76 :             CPLDebug("GTiff", "Setting JPEGCOLORMODE_RGB");
    7561          76 :             TIFFSetField(l_hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
    7562             :         }
    7563             :     }
    7564             : 
    7565             :     /* -------------------------------------------------------------------- */
    7566             :     /*      Does the source image consist of one band, with a palette?      */
    7567             :     /*      If so, copy over.                                               */
    7568             :     /* -------------------------------------------------------------------- */
    7569        1277 :     if ((l_nBands == 1 || l_nBands == 2) &&
    7570        3294 :         poSrcDS->GetRasterBand(1)->GetColorTable() != nullptr &&
    7571             :         eType == GDT_Byte)
    7572             :     {
    7573          16 :         unsigned short anTRed[256] = {0};
    7574          16 :         unsigned short anTGreen[256] = {0};
    7575          16 :         unsigned short anTBlue[256] = {0};
    7576          16 :         GDALColorTable *poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
    7577             : 
    7578        4112 :         for (int iColor = 0; iColor < 256; ++iColor)
    7579             :         {
    7580        4096 :             if (iColor < poCT->GetColorEntryCount())
    7581             :             {
    7582        3041 :                 GDALColorEntry sRGB = {0, 0, 0, 0};
    7583             : 
    7584        3041 :                 poCT->GetColorEntryAsRGB(iColor, &sRGB);
    7585             : 
    7586        6082 :                 anTRed[iColor] = GTiffDataset::ClampCTEntry(
    7587        3041 :                     iColor, 1, sRGB.c1, nColorTableMultiplier);
    7588        6082 :                 anTGreen[iColor] = GTiffDataset::ClampCTEntry(
    7589        3041 :                     iColor, 2, sRGB.c2, nColorTableMultiplier);
    7590        3041 :                 anTBlue[iColor] = GTiffDataset::ClampCTEntry(
    7591        3041 :                     iColor, 3, sRGB.c3, nColorTableMultiplier);
    7592             :             }
    7593             :             else
    7594             :             {
    7595        1055 :                 anTRed[iColor] = 0;
    7596        1055 :                 anTGreen[iColor] = 0;
    7597        1055 :                 anTBlue[iColor] = 0;
    7598             :             }
    7599             :         }
    7600             : 
    7601          16 :         if (!bForcePhotometric)
    7602          16 :             TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
    7603          16 :         TIFFSetField(l_hTIFF, TIFFTAG_COLORMAP, anTRed, anTGreen, anTBlue);
    7604             :     }
    7605        1276 :     else if ((l_nBands == 1 || l_nBands == 2) &&
    7606        3277 :              poSrcDS->GetRasterBand(1)->GetColorTable() != nullptr &&
    7607             :              eType == GDT_UInt16)
    7608             :     {
    7609             :         unsigned short *panTRed = static_cast<unsigned short *>(
    7610           1 :             CPLMalloc(65536 * sizeof(unsigned short)));
    7611             :         unsigned short *panTGreen = static_cast<unsigned short *>(
    7612           1 :             CPLMalloc(65536 * sizeof(unsigned short)));
    7613             :         unsigned short *panTBlue = static_cast<unsigned short *>(
    7614           1 :             CPLMalloc(65536 * sizeof(unsigned short)));
    7615             : 
    7616           1 :         GDALColorTable *poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
    7617             : 
    7618       65537 :         for (int iColor = 0; iColor < 65536; ++iColor)
    7619             :         {
    7620       65536 :             if (iColor < poCT->GetColorEntryCount())
    7621             :             {
    7622       65536 :                 GDALColorEntry sRGB = {0, 0, 0, 0};
    7623             : 
    7624       65536 :                 poCT->GetColorEntryAsRGB(iColor, &sRGB);
    7625             : 
    7626      131072 :                 panTRed[iColor] = GTiffDataset::ClampCTEntry(
    7627       65536 :                     iColor, 1, sRGB.c1, nColorTableMultiplier);
    7628      131072 :                 panTGreen[iColor] = GTiffDataset::ClampCTEntry(
    7629       65536 :                     iColor, 2, sRGB.c2, nColorTableMultiplier);
    7630       65536 :                 panTBlue[iColor] = GTiffDataset::ClampCTEntry(
    7631       65536 :                     iColor, 3, sRGB.c3, nColorTableMultiplier);
    7632             :             }
    7633             :             else
    7634             :             {
    7635           0 :                 panTRed[iColor] = 0;
    7636           0 :                 panTGreen[iColor] = 0;
    7637           0 :                 panTBlue[iColor] = 0;
    7638             :             }
    7639             :         }
    7640             : 
    7641           1 :         if (!bForcePhotometric)
    7642           1 :             TIFFSetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
    7643           1 :         TIFFSetField(l_hTIFF, TIFFTAG_COLORMAP, panTRed, panTGreen, panTBlue);
    7644             : 
    7645           1 :         CPLFree(panTRed);
    7646           1 :         CPLFree(panTGreen);
    7647           1 :         CPLFree(panTBlue);
    7648             :     }
    7649        2000 :     else if (poSrcDS->GetRasterBand(1)->GetColorTable() != nullptr)
    7650           1 :         ReportError(
    7651             :             pszFilename, CE_Failure, CPLE_AppDefined,
    7652             :             "Unable to export color table to GeoTIFF file.  Color tables "
    7653             :             "can only be written to 1 band or 2 bands Byte or "
    7654             :             "UInt16 GeoTIFF files.");
    7655             : 
    7656        2017 :     if (l_nCompression == COMPRESSION_JPEG)
    7657             :     {
    7658          76 :         uint16_t l_nPhotometric = 0;
    7659          76 :         TIFFGetField(l_hTIFF, TIFFTAG_PHOTOMETRIC, &l_nPhotometric);
    7660             :         // Check done in tif_jpeg.c later, but not with a very clear error
    7661             :         // message
    7662          76 :         if (l_nPhotometric == PHOTOMETRIC_PALETTE)
    7663             :         {
    7664           1 :             ReportError(pszFilename, CE_Failure, CPLE_NotSupported,
    7665             :                         "JPEG compression not supported with paletted image");
    7666           1 :             XTIFFClose(l_hTIFF);
    7667           1 :             VSIUnlink(l_osTmpFilename);
    7668           1 :             CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
    7669           1 :             return nullptr;
    7670             :         }
    7671             :     }
    7672             : 
    7673        2101 :     if (l_nBands == 2 &&
    7674        2016 :         poSrcDS->GetRasterBand(1)->GetColorTable() != nullptr &&
    7675           0 :         (eType == GDT_Byte || eType == GDT_UInt16))
    7676             :     {
    7677           1 :         uint16_t v[1] = {EXTRASAMPLE_UNASSALPHA};
    7678             : 
    7679           1 :         TIFFSetField(l_hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
    7680             :     }
    7681             : 
    7682        2016 :     const int nMaskFlags = poSrcDS->GetRasterBand(1)->GetMaskFlags();
    7683        2016 :     bool bCreateMask = false;
    7684        4032 :     CPLString osHiddenStructuralMD;
    7685             :     const char *pszInterleave =
    7686        2016 :         CSLFetchNameValueDef(papszOptions, "INTERLEAVE", "PIXEL");
    7687        2016 :     if (bCopySrcOverviews)
    7688             :     {
    7689         181 :         osHiddenStructuralMD += "LAYOUT=IFDS_BEFORE_DATA\n";
    7690         181 :         osHiddenStructuralMD += "BLOCK_ORDER=ROW_MAJOR\n";
    7691         181 :         osHiddenStructuralMD += "BLOCK_LEADER=SIZE_AS_UINT4\n";
    7692         181 :         osHiddenStructuralMD += "BLOCK_TRAILER=LAST_4_BYTES_REPEATED\n";
    7693         181 :         if (l_nBands > 1 && !EQUAL(pszInterleave, "PIXEL"))
    7694             :         {
    7695          22 :             osHiddenStructuralMD += "INTERLEAVE=";
    7696          22 :             osHiddenStructuralMD += CPLString(pszInterleave).toupper();
    7697          22 :             osHiddenStructuralMD += "\n";
    7698             :         }
    7699             :         osHiddenStructuralMD +=
    7700         181 :             "KNOWN_INCOMPATIBLE_EDITION=NO\n ";  // Final space intended, so
    7701             :                                                  // this can be replaced by YES
    7702             :     }
    7703        2016 :     if (!(nMaskFlags & (GMF_ALL_VALID | GMF_ALPHA | GMF_NODATA)) &&
    7704          41 :         (nMaskFlags & GMF_PER_DATASET) && !bStreaming)
    7705             :     {
    7706          38 :         bCreateMask = true;
    7707          38 :         if (GTiffDataset::MustCreateInternalMask() &&
    7708          38 :             !osHiddenStructuralMD.empty() && EQUAL(pszInterleave, "PIXEL"))
    7709             :         {
    7710          22 :             osHiddenStructuralMD += "MASK_INTERLEAVED_WITH_IMAGERY=YES\n";
    7711             :         }
    7712             :     }
    7713        2016 :     if (!osHiddenStructuralMD.empty())
    7714             :     {
    7715         181 :         const int nHiddenMDSize = static_cast<int>(osHiddenStructuralMD.size());
    7716             :         osHiddenStructuralMD =
    7717         181 :             CPLOPrintf("GDAL_STRUCTURAL_METADATA_SIZE=%06d bytes\n",
    7718         362 :                        nHiddenMDSize) +
    7719         181 :             osHiddenStructuralMD;
    7720         181 :         VSI_TIFFWrite(l_hTIFF, osHiddenStructuralMD.c_str(),
    7721             :                       osHiddenStructuralMD.size());
    7722             :     }
    7723             : 
    7724             :     // FIXME? libtiff writes extended tags in the order they are specified
    7725             :     // and not in increasing order.
    7726             : 
    7727             :     /* -------------------------------------------------------------------- */
    7728             :     /*      Transfer some TIFF specific metadata, if available.             */
    7729             :     /*      The return value will tell us if we need to try again later with*/
    7730             :     /*      PAM because the profile doesn't allow to write some metadata    */
    7731             :     /*      as TIFF tag                                                     */
    7732             :     /* -------------------------------------------------------------------- */
    7733        2016 :     const bool bHasWrittenMDInGeotiffTAG = GTiffDataset::WriteMetadata(
    7734             :         poSrcDS, l_hTIFF, false, eProfile, pszFilename, papszOptions);
    7735             : 
    7736             :     /* -------------------------------------------------------------------- */
    7737             :     /*      Write NoData value, if exist.                                   */
    7738             :     /* -------------------------------------------------------------------- */
    7739        2016 :     if (eProfile == GTiffProfile::GDALGEOTIFF)
    7740             :     {
    7741        1995 :         int bSuccess = FALSE;
    7742        1995 :         GDALRasterBand *poFirstBand = poSrcDS->GetRasterBand(1);
    7743        1995 :         if (poFirstBand->GetRasterDataType() == GDT_Int64)
    7744             :         {
    7745           2 :             const auto nNoData = poFirstBand->GetNoDataValueAsInt64(&bSuccess);
    7746           2 :             if (bSuccess)
    7747           1 :                 GTiffDataset::WriteNoDataValue(l_hTIFF, nNoData);
    7748             :         }
    7749        1993 :         else if (poFirstBand->GetRasterDataType() == GDT_UInt64)
    7750             :         {
    7751           2 :             const auto nNoData = poFirstBand->GetNoDataValueAsUInt64(&bSuccess);
    7752           2 :             if (bSuccess)
    7753           1 :                 GTiffDataset::WriteNoDataValue(l_hTIFF, nNoData);
    7754             :         }
    7755             :         else
    7756             :         {
    7757        1991 :             const auto dfNoData = poFirstBand->GetNoDataValue(&bSuccess);
    7758        1991 :             if (bSuccess)
    7759         135 :                 GTiffDataset::WriteNoDataValue(l_hTIFF, dfNoData);
    7760             :         }
    7761             :     }
    7762             : 
    7763             :     /* -------------------------------------------------------------------- */
    7764             :     /*      Are we addressing PixelIsPoint mode?                            */
    7765             :     /* -------------------------------------------------------------------- */
    7766        2016 :     bool bPixelIsPoint = false;
    7767        2016 :     bool bPointGeoIgnore = false;
    7768             : 
    7769        3394 :     if (poSrcDS->GetMetadataItem(GDALMD_AREA_OR_POINT) &&
    7770        1378 :         EQUAL(poSrcDS->GetMetadataItem(GDALMD_AREA_OR_POINT), GDALMD_AOP_POINT))
    7771             :     {
    7772          10 :         bPixelIsPoint = true;
    7773             :         bPointGeoIgnore =
    7774          10 :             CPLTestBool(CPLGetConfigOption("GTIFF_POINT_GEO_IGNORE", "FALSE"));
    7775             :     }
    7776             : 
    7777             :     /* -------------------------------------------------------------------- */
    7778             :     /*      Write affine transform if it is meaningful.                     */
    7779             :     /* -------------------------------------------------------------------- */
    7780        2016 :     const OGRSpatialReference *l_poSRS = nullptr;
    7781        2016 :     GDALGeoTransform l_gt;
    7782        2016 :     if (poSrcDS->GetGeoTransform(l_gt) == CE_None)
    7783             :     {
    7784        1597 :         if (bGeoTIFF)
    7785             :         {
    7786        1592 :             l_poSRS = poSrcDS->GetSpatialRef();
    7787             : 
    7788        1592 :             if (l_gt[2] == 0.0 && l_gt[4] == 0.0 && l_gt[5] < 0.0)
    7789             :             {
    7790        1578 :                 double dfOffset = 0.0;
    7791             :                 {
    7792             :                     // In the case the SRS has a vertical component and we have
    7793             :                     // a single band, encode its scale/offset in the GeoTIFF
    7794             :                     // tags
    7795        1578 :                     int bHasScale = FALSE;
    7796             :                     double dfScale =
    7797        1578 :                         poSrcDS->GetRasterBand(1)->GetScale(&bHasScale);
    7798        1578 :                     int bHasOffset = FALSE;
    7799             :                     dfOffset =
    7800        1578 :                         poSrcDS->GetRasterBand(1)->GetOffset(&bHasOffset);
    7801             :                     const bool bApplyScaleOffset =
    7802        1582 :                         l_poSRS && l_poSRS->IsVertical() &&
    7803           4 :                         poSrcDS->GetRasterCount() == 1;
    7804        1578 :                     if (bApplyScaleOffset && !bHasScale)
    7805           0 :                         dfScale = 1.0;
    7806        1578 :                     if (!bApplyScaleOffset || !bHasOffset)
    7807        1574 :                         dfOffset = 0.0;
    7808        1578 :                     const double adfPixelScale[3] = {l_gt[1], fabs(l_gt[5]),
    7809        1578 :                                                      bApplyScaleOffset ? dfScale
    7810        1578 :                                                                        : 0.0};
    7811             : 
    7812        1578 :                     TIFFSetField(l_hTIFF, TIFFTAG_GEOPIXELSCALE, 3,
    7813             :                                  adfPixelScale);
    7814             :                 }
    7815             : 
    7816        1578 :                 double adfTiePoints[6] = {0.0,     0.0,     0.0,
    7817        1578 :                                           l_gt[0], l_gt[3], dfOffset};
    7818             : 
    7819        1578 :                 if (bPixelIsPoint && !bPointGeoIgnore)
    7820             :                 {
    7821           6 :                     adfTiePoints[3] += l_gt[1] * 0.5 + l_gt[2] * 0.5;
    7822           6 :                     adfTiePoints[4] += l_gt[4] * 0.5 + l_gt[5] * 0.5;
    7823             :                 }
    7824             : 
    7825        1578 :                 TIFFSetField(l_hTIFF, TIFFTAG_GEOTIEPOINTS, 6, adfTiePoints);
    7826             :             }
    7827             :             else
    7828             :             {
    7829          14 :                 double adfMatrix[16] = {0.0};
    7830             : 
    7831          14 :                 adfMatrix[0] = l_gt[1];
    7832          14 :                 adfMatrix[1] = l_gt[2];
    7833          14 :                 adfMatrix[3] = l_gt[0];
    7834          14 :                 adfMatrix[4] = l_gt[4];
    7835          14 :                 adfMatrix[5] = l_gt[5];
    7836          14 :                 adfMatrix[7] = l_gt[3];
    7837          14 :                 adfMatrix[15] = 1.0;
    7838             : 
    7839          14 :                 if (bPixelIsPoint && !bPointGeoIgnore)
    7840             :                 {
    7841           0 :                     adfMatrix[3] += l_gt[1] * 0.5 + l_gt[2] * 0.5;
    7842           0 :                     adfMatrix[7] += l_gt[4] * 0.5 + l_gt[5] * 0.5;
    7843             :                 }
    7844             : 
    7845          14 :                 TIFFSetField(l_hTIFF, TIFFTAG_GEOTRANSMATRIX, 16, adfMatrix);
    7846             :             }
    7847             :         }
    7848             : 
    7849             :         /* --------------------------------------------------------------------
    7850             :          */
    7851             :         /*      Do we need a TFW file? */
    7852             :         /* --------------------------------------------------------------------
    7853             :          */
    7854        1597 :         if (CPLFetchBool(papszOptions, "TFW", false))
    7855           2 :             GDALWriteWorldFile(pszFilename, "tfw", l_gt.data());
    7856        1595 :         else if (CPLFetchBool(papszOptions, "WORLDFILE", false))
    7857           1 :             GDALWriteWorldFile(pszFilename, "wld", l_gt.data());
    7858             :     }
    7859             : 
    7860             :     /* -------------------------------------------------------------------- */
    7861             :     /*      Otherwise write tiepoints if they are available.                */
    7862             :     /* -------------------------------------------------------------------- */
    7863         419 :     else if (poSrcDS->GetGCPCount() > 0 && bGeoTIFF)
    7864             :     {
    7865          12 :         const GDAL_GCP *pasGCPs = poSrcDS->GetGCPs();
    7866             :         double *padfTiePoints = static_cast<double *>(
    7867          12 :             CPLMalloc(6 * sizeof(double) * poSrcDS->GetGCPCount()));
    7868             : 
    7869          60 :         for (int iGCP = 0; iGCP < poSrcDS->GetGCPCount(); ++iGCP)
    7870             :         {
    7871             : 
    7872          48 :             padfTiePoints[iGCP * 6 + 0] = pasGCPs[iGCP].dfGCPPixel;
    7873          48 :             padfTiePoints[iGCP * 6 + 1] = pasGCPs[iGCP].dfGCPLine;
    7874          48 :             padfTiePoints[iGCP * 6 + 2] = 0;
    7875          48 :             padfTiePoints[iGCP * 6 + 3] = pasGCPs[iGCP].dfGCPX;
    7876          48 :             padfTiePoints[iGCP * 6 + 4] = pasGCPs[iGCP].dfGCPY;
    7877          48 :             padfTiePoints[iGCP * 6 + 5] = pasGCPs[iGCP].dfGCPZ;
    7878             : 
    7879          48 :             if (bPixelIsPoint && !bPointGeoIgnore)
    7880             :             {
    7881           4 :                 padfTiePoints[iGCP * 6 + 0] -= 0.5;
    7882           4 :                 padfTiePoints[iGCP * 6 + 1] -= 0.5;
    7883             :             }
    7884             :         }
    7885             : 
    7886          12 :         TIFFSetField(l_hTIFF, TIFFTAG_GEOTIEPOINTS, 6 * poSrcDS->GetGCPCount(),
    7887             :                      padfTiePoints);
    7888          12 :         CPLFree(padfTiePoints);
    7889             : 
    7890          12 :         l_poSRS = poSrcDS->GetGCPSpatialRef();
    7891             : 
    7892          24 :         if (CPLFetchBool(papszOptions, "TFW", false) ||
    7893          12 :             CPLFetchBool(papszOptions, "WORLDFILE", false))
    7894             :         {
    7895           0 :             ReportError(
    7896             :                 pszFilename, CE_Warning, CPLE_AppDefined,
    7897             :                 "TFW=ON or WORLDFILE=ON creation options are ignored when "
    7898             :                 "GCPs are available");
    7899             :         }
    7900             :     }
    7901             :     else
    7902             :     {
    7903         407 :         l_poSRS = poSrcDS->GetSpatialRef();
    7904             :     }
    7905             : 
    7906             :     /* -------------------------------------------------------------------- */
    7907             :     /*      Copy xml:XMP data                                               */
    7908             :     /* -------------------------------------------------------------------- */
    7909        2016 :     char **papszXMP = poSrcDS->GetMetadata("xml:XMP");
    7910        2016 :     if (papszXMP != nullptr && *papszXMP != nullptr)
    7911             :     {
    7912           9 :         int nTagSize = static_cast<int>(strlen(*papszXMP));
    7913           9 :         TIFFSetField(l_hTIFF, TIFFTAG_XMLPACKET, nTagSize, *papszXMP);
    7914             :     }
    7915             : 
    7916             :     /* -------------------------------------------------------------------- */
    7917             :     /*      Write the projection information, if possible.                  */
    7918             :     /* -------------------------------------------------------------------- */
    7919        2016 :     const bool bHasProjection = l_poSRS != nullptr;
    7920        2016 :     bool bExportSRSToPAM = false;
    7921        2016 :     if ((bHasProjection || bPixelIsPoint) && bGeoTIFF)
    7922             :     {
    7923        1563 :         GTIF *psGTIF = GTiffDataset::GTIFNew(l_hTIFF);
    7924             : 
    7925        1563 :         if (bHasProjection)
    7926             :         {
    7927        1563 :             const auto eGeoTIFFKeysFlavor = GetGTIFFKeysFlavor(papszOptions);
    7928        1563 :             if (IsSRSCompatibleOfGeoTIFF(l_poSRS, eGeoTIFFKeysFlavor))
    7929             :             {
    7930        1563 :                 GTIFSetFromOGISDefnEx(
    7931             :                     psGTIF,
    7932             :                     OGRSpatialReference::ToHandle(
    7933             :                         const_cast<OGRSpatialReference *>(l_poSRS)),
    7934             :                     eGeoTIFFKeysFlavor, GetGeoTIFFVersion(papszOptions));
    7935             :             }
    7936             :             else
    7937             :             {
    7938           0 :                 bExportSRSToPAM = true;
    7939             :             }
    7940             :         }
    7941             : 
    7942        1563 :         if (bPixelIsPoint)
    7943             :         {
    7944          10 :             GTIFKeySet(psGTIF, GTRasterTypeGeoKey, TYPE_SHORT, 1,
    7945             :                        RasterPixelIsPoint);
    7946             :         }
    7947             : 
    7948        1563 :         GTIFWriteKeys(psGTIF);
    7949        1563 :         GTIFFree(psGTIF);
    7950             :     }
    7951             : 
    7952        2016 :     bool l_bDontReloadFirstBlock = false;
    7953             : 
    7954             : #ifdef HAVE_LIBJPEG
    7955        2016 :     if (bCopyFromJPEG)
    7956             :     {
    7957          12 :         GTIFF_CopyFromJPEG_WriteAdditionalTags(l_hTIFF, poSrcDS);
    7958             :     }
    7959             : #endif
    7960             : 
    7961             :     /* -------------------------------------------------------------------- */
    7962             :     /*      Cleanup                                                         */
    7963             :     /* -------------------------------------------------------------------- */
    7964        2016 :     if (bCopySrcOverviews)
    7965             :     {
    7966         181 :         TIFFDeferStrileArrayWriting(l_hTIFF);
    7967             :     }
    7968        2016 :     TIFFWriteCheck(l_hTIFF, TIFFIsTiled(l_hTIFF), "GTiffCreateCopy()");
    7969        2016 :     TIFFWriteDirectory(l_hTIFF);
    7970        2016 :     if (bStreaming)
    7971             :     {
    7972             :         // We need to write twice the directory to be sure that custom
    7973             :         // TIFF tags are correctly sorted and that padding bytes have been
    7974             :         // added.
    7975           5 :         TIFFSetDirectory(l_hTIFF, 0);
    7976           5 :         TIFFWriteDirectory(l_hTIFF);
    7977             : 
    7978           5 :         if (VSIFSeekL(l_fpL, 0, SEEK_END) != 0)
    7979           0 :             ReportError(pszFilename, CE_Failure, CPLE_FileIO, "Cannot seek");
    7980           5 :         const int nSize = static_cast<int>(VSIFTellL(l_fpL));
    7981             : 
    7982           5 :         vsi_l_offset nDataLength = 0;
    7983           5 :         VSIGetMemFileBuffer(l_osTmpFilename, &nDataLength, FALSE);
    7984           5 :         TIFFSetDirectory(l_hTIFF, 0);
    7985           5 :         GTiffFillStreamableOffsetAndCount(l_hTIFF, nSize);
    7986           5 :         TIFFWriteDirectory(l_hTIFF);
    7987             :     }
    7988        2016 :     const auto nDirCount = TIFFNumberOfDirectories(l_hTIFF);
    7989        2016 :     if (nDirCount >= 1)
    7990             :     {
    7991        2009 :         TIFFSetDirectory(l_hTIFF, static_cast<tdir_t>(nDirCount - 1));
    7992             :     }
    7993        2016 :     const toff_t l_nDirOffset = TIFFCurrentDirOffset(l_hTIFF);
    7994        2016 :     TIFFFlush(l_hTIFF);
    7995        2016 :     XTIFFClose(l_hTIFF);
    7996             : 
    7997        2016 :     VSIFSeekL(l_fpL, 0, SEEK_SET);
    7998             : 
    7999             :     // fpStreaming will assigned to the instance and not closed here.
    8000        2016 :     VSILFILE *fpStreaming = nullptr;
    8001        2016 :     if (bStreaming)
    8002             :     {
    8003           5 :         vsi_l_offset nDataLength = 0;
    8004             :         void *pabyBuffer =
    8005           5 :             VSIGetMemFileBuffer(l_osTmpFilename, &nDataLength, FALSE);
    8006           5 :         fpStreaming = VSIFOpenL(pszFilename, "wb");
    8007           5 :         if (fpStreaming == nullptr)
    8008             :         {
    8009           1 :             VSIUnlink(l_osTmpFilename);
    8010           1 :             CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
    8011           1 :             return nullptr;
    8012             :         }
    8013           4 :         if (static_cast<vsi_l_offset>(VSIFWriteL(pabyBuffer, 1,
    8014             :                                                  static_cast<int>(nDataLength),
    8015           4 :                                                  fpStreaming)) != nDataLength)
    8016             :         {
    8017           0 :             ReportError(pszFilename, CE_Failure, CPLE_FileIO,
    8018             :                         "Could not write %d bytes",
    8019             :                         static_cast<int>(nDataLength));
    8020           0 :             CPL_IGNORE_RET_VAL(VSIFCloseL(fpStreaming));
    8021           0 :             VSIUnlink(l_osTmpFilename);
    8022           0 :             CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
    8023           0 :             return nullptr;
    8024             :         }
    8025             :     }
    8026             : 
    8027             :     /* -------------------------------------------------------------------- */
    8028             :     /*      Re-open as a dataset and copy over missing metadata using       */
    8029             :     /*      PAM facilities.                                                 */
    8030             :     /* -------------------------------------------------------------------- */
    8031        2015 :     l_hTIFF = VSI_TIFFOpen(bStreaming ? l_osTmpFilename.c_str() : pszFilename,
    8032             :                            "r+", l_fpL);
    8033        2015 :     if (l_hTIFF == nullptr)
    8034             :     {
    8035          11 :         if (bStreaming)
    8036           0 :             VSIUnlink(l_osTmpFilename);
    8037          11 :         l_fpL->CancelCreation();
    8038          11 :         CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
    8039          11 :         return nullptr;
    8040             :     }
    8041             : 
    8042             :     /* -------------------------------------------------------------------- */
    8043             :     /*      Create a corresponding GDALDataset.                             */
    8044             :     /* -------------------------------------------------------------------- */
    8045        2004 :     GTiffDataset *poDS = new GTiffDataset();
    8046        2004 :     poDS->SetDescription(pszFilename);
    8047        2004 :     poDS->eAccess = GA_Update;
    8048        2004 :     poDS->m_pszFilename = CPLStrdup(pszFilename);
    8049        2004 :     poDS->m_fpL = l_fpL;
    8050        2004 :     poDS->m_bIMDRPCMetadataLoaded = true;
    8051        2004 :     poDS->m_nColorTableMultiplier = nColorTableMultiplier;
    8052        2004 :     poDS->m_bTileInterleave = bTileInterleaving;
    8053             : 
    8054        2004 :     if (bTileInterleaving)
    8055             :     {
    8056           7 :         poDS->m_oGTiffMDMD.SetMetadataItem("INTERLEAVE", "TILE",
    8057             :                                            "IMAGE_STRUCTURE");
    8058             :     }
    8059             : 
    8060        2004 :     const bool bAppend = CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false);
    8061        4007 :     if (poDS->OpenOffset(l_hTIFF,
    8062        2003 :                          bAppend ? l_nDirOffset : TIFFCurrentDirOffset(l_hTIFF),
    8063             :                          GA_Update,
    8064             :                          false,  // bAllowRGBAInterface
    8065             :                          true    // bReadGeoTransform
    8066        2004 :                          ) != CE_None)
    8067             :     {
    8068           0 :         l_fpL->CancelCreation();
    8069           0 :         delete poDS;
    8070           0 :         if (bStreaming)
    8071           0 :             VSIUnlink(l_osTmpFilename);
    8072           0 :         return nullptr;
    8073             :     }
    8074             : 
    8075             :     // Legacy... Patch back GDT_Int8 type to GDT_Byte if the user used
    8076             :     // PIXELTYPE=SIGNEDBYTE
    8077        2004 :     const char *pszPixelType = CSLFetchNameValue(papszOptions, "PIXELTYPE");
    8078        2004 :     if (pszPixelType == nullptr)
    8079        1999 :         pszPixelType = "";
    8080        2004 :     if (eType == GDT_Byte && EQUAL(pszPixelType, "SIGNEDBYTE"))
    8081             :     {
    8082          10 :         for (int i = 0; i < poDS->nBands; ++i)
    8083             :         {
    8084           5 :             auto poBand = static_cast<GTiffRasterBand *>(poDS->papoBands[i]);
    8085           5 :             poBand->eDataType = GDT_Byte;
    8086           5 :             poBand->EnablePixelTypeSignedByteWarning(false);
    8087           5 :             poBand->SetMetadataItem("PIXELTYPE", "SIGNEDBYTE",
    8088             :                                     "IMAGE_STRUCTURE");
    8089           5 :             poBand->EnablePixelTypeSignedByteWarning(true);
    8090             :         }
    8091             :     }
    8092             : 
    8093        2004 :     poDS->oOvManager.Initialize(poDS, pszFilename);
    8094             : 
    8095        2004 :     if (bStreaming)
    8096             :     {
    8097           4 :         VSIUnlink(l_osTmpFilename);
    8098           4 :         poDS->m_fpToWrite = fpStreaming;
    8099             :     }
    8100        2004 :     poDS->m_eProfile = eProfile;
    8101             : 
    8102        2004 :     int nCloneInfoFlags = GCIF_PAM_DEFAULT & ~GCIF_MASK;
    8103             : 
    8104             :     // If we explicitly asked not to tag the alpha band as such, do not
    8105             :     // reintroduce this alpha color interpretation in PAM.
    8106        2004 :     if (poSrcDS->GetRasterBand(l_nBands)->GetColorInterpretation() ==
    8107        2126 :             GCI_AlphaBand &&
    8108         122 :         GTiffGetAlphaValue(
    8109             :             CPLGetConfigOption("GTIFF_ALPHA",
    8110             :                                CSLFetchNameValue(papszOptions, "ALPHA")),
    8111             :             DEFAULT_ALPHA_TYPE) == EXTRASAMPLE_UNSPECIFIED)
    8112             :     {
    8113           1 :         nCloneInfoFlags &= ~GCIF_COLORINTERP;
    8114             :     }
    8115             :     // Ignore source band color interpretation if requesting PHOTOMETRIC=RGB
    8116        3193 :     else if (l_nBands >= 3 &&
    8117        1190 :              EQUAL(CSLFetchNameValueDef(papszOptions, "PHOTOMETRIC", ""),
    8118             :                    "RGB"))
    8119             :     {
    8120          28 :         for (int i = 1; i <= 3; i++)
    8121             :         {
    8122          21 :             poDS->GetRasterBand(i)->SetColorInterpretation(
    8123          21 :                 static_cast<GDALColorInterp>(GCI_RedBand + (i - 1)));
    8124             :         }
    8125           7 :         nCloneInfoFlags &= ~GCIF_COLORINTERP;
    8126           9 :         if (!(l_nBands == 4 &&
    8127           2 :               CSLFetchNameValue(papszOptions, "ALPHA") != nullptr))
    8128             :         {
    8129          15 :             for (int i = 4; i <= l_nBands; i++)
    8130             :             {
    8131          18 :                 poDS->GetRasterBand(i)->SetColorInterpretation(
    8132           9 :                     poSrcDS->GetRasterBand(i)->GetColorInterpretation());
    8133             :             }
    8134             :         }
    8135             :     }
    8136             : 
    8137             :     CPLString osOldGTIFF_REPORT_COMPD_CSVal(
    8138        4008 :         CPLGetConfigOption("GTIFF_REPORT_COMPD_CS", ""));
    8139        2004 :     CPLSetThreadLocalConfigOption("GTIFF_REPORT_COMPD_CS", "YES");
    8140        2004 :     poDS->CloneInfo(poSrcDS, nCloneInfoFlags);
    8141        2004 :     CPLSetThreadLocalConfigOption("GTIFF_REPORT_COMPD_CS",
    8142        2004 :                                   osOldGTIFF_REPORT_COMPD_CSVal.empty()
    8143             :                                       ? nullptr
    8144           0 :                                       : osOldGTIFF_REPORT_COMPD_CSVal.c_str());
    8145             : 
    8146        2021 :     if ((!bGeoTIFF || bExportSRSToPAM) &&
    8147          17 :         (poDS->GetPamFlags() & GPF_DISABLED) == 0)
    8148             :     {
    8149             :         // Copy georeferencing info to PAM if the profile is not GeoTIFF
    8150          16 :         poDS->GDALPamDataset::SetSpatialRef(poDS->GetSpatialRef());
    8151          16 :         GDALGeoTransform gt;
    8152          16 :         if (poDS->GetGeoTransform(gt) == CE_None)
    8153             :         {
    8154           5 :             poDS->GDALPamDataset::SetGeoTransform(gt);
    8155             :         }
    8156          16 :         poDS->GDALPamDataset::SetGCPs(poDS->GetGCPCount(), poDS->GetGCPs(),
    8157             :                                       poDS->GetGCPSpatialRef());
    8158             :     }
    8159             : 
    8160        2004 :     poDS->m_papszCreationOptions = CSLDuplicate(papszOptions);
    8161        2004 :     poDS->m_bDontReloadFirstBlock = l_bDontReloadFirstBlock;
    8162             : 
    8163             :     /* -------------------------------------------------------------------- */
    8164             :     /*      CloneInfo() does not merge metadata, it just replaces it        */
    8165             :     /*      totally.  So we have to merge it.                               */
    8166             :     /* -------------------------------------------------------------------- */
    8167             : 
    8168        2004 :     char **papszSRC_MD = poSrcDS->GetMetadata();
    8169        2004 :     char **papszDST_MD = CSLDuplicate(poDS->GetMetadata());
    8170             : 
    8171        2004 :     papszDST_MD = CSLMerge(papszDST_MD, papszSRC_MD);
    8172             : 
    8173        2004 :     poDS->SetMetadata(papszDST_MD);
    8174        2004 :     CSLDestroy(papszDST_MD);
    8175             : 
    8176             :     // Depending on the PHOTOMETRIC tag, the TIFF file may not have the same
    8177             :     // band count as the source. Will fail later in GDALDatasetCopyWholeRaster
    8178             :     // anyway.
    8179        6853 :     for (int nBand = 1;
    8180        6853 :          nBand <= std::min(poDS->GetRasterCount(), poSrcDS->GetRasterCount());
    8181             :          ++nBand)
    8182             :     {
    8183        4849 :         GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(nBand);
    8184        4849 :         GDALRasterBand *poDstBand = poDS->GetRasterBand(nBand);
    8185        4849 :         papszSRC_MD = poSrcBand->GetMetadata();
    8186        4849 :         papszDST_MD = CSLDuplicate(poDstBand->GetMetadata());
    8187             : 
    8188        4849 :         papszDST_MD = CSLMerge(papszDST_MD, papszSRC_MD);
    8189             : 
    8190        4849 :         poDstBand->SetMetadata(papszDST_MD);
    8191        4849 :         CSLDestroy(papszDST_MD);
    8192             : 
    8193        4849 :         char **papszCatNames = poSrcBand->GetCategoryNames();
    8194        4849 :         if (nullptr != papszCatNames)
    8195           0 :             poDstBand->SetCategoryNames(papszCatNames);
    8196             :     }
    8197             : 
    8198        2004 :     l_hTIFF = static_cast<TIFF *>(poDS->GetInternalHandle("TIFF_HANDLE"));
    8199             : 
    8200             :     /* -------------------------------------------------------------------- */
    8201             :     /*      Handle forcing xml:ESRI data to be written to PAM.              */
    8202             :     /* -------------------------------------------------------------------- */
    8203        2004 :     if (CPLTestBool(CPLGetConfigOption("ESRI_XML_PAM", "NO")))
    8204             :     {
    8205           1 :         char **papszESRIMD = poSrcDS->GetMetadata("xml:ESRI");
    8206           1 :         if (papszESRIMD)
    8207             :         {
    8208           1 :             poDS->SetMetadata(papszESRIMD, "xml:ESRI");
    8209             :         }
    8210             :     }
    8211             : 
    8212             :     /* -------------------------------------------------------------------- */
    8213             :     /*      Second chance: now that we have a PAM dataset, it is possible   */
    8214             :     /*      to write metadata that we could not write as a TIFF tag.        */
    8215             :     /* -------------------------------------------------------------------- */
    8216        2004 :     if (!bHasWrittenMDInGeotiffTAG && !bStreaming)
    8217             :     {
    8218           6 :         GTiffDataset::WriteMetadata(
    8219             :             poDS, l_hTIFF, true, eProfile, pszFilename, papszOptions,
    8220             :             true /* don't write RPC and IMD file again */);
    8221             :     }
    8222             : 
    8223        2004 :     if (!bStreaming)
    8224        2000 :         GTiffDataset::WriteRPC(poDS, l_hTIFF, true, eProfile, pszFilename,
    8225             :                                papszOptions,
    8226             :                                true /* write only in PAM AND if needed */);
    8227             : 
    8228             :     // Propagate ISIS3 or VICAR metadata, but only as PAM metadata.
    8229        6012 :     for (const char *pszMDD : {"json:ISIS3", "json:VICAR"})
    8230             :     {
    8231        4008 :         char **papszMD = poSrcDS->GetMetadata(pszMDD);
    8232        4008 :         if (papszMD)
    8233             :         {
    8234           3 :             poDS->SetMetadata(papszMD, pszMDD);
    8235           3 :             poDS->PushMetadataToPam();
    8236             :         }
    8237             :     }
    8238             : 
    8239        2004 :     poDS->m_bWriteCOGLayout = bCopySrcOverviews;
    8240             : 
    8241             :     // To avoid unnecessary directory rewriting.
    8242        2004 :     poDS->m_bMetadataChanged = false;
    8243        2004 :     poDS->m_bGeoTIFFInfoChanged = false;
    8244        2004 :     poDS->m_bNoDataChanged = false;
    8245        2004 :     poDS->m_bForceUnsetGTOrGCPs = false;
    8246        2004 :     poDS->m_bForceUnsetProjection = false;
    8247        2004 :     poDS->m_bStreamingOut = bStreaming;
    8248             : 
    8249             :     // Don't try to load external metadata files (#6597).
    8250        2004 :     poDS->m_bIMDRPCMetadataLoaded = true;
    8251             : 
    8252             :     // We must re-set the compression level at this point, since it has been
    8253             :     // lost a few lines above when closing the newly create TIFF file The
    8254             :     // TIFFTAG_ZIPQUALITY & TIFFTAG_JPEGQUALITY are not store in the TIFF file.
    8255             :     // They are just TIFF session parameters.
    8256             : 
    8257        2004 :     poDS->m_nZLevel = GTiffGetZLevel(papszOptions);
    8258        2004 :     poDS->m_nLZMAPreset = GTiffGetLZMAPreset(papszOptions);
    8259        2004 :     poDS->m_nZSTDLevel = GTiffGetZSTDPreset(papszOptions);
    8260        2004 :     poDS->m_nWebPLevel = GTiffGetWebPLevel(papszOptions);
    8261        2004 :     poDS->m_bWebPLossless = GTiffGetWebPLossless(papszOptions);
    8262        2007 :     if (poDS->m_nWebPLevel != 100 && poDS->m_bWebPLossless &&
    8263           3 :         CSLFetchNameValue(papszOptions, "WEBP_LEVEL"))
    8264             :     {
    8265           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    8266             :                  "WEBP_LEVEL is specified, but WEBP_LOSSLESS=YES. "
    8267             :                  "WEBP_LEVEL will be ignored.");
    8268             :     }
    8269        2004 :     poDS->m_nJpegQuality = GTiffGetJpegQuality(papszOptions);
    8270        2004 :     poDS->m_nJpegTablesMode = GTiffGetJpegTablesMode(papszOptions);
    8271        2004 :     poDS->GetDiscardLsbOption(papszOptions);
    8272        2004 :     poDS->m_dfMaxZError = GTiffGetLERCMaxZError(papszOptions);
    8273        2004 :     poDS->m_dfMaxZErrorOverview = GTiffGetLERCMaxZErrorOverview(papszOptions);
    8274             : #if HAVE_JXL
    8275        2004 :     poDS->m_bJXLLossless = GTiffGetJXLLossless(papszOptions);
    8276        2004 :     poDS->m_nJXLEffort = GTiffGetJXLEffort(papszOptions);
    8277        2004 :     poDS->m_fJXLDistance = GTiffGetJXLDistance(papszOptions);
    8278        2004 :     poDS->m_fJXLAlphaDistance = GTiffGetJXLAlphaDistance(papszOptions);
    8279             : #endif
    8280        2004 :     poDS->InitCreationOrOpenOptions(true, papszOptions);
    8281             : 
    8282        2004 :     if (l_nCompression == COMPRESSION_ADOBE_DEFLATE ||
    8283        1979 :         l_nCompression == COMPRESSION_LERC)
    8284             :     {
    8285          96 :         GTiffSetDeflateSubCodec(l_hTIFF);
    8286             : 
    8287          96 :         if (poDS->m_nZLevel != -1)
    8288             :         {
    8289          12 :             TIFFSetField(l_hTIFF, TIFFTAG_ZIPQUALITY, poDS->m_nZLevel);
    8290             :         }
    8291             :     }
    8292        2004 :     if (l_nCompression == COMPRESSION_JPEG)
    8293             :     {
    8294          75 :         if (poDS->m_nJpegQuality != -1)
    8295             :         {
    8296           9 :             TIFFSetField(l_hTIFF, TIFFTAG_JPEGQUALITY, poDS->m_nJpegQuality);
    8297             :         }
    8298          75 :         TIFFSetField(l_hTIFF, TIFFTAG_JPEGTABLESMODE, poDS->m_nJpegTablesMode);
    8299             :     }
    8300        2004 :     if (l_nCompression == COMPRESSION_LZMA)
    8301             :     {
    8302           7 :         if (poDS->m_nLZMAPreset != -1)
    8303             :         {
    8304           6 :             TIFFSetField(l_hTIFF, TIFFTAG_LZMAPRESET, poDS->m_nLZMAPreset);
    8305             :         }
    8306             :     }
    8307        2004 :     if (l_nCompression == COMPRESSION_ZSTD ||
    8308        1996 :         l_nCompression == COMPRESSION_LERC)
    8309             :     {
    8310          79 :         if (poDS->m_nZSTDLevel != -1)
    8311             :         {
    8312           8 :             TIFFSetField(l_hTIFF, TIFFTAG_ZSTD_LEVEL, poDS->m_nZSTDLevel);
    8313             :         }
    8314             :     }
    8315        2004 :     if (l_nCompression == COMPRESSION_LERC)
    8316             :     {
    8317          71 :         TIFFSetField(l_hTIFF, TIFFTAG_LERC_MAXZERROR, poDS->m_dfMaxZError);
    8318             :     }
    8319             : #if HAVE_JXL
    8320        2004 :     if (l_nCompression == COMPRESSION_JXL ||
    8321        2004 :         l_nCompression == COMPRESSION_JXL_DNG_1_7)
    8322             :     {
    8323          88 :         TIFFSetField(l_hTIFF, TIFFTAG_JXL_LOSSYNESS,
    8324          88 :                      poDS->m_bJXLLossless ? JXL_LOSSLESS : JXL_LOSSY);
    8325          88 :         TIFFSetField(l_hTIFF, TIFFTAG_JXL_EFFORT, poDS->m_nJXLEffort);
    8326          88 :         TIFFSetField(l_hTIFF, TIFFTAG_JXL_DISTANCE, poDS->m_fJXLDistance);
    8327          88 :         TIFFSetField(l_hTIFF, TIFFTAG_JXL_ALPHA_DISTANCE,
    8328          88 :                      poDS->m_fJXLAlphaDistance);
    8329             :     }
    8330             : #endif
    8331        2004 :     if (l_nCompression == COMPRESSION_WEBP)
    8332             :     {
    8333          14 :         if (poDS->m_nWebPLevel != -1)
    8334             :         {
    8335          14 :             TIFFSetField(l_hTIFF, TIFFTAG_WEBP_LEVEL, poDS->m_nWebPLevel);
    8336             :         }
    8337             : 
    8338          14 :         if (poDS->m_bWebPLossless)
    8339             :         {
    8340           5 :             TIFFSetField(l_hTIFF, TIFFTAG_WEBP_LOSSLESS, poDS->m_bWebPLossless);
    8341             :         }
    8342             :     }
    8343             : 
    8344             :     /* -------------------------------------------------------------------- */
    8345             :     /*      Do we want to ensure all blocks get written out on close to     */
    8346             :     /*      avoid sparse files?                                             */
    8347             :     /* -------------------------------------------------------------------- */
    8348        2004 :     if (!CPLFetchBool(papszOptions, "SPARSE_OK", false))
    8349        1976 :         poDS->m_bFillEmptyTilesAtClosing = true;
    8350             : 
    8351        2004 :     poDS->m_bWriteEmptyTiles =
    8352        3831 :         (bCopySrcOverviews && poDS->m_bFillEmptyTilesAtClosing) || bStreaming ||
    8353        1827 :         (poDS->m_nCompression != COMPRESSION_NONE &&
    8354         300 :          poDS->m_bFillEmptyTilesAtClosing);
    8355             :     // Only required for people writing non-compressed striped files in the
    8356             :     // rightorder and wanting all tstrips to be written in the same order
    8357             :     // so that the end result can be memory mapped without knowledge of each
    8358             :     // strip offset
    8359        2004 :     if (CPLTestBool(CSLFetchNameValueDef(
    8360        4008 :             papszOptions, "WRITE_EMPTY_TILES_SYNCHRONOUSLY", "FALSE")) ||
    8361        2004 :         CPLTestBool(CSLFetchNameValueDef(
    8362             :             papszOptions, "@WRITE_EMPTY_TILES_SYNCHRONOUSLY", "FALSE")))
    8363             :     {
    8364           0 :         poDS->m_bWriteEmptyTiles = true;
    8365             :     }
    8366             : 
    8367             :     // Precreate (internal) mask, so that the IBuildOverviews() below
    8368             :     // has a chance to create also the overviews of the mask.
    8369        2004 :     CPLErr eErr = CE_None;
    8370             : 
    8371        2004 :     if (bCreateMask)
    8372             :     {
    8373          38 :         eErr = poDS->CreateMaskBand(nMaskFlags);
    8374          38 :         if (poDS->m_poMaskDS)
    8375             :         {
    8376          37 :             poDS->m_poMaskDS->m_bFillEmptyTilesAtClosing =
    8377          37 :                 poDS->m_bFillEmptyTilesAtClosing;
    8378          37 :             poDS->m_poMaskDS->m_bWriteEmptyTiles = poDS->m_bWriteEmptyTiles;
    8379             :         }
    8380             :     }
    8381             : 
    8382             :     /* -------------------------------------------------------------------- */
    8383             :     /*      Create and then copy existing overviews if requested            */
    8384             :     /*  We do it such that all the IFDs are at the beginning of the file,   */
    8385             :     /*  and that the imagery data for the smallest overview is written      */
    8386             :     /*  first, that way the file is more usable when embedded in a          */
    8387             :     /*  compressed stream.                                                  */
    8388             :     /* -------------------------------------------------------------------- */
    8389             : 
    8390             :     // For scaled progress due to overview copying.
    8391        2004 :     const int nBandsWidthMask = l_nBands + (bCreateMask ? 1 : 0);
    8392        2004 :     double dfTotalPixels =
    8393        2004 :         static_cast<double>(nXSize) * nYSize * nBandsWidthMask;
    8394        2004 :     double dfCurPixels = 0;
    8395             : 
    8396        2004 :     if (eErr == CE_None && bCopySrcOverviews)
    8397             :     {
    8398           0 :         std::unique_ptr<GDALDataset> poMaskOvrDS;
    8399             :         const char *pszMaskOvrDS =
    8400         178 :             CSLFetchNameValue(papszOptions, "@MASK_OVERVIEW_DATASET");
    8401         178 :         if (pszMaskOvrDS)
    8402             :         {
    8403          10 :             poMaskOvrDS.reset(GDALDataset::Open(pszMaskOvrDS));
    8404          10 :             if (!poMaskOvrDS)
    8405             :             {
    8406           0 :                 l_fpL->CancelCreation();
    8407           0 :                 delete poDS;
    8408           0 :                 return nullptr;
    8409             :             }
    8410          10 :             if (poMaskOvrDS->GetRasterCount() != 1)
    8411             :             {
    8412           0 :                 l_fpL->CancelCreation();
    8413           0 :                 delete poDS;
    8414           0 :                 return nullptr;
    8415             :             }
    8416             :         }
    8417         178 :         if (nSrcOverviews)
    8418             :         {
    8419          66 :             eErr = poDS->CreateOverviewsFromSrcOverviews(poSrcDS, poOvrDS.get(),
    8420             :                                                          nSrcOverviews);
    8421             : 
    8422         188 :             if (eErr == CE_None &&
    8423          66 :                 (poMaskOvrDS != nullptr ||
    8424          56 :                  (poSrcDS->GetRasterBand(1)->GetOverview(0) &&
    8425          29 :                   poSrcDS->GetRasterBand(1)->GetOverview(0)->GetMaskFlags() ==
    8426             :                       GMF_PER_DATASET)))
    8427             :             {
    8428          19 :                 int nOvrBlockXSize = 0;
    8429          19 :                 int nOvrBlockYSize = 0;
    8430          19 :                 GTIFFGetOverviewBlockSize(
    8431             :                     GDALRasterBand::ToHandle(poDS->GetRasterBand(1)),
    8432             :                     &nOvrBlockXSize, &nOvrBlockYSize);
    8433          19 :                 eErr = poDS->CreateInternalMaskOverviews(nOvrBlockXSize,
    8434             :                                                          nOvrBlockYSize);
    8435             :             }
    8436             :         }
    8437             : 
    8438         178 :         TIFFForceStrileArrayWriting(poDS->m_hTIFF);
    8439             : 
    8440         178 :         if (poDS->m_poMaskDS)
    8441             :         {
    8442          27 :             TIFFForceStrileArrayWriting(poDS->m_poMaskDS->m_hTIFF);
    8443             :         }
    8444             : 
    8445         303 :         for (int i = 0; i < poDS->m_nOverviewCount; i++)
    8446             :         {
    8447         125 :             TIFFForceStrileArrayWriting(poDS->m_papoOverviewDS[i]->m_hTIFF);
    8448             : 
    8449         125 :             if (poDS->m_papoOverviewDS[i]->m_poMaskDS)
    8450             :             {
    8451          36 :                 TIFFForceStrileArrayWriting(
    8452          36 :                     poDS->m_papoOverviewDS[i]->m_poMaskDS->m_hTIFF);
    8453             :             }
    8454             :         }
    8455             : 
    8456         178 :         if (eErr == CE_None && nSrcOverviews)
    8457             :         {
    8458          66 :             if (poDS->m_nOverviewCount != nSrcOverviews)
    8459             :             {
    8460           0 :                 ReportError(
    8461             :                     pszFilename, CE_Failure, CPLE_AppDefined,
    8462             :                     "Did only manage to instantiate %d overview levels, "
    8463             :                     "whereas source contains %d",
    8464           0 :                     poDS->m_nOverviewCount, nSrcOverviews);
    8465           0 :                 eErr = CE_Failure;
    8466             :             }
    8467             : 
    8468         191 :             for (int i = 0; eErr == CE_None && i < nSrcOverviews; ++i)
    8469             :             {
    8470             :                 GDALRasterBand *poOvrBand =
    8471             :                     poOvrDS
    8472         203 :                         ? (i == 0
    8473          78 :                                ? poOvrDS->GetRasterBand(1)
    8474          41 :                                : poOvrDS->GetRasterBand(1)->GetOverview(i - 1))
    8475         172 :                         : poSrcDS->GetRasterBand(1)->GetOverview(i);
    8476             :                 const double dfOvrPixels =
    8477         125 :                     static_cast<double>(poOvrBand->GetXSize()) *
    8478         125 :                     poOvrBand->GetYSize();
    8479         125 :                 dfTotalPixels += dfOvrPixels * l_nBands;
    8480         236 :                 if (poOvrBand->GetMaskFlags() == GMF_PER_DATASET ||
    8481         111 :                     poMaskOvrDS != nullptr)
    8482             :                 {
    8483          36 :                     dfTotalPixels += dfOvrPixels;
    8484             :                 }
    8485          89 :                 else if (i == 0 && poDS->GetRasterBand(1)->GetMaskFlags() ==
    8486             :                                        GMF_PER_DATASET)
    8487             :                 {
    8488           1 :                     ReportError(pszFilename, CE_Warning, CPLE_AppDefined,
    8489             :                                 "Source dataset has a mask band on full "
    8490             :                                 "resolution, overviews on the regular bands, "
    8491             :                                 "but lacks overviews on the mask band.");
    8492             :                 }
    8493             :             }
    8494             : 
    8495             :             // Now copy the imagery.
    8496             :             // Begin with the smallest overview.
    8497          66 :             for (int iOvrLevel = nSrcOverviews - 1;
    8498         190 :                  eErr == CE_None && iOvrLevel >= 0; --iOvrLevel)
    8499             :             {
    8500         124 :                 auto poDstDS = poDS->m_papoOverviewDS[iOvrLevel];
    8501             : 
    8502             :                 // Create a fake dataset with the source overview level so that
    8503             :                 // GDALDatasetCopyWholeRaster can cope with it.
    8504             :                 GDALDataset *poSrcOvrDS =
    8505             :                     poOvrDS
    8506         165 :                         ? (iOvrLevel == 0 ? poOvrDS.get()
    8507          41 :                                           : GDALCreateOverviewDataset(
    8508             :                                                 poOvrDS.get(), iOvrLevel - 1,
    8509             :                                                 /* bThisLevelOnly = */ true))
    8510          46 :                         : GDALCreateOverviewDataset(
    8511             :                               poSrcDS, iOvrLevel,
    8512         124 :                               /* bThisLevelOnly = */ true);
    8513             :                 GDALRasterBand *poSrcOvrBand =
    8514         202 :                     poOvrDS ? (iOvrLevel == 0
    8515          78 :                                    ? poOvrDS->GetRasterBand(1)
    8516          82 :                                    : poOvrDS->GetRasterBand(1)->GetOverview(
    8517          41 :                                          iOvrLevel - 1))
    8518         170 :                             : poSrcDS->GetRasterBand(1)->GetOverview(iOvrLevel);
    8519             :                 double dfNextCurPixels =
    8520             :                     dfCurPixels +
    8521         124 :                     static_cast<double>(poSrcOvrBand->GetXSize()) *
    8522         124 :                         poSrcOvrBand->GetYSize() * l_nBands;
    8523             : 
    8524         124 :                 poDstDS->m_bBlockOrderRowMajor = true;
    8525         124 :                 poDstDS->m_bLeaderSizeAsUInt4 = true;
    8526         124 :                 poDstDS->m_bTrailerRepeatedLast4BytesRepeated = true;
    8527         124 :                 poDstDS->m_bFillEmptyTilesAtClosing =
    8528         124 :                     poDS->m_bFillEmptyTilesAtClosing;
    8529         124 :                 poDstDS->m_bWriteEmptyTiles = poDS->m_bWriteEmptyTiles;
    8530         124 :                 poDstDS->m_bTileInterleave = poDS->m_bTileInterleave;
    8531         124 :                 GDALRasterBand *poSrcMaskBand = nullptr;
    8532         124 :                 if (poDstDS->m_poMaskDS)
    8533             :                 {
    8534          36 :                     poDstDS->m_poMaskDS->m_bBlockOrderRowMajor = true;
    8535          36 :                     poDstDS->m_poMaskDS->m_bLeaderSizeAsUInt4 = true;
    8536          36 :                     poDstDS->m_poMaskDS->m_bTrailerRepeatedLast4BytesRepeated =
    8537             :                         true;
    8538          36 :                     poDstDS->m_poMaskDS->m_bFillEmptyTilesAtClosing =
    8539          36 :                         poDS->m_bFillEmptyTilesAtClosing;
    8540          36 :                     poDstDS->m_poMaskDS->m_bWriteEmptyTiles =
    8541          36 :                         poDS->m_bWriteEmptyTiles;
    8542             : 
    8543          36 :                     poSrcMaskBand =
    8544             :                         poMaskOvrDS
    8545          58 :                             ? (iOvrLevel == 0
    8546          22 :                                    ? poMaskOvrDS->GetRasterBand(1)
    8547          24 :                                    : poMaskOvrDS->GetRasterBand(1)->GetOverview(
    8548          12 :                                          iOvrLevel - 1))
    8549          50 :                             : poSrcOvrBand->GetMaskBand();
    8550             :                 }
    8551             : 
    8552         124 :                 if (poDstDS->m_poMaskDS)
    8553             :                 {
    8554          36 :                     dfNextCurPixels +=
    8555          36 :                         static_cast<double>(poSrcOvrBand->GetXSize()) *
    8556          36 :                         poSrcOvrBand->GetYSize();
    8557             :                 }
    8558             :                 void *pScaledData =
    8559         124 :                     GDALCreateScaledProgress(dfCurPixels / dfTotalPixels,
    8560             :                                              dfNextCurPixels / dfTotalPixels,
    8561             :                                              pfnProgress, pProgressData);
    8562             : 
    8563         124 :                 eErr = CopyImageryAndMask(poDstDS, poSrcOvrDS, poSrcMaskBand,
    8564             :                                           GDALScaledProgress, pScaledData);
    8565             : 
    8566         124 :                 dfCurPixels = dfNextCurPixels;
    8567         124 :                 GDALDestroyScaledProgress(pScaledData);
    8568             : 
    8569         124 :                 if (poSrcOvrDS != poOvrDS.get())
    8570          87 :                     delete poSrcOvrDS;
    8571         124 :                 poSrcOvrDS = nullptr;
    8572             :             }
    8573             :         }
    8574             :     }
    8575             : 
    8576             :     /* -------------------------------------------------------------------- */
    8577             :     /*      Copy actual imagery.                                            */
    8578             :     /* -------------------------------------------------------------------- */
    8579        2004 :     double dfNextCurPixels =
    8580        2004 :         dfCurPixels + static_cast<double>(nXSize) * nYSize * l_nBands;
    8581        2004 :     void *pScaledData = GDALCreateScaledProgress(
    8582             :         dfCurPixels / dfTotalPixels, dfNextCurPixels / dfTotalPixels,
    8583             :         pfnProgress, pProgressData);
    8584             : 
    8585             : #if defined(HAVE_LIBJPEG) || defined(JPEG_DIRECT_COPY)
    8586        2004 :     bool bTryCopy = true;
    8587             : #endif
    8588             : 
    8589             : #ifdef HAVE_LIBJPEG
    8590        2004 :     if (bCopyFromJPEG)
    8591             :     {
    8592          12 :         eErr = GTIFF_CopyFromJPEG(poDS, poSrcDS, pfnProgress, pProgressData,
    8593             :                                   bTryCopy);
    8594             : 
    8595             :         // In case of failure in the decompression step, try normal copy.
    8596          12 :         if (bTryCopy)
    8597           0 :             eErr = CE_None;
    8598             :     }
    8599             : #endif
    8600             : 
    8601             : #ifdef JPEG_DIRECT_COPY
    8602             :     if (bDirectCopyFromJPEG)
    8603             :     {
    8604             :         eErr = GTIFF_DirectCopyFromJPEG(poDS, poSrcDS, pfnProgress,
    8605             :                                         pProgressData, bTryCopy);
    8606             : 
    8607             :         // In case of failure in the reading step, try normal copy.
    8608             :         if (bTryCopy)
    8609             :             eErr = CE_None;
    8610             :     }
    8611             : #endif
    8612             : 
    8613        2004 :     bool bWriteMask = true;
    8614        2004 :     if (
    8615             : #if defined(HAVE_LIBJPEG) || defined(JPEG_DIRECT_COPY)
    8616        1992 :         bTryCopy &&
    8617             : #endif
    8618        1992 :         (poDS->m_bTreatAsSplit || poDS->m_bTreatAsSplitBitmap))
    8619             :     {
    8620             :         // For split bands, we use TIFFWriteScanline() interface.
    8621           9 :         CPLAssert(poDS->m_nBitsPerSample == 8 || poDS->m_nBitsPerSample == 1);
    8622             : 
    8623           9 :         if (poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG && poDS->nBands > 1)
    8624             :         {
    8625             :             GByte *pabyScanline = static_cast<GByte *>(
    8626           3 :                 VSI_MALLOC_VERBOSE(TIFFScanlineSize(l_hTIFF)));
    8627           3 :             if (pabyScanline == nullptr)
    8628           0 :                 eErr = CE_Failure;
    8629        9052 :             for (int j = 0; j < nYSize && eErr == CE_None; ++j)
    8630             :             {
    8631       18098 :                 eErr = poSrcDS->RasterIO(GF_Read, 0, j, nXSize, 1, pabyScanline,
    8632             :                                          nXSize, 1, GDT_Byte, l_nBands, nullptr,
    8633        9049 :                                          poDS->nBands, 0, 1, nullptr);
    8634       18098 :                 if (eErr == CE_None &&
    8635        9049 :                     TIFFWriteScanline(l_hTIFF, pabyScanline, j, 0) == -1)
    8636             :                 {
    8637           0 :                     ReportError(pszFilename, CE_Failure, CPLE_AppDefined,
    8638             :                                 "TIFFWriteScanline() failed.");
    8639           0 :                     eErr = CE_Failure;
    8640             :                 }
    8641        9049 :                 if (!GDALScaledProgress((j + 1) * 1.0 / nYSize, nullptr,
    8642             :                                         pScaledData))
    8643           0 :                     eErr = CE_Failure;
    8644             :             }
    8645           3 :             CPLFree(pabyScanline);
    8646             :         }
    8647             :         else
    8648             :         {
    8649             :             GByte *pabyScanline =
    8650           6 :                 static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize));
    8651           6 :             if (pabyScanline == nullptr)
    8652           0 :                 eErr = CE_Failure;
    8653             :             else
    8654           6 :                 eErr = CE_None;
    8655          14 :             for (int iBand = 1; iBand <= l_nBands && eErr == CE_None; ++iBand)
    8656             :             {
    8657       48211 :                 for (int j = 0; j < nYSize && eErr == CE_None; ++j)
    8658             :                 {
    8659       48203 :                     eErr = poSrcDS->GetRasterBand(iBand)->RasterIO(
    8660             :                         GF_Read, 0, j, nXSize, 1, pabyScanline, nXSize, 1,
    8661             :                         GDT_Byte, 0, 0, nullptr);
    8662       48203 :                     if (poDS->m_bTreatAsSplitBitmap)
    8663             :                     {
    8664     7225210 :                         for (int i = 0; i < nXSize; ++i)
    8665             :                         {
    8666     7216010 :                             const GByte byVal = pabyScanline[i];
    8667     7216010 :                             if ((i & 0x7) == 0)
    8668      902001 :                                 pabyScanline[i >> 3] = 0;
    8669     7216010 :                             if (byVal)
    8670     7097220 :                                 pabyScanline[i >> 3] |= 0x80 >> (i & 0x7);
    8671             :                         }
    8672             :                     }
    8673       96406 :                     if (eErr == CE_None &&
    8674       48203 :                         TIFFWriteScanline(l_hTIFF, pabyScanline, j,
    8675       48203 :                                           static_cast<uint16_t>(iBand - 1)) ==
    8676             :                             -1)
    8677             :                     {
    8678           0 :                         ReportError(pszFilename, CE_Failure, CPLE_AppDefined,
    8679             :                                     "TIFFWriteScanline() failed.");
    8680           0 :                         eErr = CE_Failure;
    8681             :                     }
    8682       48203 :                     if (!GDALScaledProgress((j + 1 + (iBand - 1) * nYSize) *
    8683       48203 :                                                 1.0 / (l_nBands * nYSize),
    8684             :                                             nullptr, pScaledData))
    8685           0 :                         eErr = CE_Failure;
    8686             :                 }
    8687             :             }
    8688           6 :             CPLFree(pabyScanline);
    8689             :         }
    8690             : 
    8691             :         // Necessary to be able to read the file without re-opening.
    8692           9 :         TIFFSizeProc pfnSizeProc = TIFFGetSizeProc(l_hTIFF);
    8693             : 
    8694           9 :         TIFFFlushData(l_hTIFF);
    8695             : 
    8696           9 :         toff_t nNewDirOffset = pfnSizeProc(TIFFClientdata(l_hTIFF));
    8697           9 :         if ((nNewDirOffset % 2) == 1)
    8698           5 :             ++nNewDirOffset;
    8699             : 
    8700           9 :         TIFFFlush(l_hTIFF);
    8701             : 
    8702           9 :         if (poDS->m_nDirOffset != TIFFCurrentDirOffset(l_hTIFF))
    8703             :         {
    8704           0 :             poDS->m_nDirOffset = nNewDirOffset;
    8705           0 :             CPLDebug("GTiff", "directory moved during flush.");
    8706           9 :         }
    8707             :     }
    8708        1995 :     else if (
    8709             : #if defined(HAVE_LIBJPEG) || defined(JPEG_DIRECT_COPY)
    8710        1983 :         bTryCopy &&
    8711             : #endif
    8712             :         eErr == CE_None)
    8713             :     {
    8714        1982 :         const char *papszCopyWholeRasterOptions[3] = {nullptr, nullptr,
    8715             :                                                       nullptr};
    8716        1982 :         int iNextOption = 0;
    8717        1982 :         papszCopyWholeRasterOptions[iNextOption++] = "SKIP_HOLES=YES";
    8718        1982 :         if (l_nCompression != COMPRESSION_NONE)
    8719             :         {
    8720         444 :             papszCopyWholeRasterOptions[iNextOption++] = "COMPRESSED=YES";
    8721             :         }
    8722             : 
    8723             :         // For streaming with separate, we really want that bands are written
    8724             :         // after each other, even if the source is pixel interleaved.
    8725        1538 :         else if (bStreaming && poDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
    8726             :         {
    8727           1 :             papszCopyWholeRasterOptions[iNextOption++] = "INTERLEAVE=BAND";
    8728             :         }
    8729             : 
    8730        1982 :         if (bCopySrcOverviews || bTileInterleaving)
    8731             :         {
    8732         178 :             poDS->m_bBlockOrderRowMajor = true;
    8733         178 :             poDS->m_bLeaderSizeAsUInt4 = bCopySrcOverviews;
    8734         178 :             poDS->m_bTrailerRepeatedLast4BytesRepeated = bCopySrcOverviews;
    8735         178 :             if (poDS->m_poMaskDS)
    8736             :             {
    8737          27 :                 poDS->m_poMaskDS->m_bBlockOrderRowMajor = true;
    8738          27 :                 poDS->m_poMaskDS->m_bLeaderSizeAsUInt4 = bCopySrcOverviews;
    8739          27 :                 poDS->m_poMaskDS->m_bTrailerRepeatedLast4BytesRepeated =
    8740             :                     bCopySrcOverviews;
    8741          27 :                 GDALDestroyScaledProgress(pScaledData);
    8742             :                 pScaledData =
    8743          27 :                     GDALCreateScaledProgress(dfCurPixels / dfTotalPixels, 1.0,
    8744             :                                              pfnProgress, pProgressData);
    8745             :             }
    8746             : 
    8747         178 :             eErr = CopyImageryAndMask(poDS, poSrcDS,
    8748         178 :                                       poSrcDS->GetRasterBand(1)->GetMaskBand(),
    8749             :                                       GDALScaledProgress, pScaledData);
    8750         178 :             if (poDS->m_poMaskDS)
    8751             :             {
    8752          27 :                 bWriteMask = false;
    8753             :             }
    8754             :         }
    8755             :         else
    8756             :         {
    8757        1804 :             eErr = GDALDatasetCopyWholeRaster(
    8758             :                 /* (GDALDatasetH) */ poSrcDS,
    8759             :                 /* (GDALDatasetH) */ poDS, papszCopyWholeRasterOptions,
    8760             :                 GDALScaledProgress, pScaledData);
    8761             :         }
    8762             :     }
    8763             : 
    8764        2004 :     GDALDestroyScaledProgress(pScaledData);
    8765             : 
    8766        2004 :     if (eErr == CE_None && !bStreaming && bWriteMask)
    8767             :     {
    8768        1955 :         pScaledData = GDALCreateScaledProgress(dfNextCurPixels / dfTotalPixels,
    8769             :                                                1.0, pfnProgress, pProgressData);
    8770        1955 :         if (poDS->m_poMaskDS)
    8771             :         {
    8772          10 :             const char *l_papszOptions[2] = {"COMPRESSED=YES", nullptr};
    8773          10 :             eErr = GDALRasterBandCopyWholeRaster(
    8774          10 :                 poSrcDS->GetRasterBand(1)->GetMaskBand(),
    8775          10 :                 poDS->GetRasterBand(1)->GetMaskBand(),
    8776             :                 const_cast<char **>(l_papszOptions), GDALScaledProgress,
    8777             :                 pScaledData);
    8778             :         }
    8779             :         else
    8780             :         {
    8781             :             eErr =
    8782        1945 :                 GDALDriver::DefaultCopyMasks(poSrcDS, poDS, bStrict, nullptr,
    8783             :                                              GDALScaledProgress, pScaledData);
    8784             :         }
    8785        1955 :         GDALDestroyScaledProgress(pScaledData);
    8786             :     }
    8787             : 
    8788        2004 :     poDS->m_bWriteCOGLayout = false;
    8789             : 
    8790        3990 :     if (eErr == CE_None &&
    8791        1986 :         CPLTestBool(CSLFetchNameValueDef(poDS->m_papszCreationOptions,
    8792             :                                          "@FLUSHCACHE", "NO")))
    8793             :     {
    8794         135 :         if (poDS->FlushCache(false) != CE_None)
    8795             :         {
    8796           0 :             eErr = CE_Failure;
    8797             :         }
    8798             :     }
    8799             : 
    8800        2004 :     if (eErr == CE_Failure)
    8801             :     {
    8802          18 :         l_fpL->CancelCreation();
    8803          18 :         delete poDS;
    8804          18 :         poDS = nullptr;
    8805             : 
    8806          18 :         if (CPLTestBool(CPLGetConfigOption("GTIFF_DELETE_ON_ERROR", "YES")))
    8807             :         {
    8808          17 :             if (!bStreaming)
    8809             :             {
    8810             :                 // Should really delete more carefully.
    8811          17 :                 VSIUnlink(pszFilename);
    8812             :             }
    8813             :         }
    8814             :     }
    8815             : 
    8816        2004 :     return poDS;
    8817             : }
    8818             : 
    8819             : /************************************************************************/
    8820             : /*                           SetSpatialRef()                            */
    8821             : /************************************************************************/
    8822             : 
    8823        1398 : CPLErr GTiffDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
    8824             : 
    8825             : {
    8826        1398 :     if (m_bStreamingOut && m_bCrystalized)
    8827             :     {
    8828           1 :         ReportError(CE_Failure, CPLE_NotSupported,
    8829             :                     "Cannot modify projection at that point in "
    8830             :                     "a streamed output file");
    8831           1 :         return CE_Failure;
    8832             :     }
    8833             : 
    8834        1397 :     LoadGeoreferencingAndPamIfNeeded();
    8835        1397 :     LookForProjection();
    8836             : 
    8837        1397 :     CPLErr eErr = CE_None;
    8838        1397 :     if (eAccess == GA_Update)
    8839             :     {
    8840        1399 :         if ((m_eProfile == GTiffProfile::BASELINE) &&
    8841           7 :             (GetPamFlags() & GPF_DISABLED) == 0)
    8842             :         {
    8843           7 :             eErr = GDALPamDataset::SetSpatialRef(poSRS);
    8844             :         }
    8845             :         else
    8846             :         {
    8847        1385 :             if (GDALPamDataset::GetSpatialRef() != nullptr)
    8848             :             {
    8849             :                 // Cancel any existing SRS from PAM file.
    8850           1 :                 GDALPamDataset::SetSpatialRef(nullptr);
    8851             :             }
    8852        1385 :             m_bGeoTIFFInfoChanged = true;
    8853             :         }
    8854             :     }
    8855             :     else
    8856             :     {
    8857           5 :         CPLDebug("GTIFF", "SetSpatialRef() goes to PAM instead of TIFF tags");
    8858           5 :         eErr = GDALPamDataset::SetSpatialRef(poSRS);
    8859             :     }
    8860             : 
    8861        1397 :     if (eErr == CE_None)
    8862             :     {
    8863        1397 :         if (poSRS == nullptr || poSRS->IsEmpty())
    8864             :         {
    8865          14 :             if (!m_oSRS.IsEmpty())
    8866             :             {
    8867           4 :                 m_bForceUnsetProjection = true;
    8868             :             }
    8869          14 :             m_oSRS.Clear();
    8870             :         }
    8871             :         else
    8872             :         {
    8873        1383 :             m_oSRS = *poSRS;
    8874        1383 :             m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    8875             :         }
    8876             :     }
    8877             : 
    8878        1397 :     return eErr;
    8879             : }
    8880             : 
    8881             : /************************************************************************/
    8882             : /*                          SetGeoTransform()                           */
    8883             : /************************************************************************/
    8884             : 
    8885        1688 : CPLErr GTiffDataset::SetGeoTransform(const GDALGeoTransform &gt)
    8886             : 
    8887             : {
    8888        1688 :     if (m_bStreamingOut && m_bCrystalized)
    8889             :     {
    8890           1 :         ReportError(CE_Failure, CPLE_NotSupported,
    8891             :                     "Cannot modify geotransform at that point in a "
    8892             :                     "streamed output file");
    8893           1 :         return CE_Failure;
    8894             :     }
    8895             : 
    8896        1687 :     LoadGeoreferencingAndPamIfNeeded();
    8897             : 
    8898        1687 :     CPLErr eErr = CE_None;
    8899        1687 :     if (eAccess == GA_Update)
    8900             :     {
    8901        1681 :         if (!m_aoGCPs.empty())
    8902             :         {
    8903           1 :             ReportError(CE_Warning, CPLE_AppDefined,
    8904             :                         "GCPs previously set are going to be cleared "
    8905             :                         "due to the setting of a geotransform.");
    8906           1 :             m_bForceUnsetGTOrGCPs = true;
    8907           1 :             m_aoGCPs.clear();
    8908             :         }
    8909        1881 :         else if (gt[0] == 0.0 && gt[1] == 0.0 && gt[2] == 0.0 && gt[3] == 0.0 &&
    8910        1881 :                  gt[4] == 0.0 && gt[5] == 0.0)
    8911             :         {
    8912           2 :             if (m_bGeoTransformValid)
    8913             :             {
    8914           2 :                 m_bForceUnsetGTOrGCPs = true;
    8915           2 :                 m_bGeoTIFFInfoChanged = true;
    8916             :             }
    8917           2 :             m_bGeoTransformValid = false;
    8918           2 :             m_gt = gt;
    8919           2 :             return CE_None;
    8920             :         }
    8921             : 
    8922        3367 :         if ((m_eProfile == GTiffProfile::BASELINE) &&
    8923           9 :             !CPLFetchBool(m_papszCreationOptions, "TFW", false) &&
    8924        1693 :             !CPLFetchBool(m_papszCreationOptions, "WORLDFILE", false) &&
    8925           5 :             (GetPamFlags() & GPF_DISABLED) == 0)
    8926             :         {
    8927           5 :             eErr = GDALPamDataset::SetGeoTransform(gt);
    8928             :         }
    8929             :         else
    8930             :         {
    8931             :             // Cancel any existing geotransform from PAM file.
    8932        1674 :             GDALPamDataset::DeleteGeoTransform();
    8933        1674 :             m_bGeoTIFFInfoChanged = true;
    8934             :         }
    8935             :     }
    8936             :     else
    8937             :     {
    8938           6 :         CPLDebug("GTIFF", "SetGeoTransform() goes to PAM instead of TIFF tags");
    8939           6 :         eErr = GDALPamDataset::SetGeoTransform(gt);
    8940             :     }
    8941             : 
    8942        1685 :     if (eErr == CE_None)
    8943             :     {
    8944        1685 :         m_gt = gt;
    8945        1685 :         m_bGeoTransformValid = true;
    8946             :     }
    8947             : 
    8948        1685 :     return eErr;
    8949             : }
    8950             : 
    8951             : /************************************************************************/
    8952             : /*                               SetGCPs()                              */
    8953             : /************************************************************************/
    8954             : 
    8955          23 : CPLErr GTiffDataset::SetGCPs(int nGCPCountIn, const GDAL_GCP *pasGCPListIn,
    8956             :                              const OGRSpatialReference *poGCPSRS)
    8957             : {
    8958          23 :     CPLErr eErr = CE_None;
    8959          23 :     LoadGeoreferencingAndPamIfNeeded();
    8960          23 :     LookForProjection();
    8961             : 
    8962          23 :     if (eAccess == GA_Update)
    8963             :     {
    8964          21 :         if (!m_aoGCPs.empty() && nGCPCountIn == 0)
    8965             :         {
    8966           3 :             m_bForceUnsetGTOrGCPs = true;
    8967             :         }
    8968          18 :         else if (nGCPCountIn > 0 && m_bGeoTransformValid)
    8969             :         {
    8970           5 :             ReportError(CE_Warning, CPLE_AppDefined,
    8971             :                         "A geotransform previously set is going to be cleared "
    8972             :                         "due to the setting of GCPs.");
    8973           5 :             m_gt = GDALGeoTransform();
    8974           5 :             m_bGeoTransformValid = false;
    8975           5 :             m_bForceUnsetGTOrGCPs = true;
    8976             :         }
    8977          21 :         if ((m_eProfile == GTiffProfile::BASELINE) &&
    8978           0 :             (GetPamFlags() & GPF_DISABLED) == 0)
    8979             :         {
    8980           0 :             eErr = GDALPamDataset::SetGCPs(nGCPCountIn, pasGCPListIn, poGCPSRS);
    8981             :         }
    8982             :         else
    8983             :         {
    8984          21 :             if (nGCPCountIn > knMAX_GCP_COUNT)
    8985             :             {
    8986           2 :                 if (GDALPamDataset::GetGCPCount() == 0 && !m_aoGCPs.empty())
    8987             :                 {
    8988           1 :                     m_bForceUnsetGTOrGCPs = true;
    8989             :                 }
    8990           2 :                 ReportError(CE_Warning, CPLE_AppDefined,
    8991             :                             "Trying to write %d GCPs, whereas the maximum "
    8992             :                             "supported in GeoTIFF tag is %d. "
    8993             :                             "Falling back to writing them to PAM",
    8994             :                             nGCPCountIn, knMAX_GCP_COUNT);
    8995           2 :                 eErr = GDALPamDataset::SetGCPs(nGCPCountIn, pasGCPListIn,
    8996             :                                                poGCPSRS);
    8997             :             }
    8998          19 :             else if (GDALPamDataset::GetGCPCount() > 0)
    8999             :             {
    9000             :                 // Cancel any existing GCPs from PAM file.
    9001           1 :                 GDALPamDataset::SetGCPs(
    9002             :                     0, nullptr,
    9003             :                     static_cast<const OGRSpatialReference *>(nullptr));
    9004             :             }
    9005          21 :             m_bGeoTIFFInfoChanged = true;
    9006             :         }
    9007             :     }
    9008             :     else
    9009             :     {
    9010           2 :         CPLDebug("GTIFF", "SetGCPs() goes to PAM instead of TIFF tags");
    9011           2 :         eErr = GDALPamDataset::SetGCPs(nGCPCountIn, pasGCPListIn, poGCPSRS);
    9012             :     }
    9013             : 
    9014          23 :     if (eErr == CE_None)
    9015             :     {
    9016          23 :         if (poGCPSRS == nullptr || poGCPSRS->IsEmpty())
    9017             :         {
    9018          12 :             if (!m_oSRS.IsEmpty())
    9019             :             {
    9020           5 :                 m_bForceUnsetProjection = true;
    9021             :             }
    9022          12 :             m_oSRS.Clear();
    9023             :         }
    9024             :         else
    9025             :         {
    9026          11 :             m_oSRS = *poGCPSRS;
    9027          11 :             m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    9028             :         }
    9029             : 
    9030          23 :         m_aoGCPs = gdal::GCP::fromC(pasGCPListIn, nGCPCountIn);
    9031             :     }
    9032             : 
    9033          23 :     return eErr;
    9034             : }
    9035             : 
    9036             : /************************************************************************/
    9037             : /*                            SetMetadata()                             */
    9038             : /************************************************************************/
    9039        2589 : CPLErr GTiffDataset::SetMetadata(char **papszMD, const char *pszDomain)
    9040             : 
    9041             : {
    9042        2589 :     LoadGeoreferencingAndPamIfNeeded();
    9043             : 
    9044        2589 :     if (m_bStreamingOut && m_bCrystalized)
    9045             :     {
    9046           1 :         ReportError(
    9047             :             CE_Failure, CPLE_NotSupported,
    9048             :             "Cannot modify metadata at that point in a streamed output file");
    9049           1 :         return CE_Failure;
    9050             :     }
    9051             : 
    9052        2588 :     CPLErr eErr = CE_None;
    9053        2588 :     if (eAccess == GA_Update)
    9054             :     {
    9055        2586 :         if (pszDomain != nullptr && EQUAL(pszDomain, MD_DOMAIN_RPC))
    9056             :         {
    9057             :             // So that a subsequent GetMetadata() wouldn't override our new
    9058             :             // values
    9059          22 :             LoadMetadata();
    9060          22 :             m_bForceUnsetRPC = (CSLCount(papszMD) == 0);
    9061             :         }
    9062             : 
    9063        2586 :         if ((papszMD != nullptr) && (pszDomain != nullptr) &&
    9064        1770 :             EQUAL(pszDomain, "COLOR_PROFILE"))
    9065             :         {
    9066           0 :             m_bColorProfileMetadataChanged = true;
    9067             :         }
    9068        2586 :         else if (pszDomain == nullptr || !EQUAL(pszDomain, "_temporary_"))
    9069             :         {
    9070        2586 :             m_bMetadataChanged = true;
    9071             :             // Cancel any existing metadata from PAM file.
    9072        2586 :             if (GDALPamDataset::GetMetadata(pszDomain) != nullptr)
    9073           1 :                 GDALPamDataset::SetMetadata(nullptr, pszDomain);
    9074             :         }
    9075             : 
    9076        5135 :         if ((pszDomain == nullptr || EQUAL(pszDomain, "")) &&
    9077        2549 :             CSLFetchNameValue(papszMD, GDALMD_AREA_OR_POINT) != nullptr)
    9078             :         {
    9079        1925 :             const char *pszPrevValue = GetMetadataItem(GDALMD_AREA_OR_POINT);
    9080             :             const char *pszNewValue =
    9081        1925 :                 CSLFetchNameValue(papszMD, GDALMD_AREA_OR_POINT);
    9082        1925 :             if (pszPrevValue == nullptr || pszNewValue == nullptr ||
    9083        1507 :                 !EQUAL(pszPrevValue, pszNewValue))
    9084             :             {
    9085         422 :                 LookForProjection();
    9086         422 :                 m_bGeoTIFFInfoChanged = true;
    9087             :             }
    9088             :         }
    9089             : 
    9090        2586 :         if (pszDomain != nullptr && EQUAL(pszDomain, "xml:XMP"))
    9091             :         {
    9092           2 :             if (papszMD != nullptr && *papszMD != nullptr)
    9093             :             {
    9094           1 :                 int nTagSize = static_cast<int>(strlen(*papszMD));
    9095           1 :                 TIFFSetField(m_hTIFF, TIFFTAG_XMLPACKET, nTagSize, *papszMD);
    9096             :             }
    9097             :             else
    9098             :             {
    9099           1 :                 TIFFUnsetField(m_hTIFF, TIFFTAG_XMLPACKET);
    9100             :             }
    9101             :         }
    9102             :     }
    9103             :     else
    9104             :     {
    9105           2 :         CPLDebug(
    9106             :             "GTIFF",
    9107             :             "GTiffDataset::SetMetadata() goes to PAM instead of TIFF tags");
    9108           2 :         eErr = GDALPamDataset::SetMetadata(papszMD, pszDomain);
    9109             :     }
    9110             : 
    9111        2588 :     if (eErr == CE_None)
    9112             :     {
    9113        2588 :         eErr = m_oGTiffMDMD.SetMetadata(papszMD, pszDomain);
    9114             :     }
    9115        2588 :     return eErr;
    9116             : }
    9117             : 
    9118             : /************************************************************************/
    9119             : /*                          SetMetadataItem()                           */
    9120             : /************************************************************************/
    9121             : 
    9122        5576 : CPLErr GTiffDataset::SetMetadataItem(const char *pszName, const char *pszValue,
    9123             :                                      const char *pszDomain)
    9124             : 
    9125             : {
    9126        5576 :     LoadGeoreferencingAndPamIfNeeded();
    9127             : 
    9128        5576 :     if (m_bStreamingOut && m_bCrystalized)
    9129             :     {
    9130           1 :         ReportError(
    9131             :             CE_Failure, CPLE_NotSupported,
    9132             :             "Cannot modify metadata at that point in a streamed output file");
    9133           1 :         return CE_Failure;
    9134             :     }
    9135             : 
    9136        5575 :     CPLErr eErr = CE_None;
    9137        5575 :     if (eAccess == GA_Update)
    9138             :     {
    9139        5568 :         if ((pszDomain != nullptr) && EQUAL(pszDomain, "COLOR_PROFILE"))
    9140             :         {
    9141           8 :             m_bColorProfileMetadataChanged = true;
    9142             :         }
    9143        5560 :         else if (pszDomain == nullptr || !EQUAL(pszDomain, "_temporary_"))
    9144             :         {
    9145        5560 :             m_bMetadataChanged = true;
    9146             :             // Cancel any existing metadata from PAM file.
    9147        5560 :             if (GDALPamDataset::GetMetadataItem(pszName, pszDomain) != nullptr)
    9148           1 :                 GDALPamDataset::SetMetadataItem(pszName, nullptr, pszDomain);
    9149             :         }
    9150             : 
    9151        5568 :         if ((pszDomain == nullptr || EQUAL(pszDomain, "")) &&
    9152          70 :             pszName != nullptr && EQUAL(pszName, GDALMD_AREA_OR_POINT))
    9153             :         {
    9154           7 :             LookForProjection();
    9155           7 :             m_bGeoTIFFInfoChanged = true;
    9156             :         }
    9157             :     }
    9158             :     else
    9159             :     {
    9160           7 :         CPLDebug(
    9161             :             "GTIFF",
    9162             :             "GTiffDataset::SetMetadataItem() goes to PAM instead of TIFF tags");
    9163           7 :         eErr = GDALPamDataset::SetMetadataItem(pszName, pszValue, pszDomain);
    9164             :     }
    9165             : 
    9166        5575 :     if (eErr == CE_None)
    9167             :     {
    9168        5575 :         eErr = m_oGTiffMDMD.SetMetadataItem(pszName, pszValue, pszDomain);
    9169             :     }
    9170             : 
    9171        5575 :     return eErr;
    9172             : }
    9173             : 
    9174             : /************************************************************************/
    9175             : /*                         CreateMaskBand()                             */
    9176             : /************************************************************************/
    9177             : 
    9178          96 : CPLErr GTiffDataset::CreateMaskBand(int nFlagsIn)
    9179             : {
    9180          96 :     ScanDirectories();
    9181             : 
    9182          96 :     if (m_poMaskDS != nullptr)
    9183             :     {
    9184           1 :         ReportError(CE_Failure, CPLE_AppDefined,
    9185             :                     "This TIFF dataset has already an internal mask band");
    9186           1 :         return CE_Failure;
    9187             :     }
    9188          95 :     else if (MustCreateInternalMask())
    9189             :     {
    9190          82 :         if (nFlagsIn != GMF_PER_DATASET)
    9191             :         {
    9192           1 :             ReportError(CE_Failure, CPLE_AppDefined,
    9193             :                         "The only flag value supported for internal mask is "
    9194             :                         "GMF_PER_DATASET");
    9195           1 :             return CE_Failure;
    9196             :         }
    9197             : 
    9198          81 :         int l_nCompression = COMPRESSION_PACKBITS;
    9199          81 :         if (strstr(GDALGetMetadataItem(GDALGetDriverByName("GTiff"),
    9200             :                                        GDAL_DMD_CREATIONOPTIONLIST, nullptr),
    9201          81 :                    "<Value>DEFLATE</Value>") != nullptr)
    9202          81 :             l_nCompression = COMPRESSION_ADOBE_DEFLATE;
    9203             : 
    9204             :         /* --------------------------------------------------------------------
    9205             :          */
    9206             :         /*      If we don't have read access, then create the mask externally.
    9207             :          */
    9208             :         /* --------------------------------------------------------------------
    9209             :          */
    9210          81 :         if (GetAccess() != GA_Update)
    9211             :         {
    9212           1 :             ReportError(CE_Warning, CPLE_AppDefined,
    9213             :                         "File open for read-only accessing, "
    9214             :                         "creating mask externally.");
    9215             : 
    9216           1 :             return GDALPamDataset::CreateMaskBand(nFlagsIn);
    9217             :         }
    9218             : 
    9219          80 :         if (m_bLayoutIFDSBeforeData && !m_bKnownIncompatibleEdition &&
    9220           0 :             !m_bWriteKnownIncompatibleEdition)
    9221             :         {
    9222           0 :             ReportError(CE_Warning, CPLE_AppDefined,
    9223             :                         "Adding a mask invalidates the "
    9224             :                         "LAYOUT=IFDS_BEFORE_DATA property");
    9225           0 :             m_bKnownIncompatibleEdition = true;
    9226           0 :             m_bWriteKnownIncompatibleEdition = true;
    9227             :         }
    9228             : 
    9229          80 :         bool bIsOverview = false;
    9230          80 :         uint32_t nSubType = 0;
    9231          80 :         if (TIFFGetField(m_hTIFF, TIFFTAG_SUBFILETYPE, &nSubType))
    9232             :         {
    9233           8 :             bIsOverview = (nSubType & FILETYPE_REDUCEDIMAGE) != 0;
    9234             : 
    9235           8 :             if ((nSubType & FILETYPE_MASK) != 0)
    9236             :             {
    9237           0 :                 ReportError(CE_Failure, CPLE_AppDefined,
    9238             :                             "Cannot create a mask on a TIFF mask IFD !");
    9239           0 :                 return CE_Failure;
    9240             :             }
    9241             :         }
    9242             : 
    9243          80 :         const int bIsTiled = TIFFIsTiled(m_hTIFF);
    9244             : 
    9245          80 :         FlushDirectory();
    9246             : 
    9247          80 :         const toff_t nOffset = GTIFFWriteDirectory(
    9248             :             m_hTIFF,
    9249             :             bIsOverview ? FILETYPE_REDUCEDIMAGE | FILETYPE_MASK : FILETYPE_MASK,
    9250             :             nRasterXSize, nRasterYSize, 1, PLANARCONFIG_CONTIG, 1,
    9251             :             m_nBlockXSize, m_nBlockYSize, bIsTiled, l_nCompression,
    9252             :             PHOTOMETRIC_MASK, PREDICTOR_NONE, SAMPLEFORMAT_UINT, nullptr,
    9253             :             nullptr, nullptr, 0, nullptr, "", nullptr, nullptr, nullptr,
    9254          80 :             nullptr, m_bWriteCOGLayout);
    9255             : 
    9256          80 :         ReloadDirectory();
    9257             : 
    9258          80 :         if (nOffset == 0)
    9259           0 :             return CE_Failure;
    9260             : 
    9261          80 :         m_poMaskDS = new GTiffDataset();
    9262          80 :         m_poMaskDS->m_poBaseDS = this;
    9263          80 :         m_poMaskDS->m_poImageryDS = this;
    9264          80 :         m_poMaskDS->ShareLockWithParentDataset(this);
    9265          80 :         m_poMaskDS->m_bPromoteTo8Bits = CPLTestBool(
    9266             :             CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK_TO_8BIT", "YES"));
    9267          80 :         if (m_poMaskDS->OpenOffset(VSI_TIFFOpenChild(m_hTIFF), nOffset,
    9268          80 :                                    GA_Update) != CE_None)
    9269             :         {
    9270           0 :             delete m_poMaskDS;
    9271           0 :             m_poMaskDS = nullptr;
    9272           0 :             return CE_Failure;
    9273             :         }
    9274             : 
    9275          80 :         return CE_None;
    9276             :     }
    9277             : 
    9278          13 :     return GDALPamDataset::CreateMaskBand(nFlagsIn);
    9279             : }
    9280             : 
    9281             : /************************************************************************/
    9282             : /*                        MustCreateInternalMask()                      */
    9283             : /************************************************************************/
    9284             : 
    9285         133 : bool GTiffDataset::MustCreateInternalMask()
    9286             : {
    9287         133 :     return CPLTestBool(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK", "YES"));
    9288             : }
    9289             : 
    9290             : /************************************************************************/
    9291             : /*                         CreateMaskBand()                             */
    9292             : /************************************************************************/
    9293             : 
    9294          27 : CPLErr GTiffRasterBand::CreateMaskBand(int nFlagsIn)
    9295             : {
    9296          27 :     m_poGDS->ScanDirectories();
    9297             : 
    9298          27 :     if (m_poGDS->m_poMaskDS != nullptr)
    9299             :     {
    9300           5 :         ReportError(CE_Failure, CPLE_AppDefined,
    9301             :                     "This TIFF dataset has already an internal mask band");
    9302           5 :         return CE_Failure;
    9303             :     }
    9304             : 
    9305             :     const char *pszGDAL_TIFF_INTERNAL_MASK =
    9306          22 :         CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK", nullptr);
    9307          25 :     if ((pszGDAL_TIFF_INTERNAL_MASK &&
    9308          22 :          CPLTestBool(pszGDAL_TIFF_INTERNAL_MASK)) ||
    9309             :         nFlagsIn == GMF_PER_DATASET)
    9310             :     {
    9311          15 :         return m_poGDS->CreateMaskBand(nFlagsIn);
    9312             :     }
    9313             : 
    9314           7 :     return GDALPamRasterBand::CreateMaskBand(nFlagsIn);
    9315             : }
    9316             : 
    9317             : /************************************************************************/
    9318             : /*                          ClampCTEntry()                              */
    9319             : /************************************************************************/
    9320             : 
    9321      232815 : /* static */ unsigned short GTiffDataset::ClampCTEntry(int iColor, int iComp,
    9322             :                                                        int nCTEntryVal,
    9323             :                                                        int nMultFactor)
    9324             : {
    9325      232815 :     const int nVal = nCTEntryVal * nMultFactor;
    9326      232815 :     if (nVal < 0)
    9327             :     {
    9328           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    9329             :                  "Color table entry [%d][%d] = %d, clamped to 0", iColor, iComp,
    9330             :                  nCTEntryVal);
    9331           0 :         return 0;
    9332             :     }
    9333      232815 :     if (nVal > 65535)
    9334             :     {
    9335           2 :         CPLError(CE_Warning, CPLE_AppDefined,
    9336             :                  "Color table entry [%d][%d] = %d, clamped to 65535", iColor,
    9337             :                  iComp, nCTEntryVal);
    9338           2 :         return 65535;
    9339             :     }
    9340      232813 :     return static_cast<unsigned short>(nVal);
    9341             : }

Generated by: LCOV version 1.14