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

Generated by: LCOV version 1.14