LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffrasterband_write.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 397 445 89.2 %
Date: 2025-10-19 14:04:36 Functions: 17 17 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GeoTIFF Driver
       4             :  * Purpose:  Write/set operations on GTiffRasterBand
       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 "gtiffrasterband.h"
      15             : #include "gtiffdataset.h"
      16             : 
      17             : #include <algorithm>
      18             : #include <cmath>
      19             : #include <limits>
      20             : 
      21             : #include "cpl_vsi_virtual.h"
      22             : #include "gdal_priv_templates.hpp"
      23             : #include "gdal_priv.h"
      24             : #include "gtiff.h"
      25             : #include "tifvsi.h"
      26             : 
      27             : /************************************************************************/
      28             : /*                           SetDefaultRAT()                            */
      29             : /************************************************************************/
      30             : 
      31          11 : CPLErr GTiffRasterBand::SetDefaultRAT(const GDALRasterAttributeTable *poRAT)
      32             : {
      33          11 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
      34          11 :     return GDALPamRasterBand::SetDefaultRAT(poRAT);
      35             : }
      36             : 
      37             : /************************************************************************/
      38             : /*                            IWriteBlock()                             */
      39             : /************************************************************************/
      40             : 
      41       64361 : CPLErr GTiffRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
      42             :                                     void *pImage)
      43             : 
      44             : {
      45       64361 :     m_poGDS->Crystalize();
      46             : 
      47       64361 :     if (m_poGDS->m_bDebugDontWriteBlocks)
      48           0 :         return CE_None;
      49             : 
      50       64361 :     if (m_poGDS->m_bWriteError)
      51             :     {
      52             :         // Report as an error if a previously loaded block couldn't be written
      53             :         // correctly.
      54           0 :         return CE_Failure;
      55             :     }
      56             : 
      57       64361 :     const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
      58             : 
      59             :     /* -------------------------------------------------------------------- */
      60             :     /*      Handle case of "separate" images                                */
      61             :     /* -------------------------------------------------------------------- */
      62       64361 :     if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE ||
      63       49521 :         m_poGDS->nBands == 1)
      64             :     {
      65             :         const CPLErr eErr =
      66       35220 :             m_poGDS->WriteEncodedTileOrStrip(nBlockId, pImage, true);
      67             : 
      68       35217 :         return eErr;
      69             :     }
      70             : 
      71             :     /* -------------------------------------------------------------------- */
      72             :     /*      Handle case of pixel interleaved (PLANARCONFIG_CONTIG) images.  */
      73             :     /* -------------------------------------------------------------------- */
      74             :     // Why 10 ? Somewhat arbitrary
      75       29141 :     constexpr int MAX_BANDS_FOR_DIRTY_CHECK = 10;
      76       29141 :     GDALRasterBlock *apoBlocks[MAX_BANDS_FOR_DIRTY_CHECK] = {};
      77       29141 :     const int nBands = m_poGDS->nBands;
      78       29141 :     bool bAllBlocksDirty = false;
      79             : 
      80             :     /* -------------------------------------------------------------------- */
      81             :     /*     If all blocks are cached and dirty then we do not need to reload */
      82             :     /*     the tile/strip from disk                                         */
      83             :     /* -------------------------------------------------------------------- */
      84       29141 :     if (nBands <= MAX_BANDS_FOR_DIRTY_CHECK)
      85             :     {
      86       29135 :         bAllBlocksDirty = true;
      87      120977 :         for (int iBand = 0; iBand < nBands; ++iBand)
      88             :         {
      89       91842 :             if (iBand + 1 != nBand)
      90             :             {
      91       62707 :                 apoBlocks[iBand] =
      92       62707 :                     cpl::down_cast<GTiffRasterBand *>(
      93       62707 :                         m_poGDS->GetRasterBand(iBand + 1))
      94       62707 :                         ->TryGetLockedBlockRef(nBlockXOff, nBlockYOff);
      95             : 
      96       62707 :                 if (apoBlocks[iBand] == nullptr)
      97             :                 {
      98        1536 :                     bAllBlocksDirty = false;
      99             :                 }
     100       61171 :                 else if (!apoBlocks[iBand]->GetDirty())
     101             :                 {
     102         100 :                     apoBlocks[iBand]->DropLock();
     103         100 :                     apoBlocks[iBand] = nullptr;
     104         100 :                     bAllBlocksDirty = false;
     105             :                 }
     106             :             }
     107             :             else
     108       29135 :                 apoBlocks[iBand] = nullptr;
     109             :         }
     110             : #if DEBUG_VERBOSE
     111             :         if (bAllBlocksDirty)
     112             :             CPLDebug("GTIFF", "Saved reloading block %d", nBlockId);
     113             :         else
     114             :             CPLDebug("GTIFF", "Must reload block %d", nBlockId);
     115             : #endif
     116             :     }
     117             : 
     118             :     {
     119       29141 :         const CPLErr eErr = m_poGDS->LoadBlockBuf(nBlockId, !bAllBlocksDirty);
     120       29141 :         if (eErr != CE_None)
     121             :         {
     122           1 :             if (nBands <= MAX_BANDS_FOR_DIRTY_CHECK)
     123             :             {
     124           4 :                 for (int iBand = 0; iBand < nBands; ++iBand)
     125             :                 {
     126           3 :                     if (apoBlocks[iBand] != nullptr)
     127           0 :                         apoBlocks[iBand]->DropLock();
     128             :                 }
     129             :             }
     130           1 :             return eErr;
     131             :         }
     132             :     }
     133             : 
     134             :     /* -------------------------------------------------------------------- */
     135             :     /*      On write of pixel interleaved data, we might as well flush      */
     136             :     /*      out any other bands that are dirty in our cache.  This is       */
     137             :     /*      especially helpful when writing compressed blocks.              */
     138             :     /* -------------------------------------------------------------------- */
     139       29140 :     const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
     140             : 
     141      219433 :     for (int iBand = 0; iBand < nBands; ++iBand)
     142             :     {
     143      190293 :         const GByte *pabyThisImage = nullptr;
     144      190293 :         GDALRasterBlock *poBlock = nullptr;
     145             : 
     146      190293 :         if (iBand + 1 == nBand)
     147             :         {
     148       29140 :             pabyThisImage = static_cast<GByte *>(pImage);
     149             :         }
     150             :         else
     151             :         {
     152      161153 :             if (nBands <= MAX_BANDS_FOR_DIRTY_CHECK)
     153       62705 :                 poBlock = apoBlocks[iBand];
     154             :             else
     155       98448 :                 poBlock = cpl::down_cast<GTiffRasterBand *>(
     156       98448 :                               m_poGDS->GetRasterBand(iBand + 1))
     157       98448 :                               ->TryGetLockedBlockRef(nBlockXOff, nBlockYOff);
     158             : 
     159      161153 :             if (poBlock == nullptr)
     160        1645 :                 continue;
     161             : 
     162      159508 :             if (!poBlock->GetDirty())
     163             :             {
     164           8 :                 poBlock->DropLock();
     165           8 :                 continue;
     166             :             }
     167             : 
     168      159500 :             pabyThisImage = static_cast<GByte *>(poBlock->GetDataRef());
     169             :         }
     170             : 
     171      188640 :         GByte *pabyOut = m_poGDS->m_pabyBlockBuf + iBand * nWordBytes;
     172             : 
     173      188640 :         GDALCopyWords64(pabyThisImage, eDataType, nWordBytes, pabyOut,
     174             :                         eDataType, nWordBytes * nBands,
     175      188640 :                         static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
     176             : 
     177      188640 :         if (poBlock != nullptr)
     178             :         {
     179      159500 :             poBlock->MarkClean();
     180      159500 :             poBlock->DropLock();
     181             :         }
     182             :     }
     183             : 
     184       29140 :     if (bAllBlocksDirty)
     185             :     {
     186             :         // We can synchronously write the block now.
     187       56640 :         const CPLErr eErr = m_poGDS->WriteEncodedTileOrStrip(
     188       28320 :             nBlockId, m_poGDS->m_pabyBlockBuf, true);
     189       28320 :         m_poGDS->m_bLoadedBlockDirty = false;
     190       28320 :         return eErr;
     191             :     }
     192             : 
     193         820 :     m_poGDS->m_bLoadedBlockDirty = true;
     194             : 
     195         820 :     return CE_None;
     196             : }
     197             : 
     198             : /************************************************************************/
     199             : /*                           SetDescription()                           */
     200             : /************************************************************************/
     201             : 
     202          19 : void GTiffRasterBand::SetDescription(const char *pszDescription)
     203             : 
     204             : {
     205          19 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
     206             : 
     207          19 :     if (pszDescription == nullptr)
     208           0 :         pszDescription = "";
     209             : 
     210          19 :     if (m_osDescription != pszDescription)
     211          12 :         m_poGDS->m_bMetadataChanged = true;
     212             : 
     213          19 :     m_osDescription = pszDescription;
     214          19 : }
     215             : 
     216             : /************************************************************************/
     217             : /*                             SetOffset()                              */
     218             : /************************************************************************/
     219             : 
     220          42 : CPLErr GTiffRasterBand::SetOffset(double dfNewValue)
     221             : 
     222             : {
     223          42 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
     224             : 
     225          42 :     if (!m_bHaveOffsetScale || dfNewValue != m_dfOffset)
     226          38 :         m_poGDS->m_bMetadataChanged = true;
     227             : 
     228          42 :     m_bHaveOffsetScale = true;
     229          42 :     m_dfOffset = dfNewValue;
     230          42 :     return CE_None;
     231             : }
     232             : 
     233             : /************************************************************************/
     234             : /*                              SetScale()                              */
     235             : /************************************************************************/
     236             : 
     237          43 : CPLErr GTiffRasterBand::SetScale(double dfNewValue)
     238             : 
     239             : {
     240          43 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
     241             : 
     242          43 :     if (!m_bHaveOffsetScale || dfNewValue != m_dfScale)
     243          31 :         m_poGDS->m_bMetadataChanged = true;
     244             : 
     245          43 :     m_bHaveOffsetScale = true;
     246          43 :     m_dfScale = dfNewValue;
     247          43 :     return CE_None;
     248             : }
     249             : 
     250             : /************************************************************************/
     251             : /*                           SetUnitType()                              */
     252             : /************************************************************************/
     253             : 
     254          26 : CPLErr GTiffRasterBand::SetUnitType(const char *pszNewValue)
     255             : 
     256             : {
     257          26 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
     258             : 
     259          26 :     CPLString osNewValue(pszNewValue ? pszNewValue : "");
     260          26 :     if (osNewValue.compare(m_osUnitType) != 0)
     261          19 :         m_poGDS->m_bMetadataChanged = true;
     262             : 
     263          26 :     m_osUnitType = std::move(osNewValue);
     264          52 :     return CE_None;
     265             : }
     266             : 
     267             : /************************************************************************/
     268             : /*                            SetMetadata()                             */
     269             : /************************************************************************/
     270             : 
     271        4933 : CPLErr GTiffRasterBand::SetMetadata(char **papszMD, const char *pszDomain)
     272             : 
     273             : {
     274        4933 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
     275             : 
     276        4933 :     if (m_poGDS->m_bStreamingOut && m_poGDS->m_bCrystalized)
     277             :     {
     278           1 :         ReportError(CE_Failure, CPLE_NotSupported,
     279             :                     "Cannot modify metadata at that point in a streamed "
     280             :                     "output file");
     281           1 :         return CE_Failure;
     282             :     }
     283             : 
     284        4932 :     CPLErr eErr = CE_None;
     285        4932 :     if (eAccess == GA_Update)
     286             :     {
     287        4922 :         if (pszDomain == nullptr || !EQUAL(pszDomain, "_temporary_"))
     288             :         {
     289        4922 :             if (papszMD != nullptr || GetMetadata(pszDomain) != nullptr)
     290             :             {
     291          99 :                 m_poGDS->m_bMetadataChanged = true;
     292             :                 // Cancel any existing metadata from PAM file.
     293          99 :                 if (GDALPamRasterBand::GetMetadata(pszDomain) != nullptr)
     294           1 :                     GDALPamRasterBand::SetMetadata(nullptr, pszDomain);
     295             :             }
     296             :         }
     297             :     }
     298             :     else
     299             :     {
     300          10 :         CPLDebug(
     301             :             "GTIFF",
     302             :             "GTiffRasterBand::SetMetadata() goes to PAM instead of TIFF tags");
     303          10 :         eErr = GDALPamRasterBand::SetMetadata(papszMD, pszDomain);
     304             :     }
     305             : 
     306        4932 :     if (eErr == CE_None)
     307             :     {
     308        4932 :         eErr = m_oGTiffMDMD.SetMetadata(papszMD, pszDomain);
     309             :     }
     310        4932 :     return eErr;
     311             : }
     312             : 
     313             : /************************************************************************/
     314             : /*                          SetMetadataItem()                           */
     315             : /************************************************************************/
     316             : 
     317         632 : CPLErr GTiffRasterBand::SetMetadataItem(const char *pszName,
     318             :                                         const char *pszValue,
     319             :                                         const char *pszDomain)
     320             : 
     321             : {
     322         632 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
     323             : 
     324         632 :     if (m_poGDS->m_bStreamingOut && m_poGDS->m_bCrystalized)
     325             :     {
     326           1 :         ReportError(CE_Failure, CPLE_NotSupported,
     327             :                     "Cannot modify metadata at that point in a streamed "
     328             :                     "output file");
     329           1 :         return CE_Failure;
     330             :     }
     331             : 
     332         631 :     CPLErr eErr = CE_None;
     333         631 :     if (eAccess == GA_Update)
     334             :     {
     335         410 :         if (pszDomain == nullptr || !EQUAL(pszDomain, "_temporary_"))
     336             :         {
     337         410 :             m_poGDS->m_bMetadataChanged = true;
     338             :             // Cancel any existing metadata from PAM file.
     339         410 :             if (GDALPamRasterBand::GetMetadataItem(pszName, pszDomain) !=
     340             :                 nullptr)
     341           1 :                 GDALPamRasterBand::SetMetadataItem(pszName, nullptr, pszDomain);
     342             :         }
     343             :     }
     344             :     else
     345             :     {
     346         221 :         CPLDebug("GTIFF", "GTiffRasterBand::SetMetadataItem() goes to PAM "
     347             :                           "instead of TIFF tags");
     348         221 :         eErr = GDALPamRasterBand::SetMetadataItem(pszName, pszValue, pszDomain);
     349             :     }
     350             : 
     351         631 :     if (eErr == CE_None)
     352             :     {
     353         631 :         eErr = m_oGTiffMDMD.SetMetadataItem(pszName, pszValue, pszDomain);
     354             :     }
     355         631 :     return eErr;
     356             : }
     357             : 
     358             : /************************************************************************/
     359             : /*                       SetColorInterpretation()                       */
     360             : /************************************************************************/
     361             : 
     362         706 : CPLErr GTiffRasterBand::SetColorInterpretation(GDALColorInterp eInterp)
     363             : 
     364             : {
     365         706 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
     366             : 
     367         706 :     if (eInterp == m_eBandInterp)
     368         592 :         return CE_None;
     369             : 
     370         114 :     m_eBandInterp = eInterp;
     371             : 
     372         114 :     if (eAccess != GA_Update)
     373             :     {
     374           1 :         CPLDebug("GTIFF",
     375             :                  "ColorInterpretation %s for band %d goes to PAM "
     376             :                  "instead of TIFF tag",
     377             :                  GDALGetColorInterpretationName(eInterp), nBand);
     378           1 :         return GDALPamRasterBand::SetColorInterpretation(eInterp);
     379             :     }
     380             : 
     381         113 :     m_poGDS->m_bNeedsRewrite = true;
     382         113 :     m_poGDS->m_bMetadataChanged = true;
     383             : 
     384             :     // Try to autoset TIFFTAG_PHOTOMETRIC = PHOTOMETRIC_RGB if possible.
     385          57 :     if (m_poGDS->nBands >= 3 && m_poGDS->m_nCompression != COMPRESSION_JPEG &&
     386          57 :         m_poGDS->m_nPhotometric != PHOTOMETRIC_RGB &&
     387          31 :         CSLFetchNameValue(m_poGDS->m_papszCreationOptions, "PHOTOMETRIC") ==
     388         170 :             nullptr &&
     389          21 :         ((nBand == 1 && eInterp == GCI_RedBand) ||
     390          17 :          (nBand == 2 && eInterp == GCI_GreenBand) ||
     391          13 :          (nBand == 3 && eInterp == GCI_BlueBand)))
     392             :     {
     393          12 :         if (m_poGDS->GetRasterBand(1)->GetColorInterpretation() ==
     394          10 :                 GCI_RedBand &&
     395          10 :             m_poGDS->GetRasterBand(2)->GetColorInterpretation() ==
     396          22 :                 GCI_GreenBand &&
     397           7 :             m_poGDS->GetRasterBand(3)->GetColorInterpretation() == GCI_BlueBand)
     398             :         {
     399           4 :             m_poGDS->m_nPhotometric = PHOTOMETRIC_RGB;
     400           4 :             TIFFSetField(m_poGDS->m_hTIFF, TIFFTAG_PHOTOMETRIC,
     401           4 :                          m_poGDS->m_nPhotometric);
     402             : 
     403             :             // We need to update the number of extra samples.
     404           4 :             uint16_t *v = nullptr;
     405           4 :             uint16_t count = 0;
     406           4 :             const uint16_t nNewExtraSamplesCount =
     407           4 :                 static_cast<uint16_t>(m_poGDS->nBands - 3);
     408          10 :             if (m_poGDS->nBands >= 4 &&
     409           2 :                 TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_EXTRASAMPLES, &count,
     410           6 :                              &v) &&
     411           2 :                 count > nNewExtraSamplesCount)
     412             :             {
     413             :                 uint16_t *const pasNewExtraSamples = static_cast<uint16_t *>(
     414           2 :                     CPLMalloc(nNewExtraSamplesCount * sizeof(uint16_t)));
     415           2 :                 memcpy(pasNewExtraSamples, v + count - nNewExtraSamplesCount,
     416           2 :                        nNewExtraSamplesCount * sizeof(uint16_t));
     417             : 
     418           2 :                 TIFFSetField(m_poGDS->m_hTIFF, TIFFTAG_EXTRASAMPLES,
     419             :                              nNewExtraSamplesCount, pasNewExtraSamples);
     420             : 
     421           2 :                 CPLFree(pasNewExtraSamples);
     422             :             }
     423             :         }
     424          12 :         return CE_None;
     425             :     }
     426             : 
     427             :     // On the contrary, cancel the above if needed
     428         303 :     if (m_poGDS->m_nCompression != COMPRESSION_JPEG &&
     429         101 :         m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB &&
     430          26 :         CSLFetchNameValue(m_poGDS->m_papszCreationOptions, "PHOTOMETRIC") ==
     431         202 :             nullptr &&
     432           8 :         ((nBand == 1 && eInterp != GCI_RedBand) ||
     433           4 :          (nBand == 2 && eInterp != GCI_GreenBand) ||
     434           4 :          (nBand == 3 && eInterp != GCI_BlueBand)))
     435             :     {
     436           4 :         m_poGDS->m_nPhotometric = PHOTOMETRIC_MINISBLACK;
     437           4 :         TIFFSetField(m_poGDS->m_hTIFF, TIFFTAG_PHOTOMETRIC,
     438           4 :                      m_poGDS->m_nPhotometric);
     439             : 
     440             :         // We need to update the number of extra samples.
     441           4 :         uint16_t *v = nullptr;
     442           4 :         uint16_t count = 0;
     443           4 :         const uint16_t nNewExtraSamplesCount =
     444           4 :             static_cast<uint16_t>(m_poGDS->nBands - 1);
     445           4 :         if (m_poGDS->nBands >= 2)
     446             :         {
     447           4 :             TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v);
     448           4 :             if (nNewExtraSamplesCount > count)
     449             :             {
     450             :                 uint16_t *const pasNewExtraSamples = static_cast<uint16_t *>(
     451           4 :                     CPLMalloc(nNewExtraSamplesCount * sizeof(uint16_t)));
     452           4 :                 for (int i = 0;
     453          12 :                      i < static_cast<int>(nNewExtraSamplesCount - count); ++i)
     454           8 :                     pasNewExtraSamples[i] = EXTRASAMPLE_UNSPECIFIED;
     455           4 :                 if (count > 0)
     456             :                 {
     457           2 :                     memcpy(pasNewExtraSamples + nNewExtraSamplesCount - count,
     458           2 :                            v, count * sizeof(uint16_t));
     459             :                 }
     460             : 
     461           4 :                 TIFFSetField(m_poGDS->m_hTIFF, TIFFTAG_EXTRASAMPLES,
     462             :                              nNewExtraSamplesCount, pasNewExtraSamples);
     463             : 
     464           4 :                 CPLFree(pasNewExtraSamples);
     465             :             }
     466             :         }
     467             :     }
     468             : 
     469             :     // Mark non-RGB in extrasamples.
     470         101 :     if (eInterp != GCI_RedBand && eInterp != GCI_GreenBand &&
     471             :         eInterp != GCI_BlueBand)
     472             :     {
     473          88 :         uint16_t *v = nullptr;
     474          88 :         uint16_t count = 0;
     475         160 :         if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v) &&
     476          72 :             count > 0)
     477             :         {
     478          72 :             const int nBaseSamples = m_poGDS->m_nSamplesPerPixel - count;
     479             : 
     480          72 :             if (eInterp == GCI_AlphaBand)
     481             :             {
     482         256 :                 for (int i = 1; i <= m_poGDS->nBands; ++i)
     483             :                 {
     484         317 :                     if (i != nBand &&
     485         126 :                         m_poGDS->GetRasterBand(i)->GetColorInterpretation() ==
     486             :                             GCI_AlphaBand)
     487             :                     {
     488           4 :                         if (i == nBaseSamples + 1 &&
     489           2 :                             CSLFetchNameValue(m_poGDS->m_papszCreationOptions,
     490             :                                               "ALPHA") != nullptr)
     491             :                         {
     492           1 :                             ReportError(
     493             :                                 CE_Warning, CPLE_AppDefined,
     494             :                                 "Band %d was already identified as alpha band, "
     495             :                                 "and band %d is now marked as alpha too. "
     496             :                                 "Presumably ALPHA creation option is not "
     497             :                                 "needed",
     498             :                                 i, nBand);
     499             :                         }
     500             :                         else
     501             :                         {
     502           1 :                             ReportError(
     503             :                                 CE_Warning, CPLE_AppDefined,
     504             :                                 "Band %d was already identified as alpha band, "
     505             :                                 "and band %d is now marked as alpha too",
     506             :                                 i, nBand);
     507             :                         }
     508             :                     }
     509             :                 }
     510             :             }
     511             : 
     512          72 :             if (nBand > nBaseSamples && nBand - nBaseSamples - 1 < count)
     513             :             {
     514             :                 // We need to allocate a new array as (current) libtiff
     515             :                 // versions will not like that we reuse the array we got from
     516             :                 // TIFFGetField().
     517             : 
     518             :                 uint16_t *pasNewExtraSamples = static_cast<uint16_t *>(
     519          70 :                     CPLMalloc(count * sizeof(uint16_t)));
     520          70 :                 memcpy(pasNewExtraSamples, v, count * sizeof(uint16_t));
     521          70 :                 if (eInterp == GCI_AlphaBand)
     522             :                 {
     523         130 :                     pasNewExtraSamples[nBand - nBaseSamples - 1] =
     524          65 :                         GTiffGetAlphaValue(
     525             :                             CPLGetConfigOption("GTIFF_ALPHA", nullptr),
     526             :                             DEFAULT_ALPHA_TYPE);
     527             :                 }
     528             :                 else
     529             :                 {
     530           5 :                     pasNewExtraSamples[nBand - nBaseSamples - 1] =
     531             :                         EXTRASAMPLE_UNSPECIFIED;
     532             :                 }
     533             : 
     534          70 :                 TIFFSetField(m_poGDS->m_hTIFF, TIFFTAG_EXTRASAMPLES, count,
     535             :                              pasNewExtraSamples);
     536             : 
     537          70 :                 CPLFree(pasNewExtraSamples);
     538             : 
     539          70 :                 return CE_None;
     540             :             }
     541             :         }
     542             :     }
     543             : 
     544          31 :     if (m_poGDS->m_nPhotometric != PHOTOMETRIC_MINISBLACK &&
     545           0 :         CSLFetchNameValue(m_poGDS->m_papszCreationOptions, "PHOTOMETRIC") ==
     546             :             nullptr)
     547             :     {
     548           0 :         m_poGDS->m_nPhotometric = PHOTOMETRIC_MINISBLACK;
     549           0 :         TIFFSetField(m_poGDS->m_hTIFF, TIFFTAG_PHOTOMETRIC,
     550           0 :                      m_poGDS->m_nPhotometric);
     551             :     }
     552             : 
     553          31 :     return CE_None;
     554             : }
     555             : 
     556             : /************************************************************************/
     557             : /*                           SetColorTable()                            */
     558             : /************************************************************************/
     559             : 
     560          38 : CPLErr GTiffRasterBand::SetColorTable(GDALColorTable *poCT)
     561             : 
     562             : {
     563          38 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
     564             : 
     565             :     /* -------------------------------------------------------------------- */
     566             :     /*      Check if this is even a candidate for applying a PCT.           */
     567             :     /* -------------------------------------------------------------------- */
     568          38 :     if (eAccess == GA_Update)
     569             :     {
     570          36 :         if (nBand != 1)
     571             :         {
     572           1 :             ReportError(CE_Failure, CPLE_NotSupported,
     573             :                         "SetColorTable() can only be called on band 1.");
     574           1 :             return CE_Failure;
     575             :         }
     576             : 
     577          35 :         if (m_poGDS->m_nSamplesPerPixel != 1 &&
     578           3 :             m_poGDS->m_nSamplesPerPixel != 2)
     579             :         {
     580           1 :             ReportError(CE_Failure, CPLE_NotSupported,
     581             :                         "SetColorTable() not supported for multi-sample TIFF "
     582             :                         "files.");
     583           1 :             return CE_Failure;
     584             :         }
     585             : 
     586          34 :         if (eDataType != GDT_Byte && eDataType != GDT_UInt16)
     587             :         {
     588           1 :             ReportError(
     589             :                 CE_Failure, CPLE_NotSupported,
     590             :                 "SetColorTable() only supported for Byte or UInt16 bands "
     591             :                 "in TIFF format.");
     592           1 :             return CE_Failure;
     593             :         }
     594             : 
     595             :         // Clear any existing PAM color table
     596          33 :         if (GDALPamRasterBand::GetColorTable() != nullptr)
     597             :         {
     598           1 :             GDALPamRasterBand::SetColorTable(nullptr);
     599           1 :             GDALPamRasterBand::SetColorInterpretation(GCI_Undefined);
     600             :         }
     601             :     }
     602             : 
     603             :     /* -------------------------------------------------------------------- */
     604             :     /*      Is this really a request to clear the color table?              */
     605             :     /* -------------------------------------------------------------------- */
     606          35 :     if (poCT == nullptr || poCT->GetColorEntryCount() == 0)
     607             :     {
     608           1 :         if (eAccess == GA_Update)
     609             :         {
     610           1 :             TIFFSetField(m_poGDS->m_hTIFF, TIFFTAG_PHOTOMETRIC,
     611             :                          PHOTOMETRIC_MINISBLACK);
     612             : 
     613           1 :             TIFFUnsetField(m_poGDS->m_hTIFF, TIFFTAG_COLORMAP);
     614             :         }
     615             : 
     616           1 :         m_poGDS->m_poColorTable.reset();
     617             : 
     618           1 :         return CE_None;
     619             :     }
     620             : 
     621             :     /* -------------------------------------------------------------------- */
     622             :     /*      Write out the colortable, and update the configuration.         */
     623             :     /* -------------------------------------------------------------------- */
     624          34 :     CPLErr eErr = CE_None;
     625          34 :     if (eAccess == GA_Update)
     626             :     {
     627          32 :         int nColors = 65536;
     628             : 
     629          32 :         if (eDataType == GDT_Byte)
     630          31 :             nColors = 256;
     631             : 
     632             :         unsigned short *panTRed = static_cast<unsigned short *>(
     633          32 :             CPLMalloc(sizeof(unsigned short) * nColors));
     634             :         unsigned short *panTGreen = static_cast<unsigned short *>(
     635          32 :             CPLMalloc(sizeof(unsigned short) * nColors));
     636             :         unsigned short *panTBlue = static_cast<unsigned short *>(
     637          32 :             CPLMalloc(sizeof(unsigned short) * nColors));
     638             : 
     639          32 :         if (m_poGDS->m_nColorTableMultiplier == 0)
     640           0 :             m_poGDS->m_nColorTableMultiplier =
     641             :                 GTiffDataset::DEFAULT_COLOR_TABLE_MULTIPLIER_257;
     642             : 
     643       73504 :         for (int iColor = 0; iColor < nColors; ++iColor)
     644             :         {
     645       73472 :             if (iColor < poCT->GetColorEntryCount())
     646             :             {
     647             :                 GDALColorEntry sRGB;
     648        3652 :                 poCT->GetColorEntryAsRGB(iColor, &sRGB);
     649             : 
     650        7304 :                 panTRed[iColor] = GTiffDataset::ClampCTEntry(
     651        3652 :                     iColor, 1, sRGB.c1, m_poGDS->m_nColorTableMultiplier);
     652        7304 :                 panTGreen[iColor] = GTiffDataset::ClampCTEntry(
     653        3652 :                     iColor, 2, sRGB.c2, m_poGDS->m_nColorTableMultiplier);
     654        3652 :                 panTBlue[iColor] = GTiffDataset::ClampCTEntry(
     655        3652 :                     iColor, 3, sRGB.c3, m_poGDS->m_nColorTableMultiplier);
     656             :             }
     657             :             else
     658             :             {
     659       69820 :                 panTRed[iColor] = 0;
     660       69820 :                 panTGreen[iColor] = 0;
     661       69820 :                 panTBlue[iColor] = 0;
     662             :             }
     663             :         }
     664             : 
     665          32 :         TIFFSetField(m_poGDS->m_hTIFF, TIFFTAG_PHOTOMETRIC,
     666             :                      PHOTOMETRIC_PALETTE);
     667          32 :         TIFFSetField(m_poGDS->m_hTIFF, TIFFTAG_COLORMAP, panTRed, panTGreen,
     668             :                      panTBlue);
     669             : 
     670          32 :         CPLFree(panTRed);
     671          32 :         CPLFree(panTGreen);
     672          32 :         CPLFree(panTBlue);
     673             : 
     674             :         // libtiff 3.X needs setting this in all cases (creation or update)
     675             :         // whereas libtiff 4.X would just need it if there
     676             :         // was no color table before.
     677          32 :         m_poGDS->m_bNeedsRewrite = true;
     678             :     }
     679             :     else
     680             :     {
     681           2 :         eErr = GDALPamRasterBand::SetColorTable(poCT);
     682             :     }
     683             : 
     684          34 :     m_poGDS->m_poColorTable.reset(poCT->Clone());
     685          34 :     m_eBandInterp = GCI_PaletteIndex;
     686             : 
     687          34 :     return eErr;
     688             : }
     689             : 
     690             : /************************************************************************/
     691             : /*                           SetNoDataValue()                           */
     692             : /************************************************************************/
     693             : 
     694         513 : CPLErr GTiffRasterBand::SetNoDataValue(double dfNoData)
     695             : 
     696             : {
     697        1025 :     const auto SetNoDataMembers = [this, dfNoData]()
     698             :     {
     699         512 :         m_bNoDataSet = true;
     700         512 :         m_dfNoDataValue = dfNoData;
     701             : 
     702         512 :         m_poGDS->m_bNoDataSet = true;
     703         512 :         m_poGDS->m_dfNoDataValue = dfNoData;
     704             : 
     705         512 :         if (eDataType == GDT_Int64 && GDALIsValueExactAs<int64_t>(dfNoData))
     706             :         {
     707           1 :             m_bNoDataSetAsInt64 = true;
     708           1 :             m_nNoDataValueInt64 = static_cast<int64_t>(dfNoData);
     709             : 
     710           1 :             m_poGDS->m_bNoDataSetAsInt64 = true;
     711           1 :             m_poGDS->m_nNoDataValueInt64 = static_cast<int64_t>(dfNoData);
     712             :         }
     713         511 :         else if (eDataType == GDT_UInt64 &&
     714           0 :                  GDALIsValueExactAs<uint64_t>(dfNoData))
     715             :         {
     716           0 :             m_bNoDataSetAsUInt64 = true;
     717           0 :             m_nNoDataValueUInt64 = static_cast<uint64_t>(dfNoData);
     718             : 
     719           0 :             m_poGDS->m_bNoDataSetAsUInt64 = true;
     720           0 :             m_poGDS->m_nNoDataValueUInt64 = static_cast<uint64_t>(dfNoData);
     721             :         }
     722        1025 :     };
     723             : 
     724         513 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
     725             : 
     726         687 :     if (m_poGDS->m_bNoDataSet &&
     727         188 :         (m_poGDS->m_dfNoDataValue == dfNoData ||
     728          22 :          (std::isnan(m_poGDS->m_dfNoDataValue) && std::isnan(dfNoData))))
     729             :     {
     730         168 :         ResetNoDataValues(false);
     731             : 
     732         168 :         SetNoDataMembers();
     733             : 
     734         168 :         return CE_None;
     735             :     }
     736             : 
     737         345 :     if (m_poGDS->nBands > 1 && m_poGDS->m_eProfile == GTiffProfile::GDALGEOTIFF)
     738             :     {
     739         107 :         int bOtherBandHasNoData = FALSE;
     740         107 :         const int nOtherBand = nBand > 1 ? 1 : 2;
     741         107 :         double dfOtherNoData = m_poGDS->GetRasterBand(nOtherBand)
     742         107 :                                    ->GetNoDataValue(&bOtherBandHasNoData);
     743         107 :         if (bOtherBandHasNoData && dfOtherNoData != dfNoData)
     744             :         {
     745           2 :             ReportError(
     746             :                 CE_Warning, CPLE_AppDefined,
     747             :                 "Setting nodata to %.17g on band %d, but band %d has nodata "
     748             :                 "at %.17g. The TIFFTAG_GDAL_NODATA only support one value "
     749             :                 "per dataset. This value of %.17g will be used for all bands "
     750             :                 "on re-opening",
     751             :                 dfNoData, nBand, nOtherBand, dfOtherNoData, dfNoData);
     752             :         }
     753             :     }
     754             : 
     755         345 :     if (m_poGDS->m_bStreamingOut && m_poGDS->m_bCrystalized)
     756             :     {
     757           1 :         ReportError(
     758             :             CE_Failure, CPLE_NotSupported,
     759             :             "Cannot modify nodata at that point in a streamed output file");
     760           1 :         return CE_Failure;
     761             :     }
     762             : 
     763         344 :     CPLErr eErr = CE_None;
     764         344 :     if (eAccess == GA_Update)
     765             :     {
     766         339 :         m_poGDS->m_bNoDataChanged = true;
     767         339 :         int bSuccess = FALSE;
     768         339 :         CPL_IGNORE_RET_VAL(GDALPamRasterBand::GetNoDataValue(&bSuccess));
     769         339 :         if (bSuccess)
     770             :         {
     771             :             // Cancel any existing nodata from PAM file.
     772           1 :             eErr = GDALPamRasterBand::DeleteNoDataValue();
     773             :         }
     774             :     }
     775             :     else
     776             :     {
     777           5 :         CPLDebug("GTIFF", "SetNoDataValue() goes to PAM instead of TIFF tags");
     778           5 :         eErr = GDALPamRasterBand::SetNoDataValue(dfNoData);
     779             :     }
     780             : 
     781         344 :     if (eErr == CE_None)
     782             :     {
     783         344 :         ResetNoDataValues(true);
     784             : 
     785         344 :         SetNoDataMembers();
     786             :     }
     787             : 
     788         344 :     return eErr;
     789             : }
     790             : 
     791             : /************************************************************************/
     792             : /*                       SetNoDataValueAsInt64()                        */
     793             : /************************************************************************/
     794             : 
     795           2 : CPLErr GTiffRasterBand::SetNoDataValueAsInt64(int64_t nNoData)
     796             : 
     797             : {
     798           2 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
     799             : 
     800           2 :     if (m_poGDS->m_bNoDataSetAsInt64 && m_poGDS->m_nNoDataValueInt64 == nNoData)
     801             :     {
     802           0 :         ResetNoDataValues(false);
     803             : 
     804           0 :         m_bNoDataSetAsInt64 = true;
     805           0 :         m_nNoDataValueInt64 = nNoData;
     806             : 
     807           0 :         return CE_None;
     808             :     }
     809             : 
     810           2 :     if (m_poGDS->nBands > 1 && m_poGDS->m_eProfile == GTiffProfile::GDALGEOTIFF)
     811             :     {
     812           0 :         int bOtherBandHasNoData = FALSE;
     813           0 :         const int nOtherBand = nBand > 1 ? 1 : 2;
     814             :         const auto nOtherNoData =
     815           0 :             m_poGDS->GetRasterBand(nOtherBand)
     816           0 :                 ->GetNoDataValueAsInt64(&bOtherBandHasNoData);
     817           0 :         if (bOtherBandHasNoData && nOtherNoData != nNoData)
     818             :         {
     819           0 :             ReportError(CE_Warning, CPLE_AppDefined,
     820             :                         "Setting nodata to " CPL_FRMT_GIB
     821             :                         " on band %d, but band %d has nodata "
     822             :                         "at " CPL_FRMT_GIB
     823             :                         ". The TIFFTAG_GDAL_NODATA only support one value "
     824             :                         "per dataset. This value of " CPL_FRMT_GIB
     825             :                         " will be used for all bands "
     826             :                         "on re-opening",
     827             :                         static_cast<GIntBig>(nNoData), nBand, nOtherBand,
     828             :                         static_cast<GIntBig>(nOtherNoData),
     829             :                         static_cast<GIntBig>(nNoData));
     830             :         }
     831             :     }
     832             : 
     833           2 :     if (m_poGDS->m_bStreamingOut && m_poGDS->m_bCrystalized)
     834             :     {
     835           0 :         ReportError(
     836             :             CE_Failure, CPLE_NotSupported,
     837             :             "Cannot modify nodata at that point in a streamed output file");
     838           0 :         return CE_Failure;
     839             :     }
     840             : 
     841           2 :     CPLErr eErr = CE_None;
     842           2 :     if (eAccess == GA_Update)
     843             :     {
     844           2 :         m_poGDS->m_bNoDataChanged = true;
     845           2 :         int bSuccess = FALSE;
     846           2 :         CPL_IGNORE_RET_VAL(GDALPamRasterBand::GetNoDataValueAsInt64(&bSuccess));
     847           2 :         if (bSuccess)
     848             :         {
     849             :             // Cancel any existing nodata from PAM file.
     850           0 :             eErr = GDALPamRasterBand::DeleteNoDataValue();
     851             :         }
     852             :     }
     853             :     else
     854             :     {
     855           0 :         CPLDebug("GTIFF", "SetNoDataValue() goes to PAM instead of TIFF tags");
     856           0 :         eErr = GDALPamRasterBand::SetNoDataValueAsInt64(nNoData);
     857             :     }
     858             : 
     859           2 :     if (eErr == CE_None)
     860             :     {
     861           2 :         ResetNoDataValues(true);
     862             : 
     863           2 :         m_poGDS->m_bNoDataSetAsInt64 = true;
     864           2 :         m_poGDS->m_nNoDataValueInt64 = nNoData;
     865             :     }
     866             : 
     867           2 :     return eErr;
     868             : }
     869             : 
     870             : /************************************************************************/
     871             : /*                      SetNoDataValueAsUInt64()                        */
     872             : /************************************************************************/
     873             : 
     874           2 : CPLErr GTiffRasterBand::SetNoDataValueAsUInt64(uint64_t nNoData)
     875             : 
     876             : {
     877           2 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
     878             : 
     879           2 :     if (m_poGDS->m_bNoDataSetAsUInt64 &&
     880           0 :         m_poGDS->m_nNoDataValueUInt64 == nNoData)
     881             :     {
     882           0 :         ResetNoDataValues(false);
     883             : 
     884           0 :         m_bNoDataSetAsUInt64 = true;
     885           0 :         m_nNoDataValueUInt64 = nNoData;
     886             : 
     887           0 :         return CE_None;
     888             :     }
     889             : 
     890           2 :     if (m_poGDS->nBands > 1 && m_poGDS->m_eProfile == GTiffProfile::GDALGEOTIFF)
     891             :     {
     892           0 :         int bOtherBandHasNoData = FALSE;
     893           0 :         const int nOtherBand = nBand > 1 ? 1 : 2;
     894             :         const auto nOtherNoData =
     895           0 :             m_poGDS->GetRasterBand(nOtherBand)
     896           0 :                 ->GetNoDataValueAsUInt64(&bOtherBandHasNoData);
     897           0 :         if (bOtherBandHasNoData && nOtherNoData != nNoData)
     898             :         {
     899           0 :             ReportError(CE_Warning, CPLE_AppDefined,
     900             :                         "Setting nodata to " CPL_FRMT_GUIB
     901             :                         " on band %d, but band %d has nodata "
     902             :                         "at " CPL_FRMT_GUIB
     903             :                         ". The TIFFTAG_GDAL_NODATA only support one value "
     904             :                         "per dataset. This value of " CPL_FRMT_GUIB
     905             :                         " will be used for all bands "
     906             :                         "on re-opening",
     907             :                         static_cast<GUIntBig>(nNoData), nBand, nOtherBand,
     908             :                         static_cast<GUIntBig>(nOtherNoData),
     909             :                         static_cast<GUIntBig>(nNoData));
     910             :         }
     911             :     }
     912             : 
     913           2 :     if (m_poGDS->m_bStreamingOut && m_poGDS->m_bCrystalized)
     914             :     {
     915           0 :         ReportError(
     916             :             CE_Failure, CPLE_NotSupported,
     917             :             "Cannot modify nodata at that point in a streamed output file");
     918           0 :         return CE_Failure;
     919             :     }
     920             : 
     921           2 :     CPLErr eErr = CE_None;
     922           2 :     if (eAccess == GA_Update)
     923             :     {
     924           2 :         m_poGDS->m_bNoDataChanged = true;
     925           2 :         int bSuccess = FALSE;
     926           2 :         CPL_IGNORE_RET_VAL(
     927           2 :             GDALPamRasterBand::GetNoDataValueAsUInt64(&bSuccess));
     928           2 :         if (bSuccess)
     929             :         {
     930             :             // Cancel any existing nodata from PAM file.
     931           0 :             eErr = GDALPamRasterBand::DeleteNoDataValue();
     932             :         }
     933             :     }
     934             :     else
     935             :     {
     936           0 :         CPLDebug("GTIFF", "SetNoDataValue() goes to PAM instead of TIFF tags");
     937           0 :         eErr = GDALPamRasterBand::SetNoDataValueAsUInt64(nNoData);
     938             :     }
     939             : 
     940           2 :     if (eErr == CE_None)
     941             :     {
     942           2 :         ResetNoDataValues(true);
     943             : 
     944           2 :         m_poGDS->m_bNoDataSetAsUInt64 = true;
     945           2 :         m_poGDS->m_nNoDataValueUInt64 = nNoData;
     946             : 
     947           2 :         m_bNoDataSetAsUInt64 = true;
     948           2 :         m_nNoDataValueUInt64 = nNoData;
     949             :     }
     950             : 
     951           2 :     return eErr;
     952             : }
     953             : 
     954             : /************************************************************************/
     955             : /*                        ResetNoDataValues()                           */
     956             : /************************************************************************/
     957             : 
     958         531 : void GTiffRasterBand::ResetNoDataValues(bool bResetDatasetToo)
     959             : {
     960         531 :     if (bResetDatasetToo)
     961             :     {
     962         363 :         m_poGDS->m_bNoDataSet = false;
     963         363 :         m_poGDS->m_dfNoDataValue = DEFAULT_NODATA_VALUE;
     964             :     }
     965             : 
     966         531 :     m_bNoDataSet = false;
     967         531 :     m_dfNoDataValue = DEFAULT_NODATA_VALUE;
     968             : 
     969         531 :     if (bResetDatasetToo)
     970             :     {
     971         363 :         m_poGDS->m_bNoDataSetAsInt64 = false;
     972         363 :         m_poGDS->m_nNoDataValueInt64 = GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
     973             :     }
     974             : 
     975         531 :     m_bNoDataSetAsInt64 = false;
     976         531 :     m_nNoDataValueInt64 = GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
     977             : 
     978         531 :     if (bResetDatasetToo)
     979             :     {
     980         363 :         m_poGDS->m_bNoDataSetAsUInt64 = false;
     981         363 :         m_poGDS->m_nNoDataValueUInt64 = GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
     982             :     }
     983             : 
     984         531 :     m_bNoDataSetAsUInt64 = false;
     985         531 :     m_nNoDataValueUInt64 = GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
     986         531 : }
     987             : 
     988             : /************************************************************************/
     989             : /*                        DeleteNoDataValue()                           */
     990             : /************************************************************************/
     991             : 
     992          15 : CPLErr GTiffRasterBand::DeleteNoDataValue()
     993             : 
     994             : {
     995          15 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
     996             : 
     997          15 :     if (m_poGDS->m_bStreamingOut && m_poGDS->m_bCrystalized)
     998             :     {
     999           0 :         ReportError(
    1000             :             CE_Failure, CPLE_NotSupported,
    1001             :             "Cannot modify nodata at that point in a streamed output file");
    1002           0 :         return CE_Failure;
    1003             :     }
    1004             : 
    1005          15 :     if (eAccess == GA_Update)
    1006             :     {
    1007          14 :         if (m_poGDS->m_bNoDataSet)
    1008          14 :             m_poGDS->m_bNoDataChanged = true;
    1009             :     }
    1010             :     else
    1011             :     {
    1012           1 :         CPLDebug("GTIFF",
    1013             :                  "DeleteNoDataValue() goes to PAM instead of TIFF tags");
    1014             :     }
    1015             : 
    1016          15 :     CPLErr eErr = GDALPamRasterBand::DeleteNoDataValue();
    1017          15 :     if (eErr == CE_None)
    1018             :     {
    1019          15 :         ResetNoDataValues(true);
    1020             :     }
    1021             : 
    1022          15 :     return eErr;
    1023             : }
    1024             : 
    1025             : /************************************************************************/
    1026             : /*                             NullBlock()                              */
    1027             : /*                                                                      */
    1028             : /*      Set the block data to the null value if it is set, or zero      */
    1029             : /*      if there is no null data value.                                 */
    1030             : /************************************************************************/
    1031             : 
    1032       54932 : void GTiffRasterBand::NullBlock(void *pData)
    1033             : 
    1034             : {
    1035       54932 :     const GPtrDiff_t nWords =
    1036       54932 :         static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
    1037       54932 :     const int nChunkSize = std::max(1, GDALGetDataTypeSizeBytes(eDataType));
    1038             : 
    1039       54932 :     int l_bNoDataSet = FALSE;
    1040       54932 :     if (eDataType == GDT_Int64)
    1041             :     {
    1042           2 :         const auto nVal = GetNoDataValueAsInt64(&l_bNoDataSet);
    1043           2 :         if (!l_bNoDataSet)
    1044             :         {
    1045           1 :             memset(pData, 0, nWords * nChunkSize);
    1046             :         }
    1047             :         else
    1048             :         {
    1049           1 :             GDALCopyWords64(&nVal, GDT_Int64, 0, pData, eDataType, nChunkSize,
    1050             :                             nWords);
    1051             :         }
    1052             :     }
    1053       54930 :     else if (eDataType == GDT_UInt64)
    1054             :     {
    1055           2 :         const auto nVal = GetNoDataValueAsUInt64(&l_bNoDataSet);
    1056           2 :         if (!l_bNoDataSet)
    1057             :         {
    1058           2 :             memset(pData, 0, nWords * nChunkSize);
    1059             :         }
    1060             :         else
    1061             :         {
    1062           0 :             GDALCopyWords64(&nVal, GDT_UInt64, 0, pData, eDataType, nChunkSize,
    1063             :                             nWords);
    1064             :         }
    1065             :     }
    1066             :     else
    1067             :     {
    1068       54928 :         double dfNoData = GetNoDataValue(&l_bNoDataSet);
    1069       54928 :         if (!l_bNoDataSet)
    1070             :         {
    1071             : #ifdef ESRI_BUILD
    1072             :             if (m_poGDS->m_nBitsPerSample >= 2)
    1073             :                 memset(pData, 0, nWords * nChunkSize);
    1074             :             else
    1075             :                 memset(pData, 1, nWords * nChunkSize);
    1076             : #else
    1077       51807 :             memset(pData, 0, nWords * nChunkSize);
    1078             : #endif
    1079             :         }
    1080             :         else
    1081             :         {
    1082             :             // Will convert nodata value to the right type and copy efficiently.
    1083        3121 :             GDALCopyWords64(&dfNoData, GDT_Float64, 0, pData, eDataType,
    1084             :                             nChunkSize, nWords);
    1085             :         }
    1086             :     }
    1087       54932 : }

Generated by: LCOV version 1.14