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

Generated by: LCOV version 1.14