LCOV - code coverage report
Current view: top level - frmts/kea - keaband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 528 728 72.5 %
Date: 2026-01-18 23:37:47 Functions: 33 38 86.8 %

          Line data    Source code
       1             : /*
       2             :  *  keaband.cpp
       3             :  *
       4             :  *  Created by Pete Bunting on 01/08/2012.
       5             :  *  Copyright 2012 LibKEA. All rights reserved.
       6             :  *
       7             :  *  This file is part of LibKEA.
       8             :  *
       9             :  * SPDX-License-Identifier: MIT
      10             :  *
      11             :  */
      12             : 
      13             : #include "keaband.h"
      14             : #include "keaoverview.h"
      15             : #include "keamaskband.h"
      16             : #include "kearat.h"
      17             : 
      18             : #include "gdal_rat.h"
      19             : 
      20             : #include <map>
      21             : #include <vector>
      22             : #include <limits>
      23             : 
      24             : // constructor
      25         405 : KEARasterBand::KEARasterBand(KEADataset *pDataset, int nSrcBand,
      26             :                              GDALAccess eAccessIn, kealib::KEAImageIO *pImageIO,
      27         405 :                              LockedRefCount *pRefCount)
      28         810 :     : m_eKEADataType(pImageIO->getImageBandDataType(
      29         405 :           nSrcBand))  // get the data type as KEA enum
      30             : {
      31         405 :     this->m_hMutex = CPLCreateMutex();
      32         405 :     CPLReleaseMutex(this->m_hMutex);
      33             : 
      34         405 :     this->poDS = pDataset;   // our pointer onto the dataset
      35         405 :     this->nBand = nSrcBand;  // this is the band we are
      36         405 :     this->eDataType = KEA_to_GDAL_Type(m_eKEADataType);  // convert to GDAL enum
      37         405 :     this->nBlockXSize =
      38         405 :         pImageIO->getImageBlockSize(nSrcBand);  // get the native blocksize
      39         405 :     this->nBlockYSize = pImageIO->getImageBlockSize(nSrcBand);
      40         405 :     this->nRasterXSize =
      41         405 :         this->poDS
      42         405 :             ->GetRasterXSize();  // ask the dataset for the total image size
      43         405 :     this->nRasterYSize = this->poDS->GetRasterYSize();
      44         405 :     this->eAccess = eAccessIn;
      45             : 
      46         405 :     if (pImageIO->attributeTablePresent(nSrcBand))
      47             :     {
      48          10 :         this->m_nAttributeChunkSize =
      49          10 :             pImageIO->getAttributeTableChunkSize(nSrcBand);
      50             :     }
      51             :     else
      52             :     {
      53         395 :         this->m_nAttributeChunkSize = -1;  // don't report
      54             :     }
      55             : 
      56             :     // grab the imageio class and its refcount
      57         405 :     this->m_pImageIO = pImageIO;
      58         405 :     this->m_pRefCount = pRefCount;
      59             :     // increment the refcount as we now have a reference to imageio
      60         405 :     this->m_pRefCount->IncRef();
      61             : 
      62             :     // Initialize overview variables
      63         405 :     m_nOverviews = 0;
      64         405 :     m_panOverviewBands = nullptr;
      65             : 
      66             :     // mask band
      67         405 :     m_pMaskBand = nullptr;
      68         405 :     m_bMaskBandOwned = false;
      69             : 
      70             :     // grab the description here
      71         405 :     this->sDescription = pImageIO->getImageBandDescription(nSrcBand);
      72             : 
      73         405 :     this->m_pAttributeTable = nullptr;  // no RAT yet
      74         405 :     this->m_pColorTable = nullptr;      // no color table yet
      75             : 
      76             :     // Initialize the metadata as a CPLStringList.
      77         405 :     m_papszMetadataList = nullptr;
      78         405 :     this->UpdateMetadataList();
      79         405 :     m_pszHistoBinValues = nullptr;
      80         405 : }
      81             : 
      82             : // destructor
      83         807 : KEARasterBand::~KEARasterBand()
      84             : {
      85             :     {
      86         810 :         CPLMutexHolderD(&m_hMutex);
      87             :         // destroy RAT if any
      88         405 :         delete this->m_pAttributeTable;
      89             :         // destroy color table if any
      90         405 :         delete this->m_pColorTable;
      91             :         // destroy the metadata
      92         405 :         CSLDestroy(this->m_papszMetadataList);
      93         405 :         if (this->m_pszHistoBinValues != nullptr)
      94             :         {
      95             :             // histogram bin values as a string
      96           0 :             CPLFree(this->m_pszHistoBinValues);
      97             :         }
      98             :         // delete any overview bands
      99         405 :         this->deleteOverviewObjects();
     100             : 
     101             :         // if GDAL created the mask it will delete it
     102         405 :         if (m_bMaskBandOwned)
     103             :         {
     104           3 :             delete m_pMaskBand;
     105             :         }
     106             :     }
     107             : 
     108             :     // according to the docs, this is required
     109         405 :     this->FlushCache(true);
     110             : 
     111             :     // decrement the recount and delete if needed
     112         405 :     if (m_pRefCount->DecRef())
     113             :     {
     114             :         try
     115             :         {
     116         271 :             m_pImageIO->close();
     117             :         }
     118           0 :         catch (const kealib::KEAIOException &)
     119             :         {
     120             :         }
     121         271 :         delete m_pImageIO;
     122         271 :         delete m_pRefCount;
     123             :     }
     124         807 : }
     125             : 
     126             : // internal method that updates the metadata into m_papszMetadataList
     127         405 : void KEARasterBand::UpdateMetadataList()
     128             : {
     129         810 :     CPLMutexHolderD(&m_hMutex);
     130         810 :     std::vector<std::pair<std::string, std::string>> data;
     131             : 
     132             :     // get all the metadata and iterate through
     133         405 :     data = this->m_pImageIO->getImageBandMetaData(this->nBand);
     134         127 :     for (std::vector<std::pair<std::string, std::string>>::iterator
     135         405 :              iterMetaData = data.begin();
     136         532 :          iterMetaData != data.end(); ++iterMetaData)
     137             :     {
     138             :         // add to our list
     139         127 :         m_papszMetadataList =
     140         127 :             CSLSetNameValue(m_papszMetadataList, iterMetaData->first.c_str(),
     141         127 :                             iterMetaData->second.c_str());
     142             :     }
     143             :     // we have a pseudo metadata item that tells if we are thematic
     144             :     // or continuous like the HFA driver
     145         405 :     if (this->m_pImageIO->getImageBandLayerType(this->nBand) ==
     146             :         kealib::kea_continuous)
     147             :     {
     148         396 :         m_papszMetadataList =
     149         396 :             CSLSetNameValue(m_papszMetadataList, "LAYER_TYPE", "athematic");
     150             :     }
     151             :     else
     152             :     {
     153           9 :         m_papszMetadataList =
     154           9 :             CSLSetNameValue(m_papszMetadataList, "LAYER_TYPE", "thematic");
     155             :     }
     156             : 
     157             :     // STATISTICS_HISTONUMBINS
     158         405 :     const GDALRasterAttributeTable *pTable = KEARasterBand::GetDefaultRAT();
     159         405 :     if (pTable != nullptr)
     160             :     {
     161         810 :         CPLString osWorkingResult;
     162         405 :         osWorkingResult.Printf("%lu", (unsigned long)pTable->GetRowCount());
     163         405 :         m_papszMetadataList = CSLSetNameValue(
     164             :             m_papszMetadataList, "STATISTICS_HISTONUMBINS", osWorkingResult);
     165             : 
     166             :         // attribute table chunksize
     167         405 :         if (this->m_nAttributeChunkSize != -1)
     168             :         {
     169          10 :             osWorkingResult.Printf("%d", this->m_nAttributeChunkSize);
     170          10 :             m_papszMetadataList =
     171          10 :                 CSLSetNameValue(m_papszMetadataList, "ATTRIBUTETABLE_CHUNKSIZE",
     172             :                                 osWorkingResult);
     173             :         }
     174             :     }
     175         405 : }
     176             : 
     177             : // internal method to set the histogram column from a string (for metadata)
     178             : 
     179           0 : CPLErr KEARasterBand::SetHistogramFromString(const char *pszString)
     180             : {
     181             :     // copy it so we can change it (put nulls in etc)
     182           0 :     char *pszBinValues = CPLStrdup(pszString);
     183           0 :     if (pszBinValues == nullptr)
     184           0 :         return CE_Failure;
     185             : 
     186             :     // find the number of | chars
     187           0 :     int nRows = 0, i = 0;
     188           0 :     while (pszBinValues[i] != '\0')
     189             :     {
     190           0 :         if (pszBinValues[i] == '|')
     191           0 :             nRows++;
     192           0 :         i++;
     193             :     }
     194             : 
     195           0 :     GDALRasterAttributeTable *pTable = this->GetDefaultRAT();
     196           0 :     if (pTable == nullptr)
     197             :     {
     198           0 :         CPLFree(pszBinValues);
     199           0 :         return CE_Failure;
     200             :     }
     201             : 
     202             :     // find histogram column if it exists
     203           0 :     int nCol = pTable->GetColOfUsage(GFU_PixelCount);
     204           0 :     if (nCol == -1)
     205             :     {
     206           0 :         if (pTable->CreateColumn("Histogram", GFT_Real, GFU_PixelCount) !=
     207             :             CE_None)
     208             :         {
     209           0 :             CPLFree(pszBinValues);
     210           0 :             return CE_Failure;
     211             :         }
     212             : 
     213           0 :         nCol = pTable->GetColumnCount() - 1;
     214             :     }
     215             : 
     216           0 :     if (nRows > pTable->GetRowCount())
     217           0 :         pTable->SetRowCount(nRows);
     218             : 
     219           0 :     char *pszWork = pszBinValues;
     220           0 :     for (int nBin = 0; nBin < nRows; ++nBin)
     221             :     {
     222           0 :         char *pszEnd = strchr(pszWork, '|');
     223           0 :         if (pszEnd != nullptr)
     224             :         {
     225           0 :             *pszEnd = 0;
     226           0 :             double dValue = CPLAtof(pszWork);
     227           0 :             pTable->SetValue(nBin, nCol, dValue);
     228           0 :             pszWork = pszEnd + 1;
     229             :         }
     230             :     }
     231             : 
     232           0 :     CPLFree(pszBinValues);
     233             : 
     234           0 :     return CE_None;
     235             : }
     236             : 
     237             : // get histogram as string with values separated by '|'
     238           0 : char *KEARasterBand::GetHistogramAsString()
     239             : {
     240           0 :     const GDALRasterAttributeTable *pTable = this->GetDefaultRAT();
     241           0 :     if (pTable == nullptr)
     242           0 :         return nullptr;
     243           0 :     int nRows = pTable->GetRowCount();
     244             :     // find histogram column if it exists
     245           0 :     int nCol = pTable->GetColOfUsage(GFU_PixelCount);
     246           0 :     if (nCol == -1)
     247           0 :         return nullptr;
     248             : 
     249           0 :     unsigned int nBufSize = 1024;
     250           0 :     char *pszBinValues = (char *)CPLMalloc(nBufSize);
     251           0 :     int nBinValuesLen = 0;
     252           0 :     pszBinValues[0] = 0;
     253             : 
     254           0 :     for (int nBin = 0; nBin < nRows; ++nBin)
     255             :     {
     256             :         char szBuf[32];
     257             :         // RAT's don't handle GUIntBig - use double instead. Cast back
     258           0 :         snprintf(szBuf, 31, CPL_FRMT_GUIB,
     259           0 :                  (GUIntBig)pTable->GetValueAsDouble(nBin, nCol));
     260           0 :         if ((nBinValuesLen + strlen(szBuf) + 2) > nBufSize)
     261             :         {
     262           0 :             nBufSize *= 2;
     263           0 :             char *pszNewBinValues = (char *)VSIRealloc(pszBinValues, nBufSize);
     264           0 :             if (pszNewBinValues == nullptr)
     265             :             {
     266           0 :                 break;
     267             :             }
     268             : 
     269           0 :             pszBinValues = pszNewBinValues;
     270             :         }
     271             : 
     272           0 :         strcat(pszBinValues + nBinValuesLen, szBuf);
     273           0 :         strcat(pszBinValues + nBinValuesLen, "|");
     274           0 :         nBinValuesLen += static_cast<int>(strlen(pszBinValues + nBinValuesLen));
     275             :     }
     276             : 
     277           0 :     return pszBinValues;
     278             : }
     279             : 
     280             : // internal method to create the overviews
     281           1 : void KEARasterBand::CreateOverviews(int nOverviews, const int *panOverviewList)
     282             : {
     283           2 :     CPLMutexHolderD(&m_hMutex);
     284             :     // delete any existing overview bands
     285           1 :     this->deleteOverviewObjects();
     286             : 
     287             :     // allocate space
     288           1 :     m_panOverviewBands =
     289           1 :         (KEAOverview **)CPLMalloc(sizeof(KEAOverview *) * nOverviews);
     290           1 :     m_nOverviews = nOverviews;
     291             : 
     292             :     // loop through and create the overviews
     293             :     int nFactor, nXSize, nYSize;
     294           2 :     for (int nCount = 0; nCount < m_nOverviews; nCount++)
     295             :     {
     296           1 :         nFactor = panOverviewList[nCount];
     297             :         // divide by the factor to get the new size
     298           1 :         nXSize = this->nRasterXSize / nFactor;
     299           1 :         nYSize = this->nRasterYSize / nFactor;
     300             : 
     301             :         // tell image io to create a new overview
     302           1 :         this->m_pImageIO->createOverview(this->nBand, nCount + 1, nXSize,
     303             :                                          nYSize);
     304             : 
     305             :         // create one of our objects to represent it
     306           1 :         m_panOverviewBands[nCount] = new KEAOverview(
     307           1 :             cpl::down_cast<KEADataset *>(poDS), this->nBand, GA_Update,
     308           1 :             this->m_pImageIO, this->m_pRefCount, nCount + 1, nXSize, nYSize);
     309             :     }
     310           1 : }
     311             : 
     312             : // virtual method to read a block
     313         145 : CPLErr KEARasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
     314             : {
     315             :     try
     316             :     {
     317             :         // GDAL deals in blocks - if we are at the end of a row
     318             :         // we need to adjust the amount read so we don't go over the edge
     319         145 :         int nxsize = this->nBlockXSize;
     320         145 :         int nxtotalsize = this->nBlockXSize * (nBlockXOff + 1);
     321         145 :         if (nxtotalsize > this->nRasterXSize)
     322             :         {
     323          11 :             nxsize -= (nxtotalsize - this->nRasterXSize);
     324             :         }
     325         145 :         int nysize = this->nBlockYSize;
     326         145 :         int nytotalsize = this->nBlockYSize * (nBlockYOff + 1);
     327         145 :         if (nytotalsize > this->nRasterYSize)
     328             :         {
     329          11 :             nysize -= (nytotalsize - this->nRasterYSize);
     330             :         }
     331         145 :         this->m_pImageIO->readImageBlock2Band(
     332         145 :             this->nBand, pImage, this->nBlockXSize * nBlockXOff,
     333         145 :             this->nBlockYSize * nBlockYOff, nxsize, nysize, this->nBlockXSize,
     334         145 :             this->nBlockYSize, this->m_eKEADataType);
     335         145 :         return CE_None;
     336             :     }
     337           0 :     catch (const kealib::KEAIOException &e)
     338             :     {
     339           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to read file: %s",
     340           0 :                  e.what());
     341           0 :         return CE_Failure;
     342             :     }
     343             : }
     344             : 
     345             : // virtual method to write a block
     346          13 : CPLErr KEARasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, void *pImage)
     347             : {
     348             :     try
     349             :     {
     350             :         // GDAL deals in blocks - if we are at the end of a row
     351             :         // we need to adjust the amount written so we don't go over the edge
     352          13 :         int nxsize = this->nBlockXSize;
     353          13 :         int nxtotalsize = this->nBlockXSize * (nBlockXOff + 1);
     354          13 :         if (nxtotalsize > this->nRasterXSize)
     355             :         {
     356           0 :             nxsize -= (nxtotalsize - this->nRasterXSize);
     357             :         }
     358          13 :         int nysize = this->nBlockYSize;
     359          13 :         int nytotalsize = this->nBlockYSize * (nBlockYOff + 1);
     360          13 :         if (nytotalsize > this->nRasterYSize)
     361             :         {
     362           0 :             nysize -= (nytotalsize - this->nRasterYSize);
     363             :         }
     364             : 
     365          13 :         this->m_pImageIO->writeImageBlock2Band(
     366          13 :             this->nBand, pImage, this->nBlockXSize * nBlockXOff,
     367          13 :             this->nBlockYSize * nBlockYOff, nxsize, nysize, this->nBlockXSize,
     368          13 :             this->nBlockYSize, this->m_eKEADataType);
     369          13 :         return CE_None;
     370             :     }
     371           0 :     catch (const kealib::KEAIOException &e)
     372             :     {
     373           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to write file: %s",
     374           0 :                  e.what());
     375           0 :         return CE_Failure;
     376             :     }
     377             : }
     378             : 
     379           1 : void KEARasterBand::SetDescription(const char *pszDescription)
     380             : {
     381           2 :     CPLMutexHolderD(&m_hMutex);
     382             :     try
     383             :     {
     384           1 :         this->m_pImageIO->setImageBandDescription(this->nBand, pszDescription);
     385           1 :         GDALRasterBand::SetDescription(pszDescription);
     386             :     }
     387           0 :     catch (const kealib::KEAIOException &)
     388             :     {
     389             :         // ignore?
     390             :     }
     391           1 : }
     392             : 
     393             : // set a metadata item
     394           7 : CPLErr KEARasterBand::SetMetadataItem(const char *pszName, const char *pszValue,
     395             :                                       const char *pszDomain)
     396             : {
     397          14 :     CPLMutexHolderD(&m_hMutex);
     398             :     // only deal with 'default' domain - no geolocation etc
     399           7 :     if ((pszDomain != nullptr) && (*pszDomain != '\0'))
     400           1 :         return CE_Failure;
     401             : 
     402             :     // kealib doesn't currently support removing values
     403           6 :     if (pszValue == nullptr)
     404           0 :         return CE_Failure;
     405             : 
     406             :     try
     407             :     {
     408             :         // if it is LAYER_TYPE handle it separately
     409           6 :         if (EQUAL(pszName, "LAYER_TYPE"))
     410             :         {
     411           6 :             if (EQUAL(pszValue, "athematic"))
     412             :             {
     413           1 :                 this->m_pImageIO->setImageBandLayerType(this->nBand,
     414             :                                                         kealib::kea_continuous);
     415             :             }
     416             :             else
     417             :             {
     418           5 :                 this->m_pImageIO->setImageBandLayerType(this->nBand,
     419             :                                                         kealib::kea_thematic);
     420             :             }
     421             :         }
     422           0 :         else if (EQUAL(pszName, "STATISTICS_HISTOBINVALUES"))
     423             :         {
     424           0 :             if (this->SetHistogramFromString(pszValue) != CE_None)
     425           0 :                 return CE_Failure;
     426             :             else
     427           0 :                 return CE_None;
     428             :         }
     429           0 :         else if (EQUAL(pszName, "STATISTICS_HISTONUMBINS"))
     430             :         {
     431           0 :             GDALRasterAttributeTable *pTable = this->GetDefaultRAT();
     432           0 :             if (pTable != nullptr)
     433           0 :                 pTable->SetRowCount(atoi(pszValue));
     434             :             // leave to update m_papszMetadataList below
     435             :         }
     436             :         else
     437             :         {
     438             :             // otherwise set it as normal
     439           0 :             this->m_pImageIO->setImageBandMetaData(this->nBand, pszName,
     440             :                                                    pszValue);
     441             :         }
     442             :         // CSLSetNameValue will update if already there
     443           6 :         m_papszMetadataList =
     444           6 :             CSLSetNameValue(m_papszMetadataList, pszName, pszValue);
     445           6 :         return CE_None;
     446             :     }
     447           0 :     catch (const kealib::KEAIOException &)
     448             :     {
     449           0 :         return CE_Failure;
     450             :     }
     451             : }
     452             : 
     453             : // get a single metadata item
     454          15 : const char *KEARasterBand::GetMetadataItem(const char *pszName,
     455             :                                            const char *pszDomain)
     456             : {
     457          30 :     CPLMutexHolderD(&m_hMutex);
     458             :     // only deal with 'default' domain - no geolocation etc
     459          15 :     if ((pszDomain != nullptr) && (*pszDomain != '\0'))
     460           8 :         return nullptr;
     461             : 
     462           7 :     if (EQUAL(pszName, "STATISTICS_HISTOBINVALUES"))
     463             :     {
     464           0 :         if (m_pszHistoBinValues != nullptr)
     465           0 :             CPLFree(m_pszHistoBinValues);  // could have changed
     466           0 :         m_pszHistoBinValues = this->GetHistogramAsString();
     467           0 :         return m_pszHistoBinValues;
     468             :     }
     469             : 
     470             :     // get it out of the CSLStringList so we can be sure it is persistent
     471           7 :     return CSLFetchNameValue(m_papszMetadataList, pszName);
     472             : }
     473             : 
     474             : // get all the metadata as a CSLStringList
     475          57 : CSLConstList KEARasterBand::GetMetadata(const char *pszDomain)
     476             : {
     477             :     // only deal with 'default' domain - no geolocation etc
     478          57 :     if ((pszDomain != nullptr) && (*pszDomain != '\0'))
     479           1 :         return nullptr;
     480             :     // Note: ignoring STATISTICS_HISTOBINVALUES as these are likely to be very
     481             :     // long not sure user should get those unless they really ask...
     482             : 
     483             :     // conveniently we already have it in this format
     484          56 :     return m_papszMetadataList;
     485             : }
     486             : 
     487             : // set the metadata as a CSLStringList
     488           5 : CPLErr KEARasterBand::SetMetadata(CSLConstList papszMetadata,
     489             :                                   const char *pszDomain)
     490             : {
     491          10 :     CPLMutexHolderD(&m_hMutex);
     492             :     // only deal with 'default' domain - no geolocation etc
     493           5 :     if ((pszDomain != nullptr) && (*pszDomain != '\0'))
     494           1 :         return CE_Failure;
     495           4 :     int nIndex = 0;
     496             :     try
     497             :     {
     498             :         // iterate through each one
     499           8 :         while (papszMetadata[nIndex] != nullptr)
     500             :         {
     501           4 :             char *pszName = nullptr;
     502             :             const char *pszValue =
     503           4 :                 CPLParseNameValue(papszMetadata[nIndex], &pszName);
     504           4 :             if (pszValue == nullptr)
     505           0 :                 pszValue = "";
     506           4 :             if (pszName != nullptr)
     507             :             {
     508             :                 // it is LAYER_TYPE? if so handle separately
     509           4 :                 if (EQUAL(pszName, "LAYER_TYPE"))
     510             :                 {
     511           2 :                     if (EQUAL(pszValue, "athematic"))
     512             :                     {
     513           1 :                         this->m_pImageIO->setImageBandLayerType(
     514           1 :                             this->nBand, kealib::kea_continuous);
     515             :                     }
     516             :                     else
     517             :                     {
     518           1 :                         this->m_pImageIO->setImageBandLayerType(
     519           1 :                             this->nBand, kealib::kea_thematic);
     520             :                     }
     521             :                 }
     522           2 :                 else if (EQUAL(pszName, "STATISTICS_HISTOBINVALUES"))
     523             :                 {
     524           0 :                     if (this->SetHistogramFromString(pszValue) != CE_None)
     525             :                     {
     526           0 :                         CPLFree(pszName);
     527           0 :                         return CE_Failure;
     528             :                     }
     529             :                 }
     530             :                 else
     531             :                 {
     532             :                     // write it into the image
     533           2 :                     this->m_pImageIO->setImageBandMetaData(this->nBand, pszName,
     534             :                                                            pszValue);
     535             :                 }
     536           4 :                 CPLFree(pszName);
     537             :             }
     538           4 :             nIndex++;
     539             :         }
     540             :     }
     541           0 :     catch (const kealib::KEAIOException &)
     542             :     {
     543           0 :         return CE_Failure;
     544             :     }
     545             :     // destroy our list and duplicate the one passed in
     546             :     // and use that as our list from now on
     547           4 :     CSLDestroy(m_papszMetadataList);
     548           4 :     m_papszMetadataList = CSLDuplicate(papszMetadata);
     549           4 :     return CE_None;
     550             : }
     551             : 
     552             : // get the no data value
     553         314 : double KEARasterBand::GetNoDataValue(int *pbSuccess)
     554             : {
     555             :     try
     556             :     {
     557             :         double dVal;
     558         314 :         this->m_pImageIO->getNoDataValue(this->nBand, &dVal,
     559             :                                          kealib::kea_64float);
     560          65 :         if (pbSuccess != nullptr)
     561          53 :             *pbSuccess = 1;
     562             : 
     563          65 :         return dVal;
     564             :     }
     565         249 :     catch (const kealib::KEAIOException &)
     566             :     {
     567         249 :         if (pbSuccess != nullptr)
     568         249 :             *pbSuccess = 0;
     569         249 :         return -1;
     570             :     }
     571             : }
     572             : 
     573          30 : int64_t KEARasterBand::GetNoDataValueAsInt64(int *pbSuccess)
     574             : {
     575             :     try
     576             :     {
     577             :         int64_t nVal;
     578          30 :         this->m_pImageIO->getNoDataValue(this->nBand, &nVal, kealib::kea_64int);
     579          12 :         if (pbSuccess != nullptr)
     580           9 :             *pbSuccess = 1;
     581             : 
     582          12 :         return nVal;
     583             :     }
     584          18 :     catch (const kealib::KEAIOException &)
     585             :     {
     586          18 :         if (pbSuccess != nullptr)
     587          18 :             *pbSuccess = 0;
     588          18 :         return -1;
     589             :     }
     590             : }
     591             : 
     592          24 : uint64_t KEARasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
     593             : {
     594             :     try
     595             :     {
     596             :         uint64_t nVal;
     597          24 :         this->m_pImageIO->getNoDataValue(this->nBand, &nVal,
     598             :                                          kealib::kea_64uint);
     599           8 :         if (pbSuccess != nullptr)
     600           6 :             *pbSuccess = 1;
     601             : 
     602           8 :         return nVal;
     603             :     }
     604          16 :     catch (const kealib::KEAIOException &)
     605             :     {
     606          16 :         if (pbSuccess != nullptr)
     607          16 :             *pbSuccess = 0;
     608          16 :         return std::numeric_limits<uint64_t>::max();
     609             :     }
     610             : }
     611             : 
     612             : // set the no data value
     613          23 : CPLErr KEARasterBand::SetNoDataValue(double dfNoData)
     614             : {
     615             :     // need to check for out of range values
     616          23 :     bool bSet = true;
     617          23 :     GDALDataType dtype = this->GetRasterDataType();
     618          23 :     switch (dtype)
     619             :     {
     620           6 :         case GDT_UInt8:
     621           6 :             bSet = (dfNoData >= 0) && (dfNoData <= UCHAR_MAX);
     622           6 :             break;
     623           4 :         case GDT_UInt16:
     624           4 :             bSet = (dfNoData >= 0) && (dfNoData <= USHRT_MAX);
     625           4 :             break;
     626           4 :         case GDT_Int16:
     627           4 :             bSet = (dfNoData >= SHRT_MIN) && (dfNoData <= SHRT_MAX);
     628           4 :             break;
     629           4 :         case GDT_UInt32:
     630           4 :             bSet = (dfNoData >= 0) && (dfNoData <= UINT_MAX);
     631           4 :             break;
     632           4 :         case GDT_Int32:
     633           4 :             bSet = (dfNoData >= INT_MIN) && (dfNoData <= INT_MAX);
     634           4 :             break;
     635           1 :         default:
     636             :             // for other types we can't really tell if outside the range
     637           1 :             break;
     638             :     }
     639             : 
     640             :     try
     641             :     {
     642          23 :         if (bSet)
     643             :         {
     644          13 :             this->m_pImageIO->setNoDataValue(this->nBand, &dfNoData,
     645             :                                              kealib::kea_64float);
     646             :         }
     647             :         else
     648             :         {
     649          10 :             this->m_pImageIO->undefineNoDataValue(this->nBand);
     650             :         }
     651          13 :         return CE_None;
     652             :     }
     653          10 :     catch (const kealib::KEAIOException &)
     654             :     {
     655          10 :         return CE_Failure;
     656             :     }
     657             : }
     658             : 
     659           3 : CPLErr KEARasterBand::SetNoDataValueAsInt64(int64_t nNoData)
     660             : {
     661             :     try
     662             :     {
     663           3 :         this->m_pImageIO->setNoDataValue(this->nBand, &nNoData,
     664             :                                          kealib::kea_64int);
     665             :     }
     666           0 :     catch (const kealib::KEAIOException &)
     667             :     {
     668           0 :         return CE_Failure;
     669             :     }
     670           3 :     return CE_None;
     671             : }
     672             : 
     673           2 : CPLErr KEARasterBand::SetNoDataValueAsUInt64(uint64_t nNoData)
     674             : {
     675             :     try
     676             :     {
     677           2 :         this->m_pImageIO->setNoDataValue(this->nBand, &nNoData,
     678             :                                          kealib::kea_64uint);
     679             :     }
     680           0 :     catch (const kealib::KEAIOException &)
     681             :     {
     682           0 :         return CE_Failure;
     683             :     }
     684           2 :     return CE_None;
     685             : }
     686             : 
     687          27 : CPLErr KEARasterBand::DeleteNoDataValue()
     688             : {
     689             :     try
     690             :     {
     691          27 :         m_pImageIO->undefineNoDataValue(this->nBand);
     692          17 :         return CE_None;
     693             :     }
     694          10 :     catch (const kealib::KEAIOException &)
     695             :     {
     696          10 :         return CE_Failure;
     697             :     }
     698             : }
     699             : 
     700           0 : CPLErr KEARasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
     701             :                                           int *pnBuckets,
     702             :                                           GUIntBig **ppanHistogram, int bForce,
     703             :                                           GDALProgressFunc fn,
     704             :                                           void *pProgressData)
     705             : {
     706           0 :     if (bForce)
     707             :     {
     708           0 :         return GDALRasterBand::GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
     709             :                                                    ppanHistogram, bForce, fn,
     710           0 :                                                    pProgressData);
     711             :     }
     712             :     else
     713             :     {
     714             :         // returned cached if avail
     715             :         // I've used the RAT interface here as it deals with data type
     716             :         // conversions. Would be nice to have GUIntBig support in RAT though...
     717           0 :         GDALRasterAttributeTable *pTable = this->GetDefaultRAT();
     718           0 :         if (pTable == nullptr)
     719           0 :             return CE_Failure;
     720           0 :         int nRows = pTable->GetRowCount();
     721             : 
     722             :         // find histogram column if it exists
     723           0 :         int nCol = pTable->GetColOfUsage(GFU_PixelCount);
     724           0 :         if (nCol == -1)
     725           0 :             return CE_Warning;
     726             : 
     727             :         double dfRow0Min, dfBinSize;
     728           0 :         if (!pTable->GetLinearBinning(&dfRow0Min, &dfBinSize))
     729           0 :             return CE_Warning;
     730             : 
     731           0 :         *ppanHistogram = (GUIntBig *)VSIMalloc2(nRows, sizeof(GUIntBig));
     732           0 :         if (*ppanHistogram == nullptr)
     733             :         {
     734           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     735             :                      "Memory Allocation failed in "
     736             :                      "KEARasterBand::GetDefaultHistogram");
     737           0 :             return CE_Failure;
     738             :         }
     739             : 
     740           0 :         double *pDoubleHisto = (double *)VSIMalloc2(nRows, sizeof(double));
     741           0 :         if (pDoubleHisto == nullptr)
     742             :         {
     743           0 :             CPLFree(*ppanHistogram);
     744           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     745             :                      "Memory Allocation failed in "
     746             :                      "KEARasterBand::GetDefaultHistogram");
     747           0 :             return CE_Failure;
     748             :         }
     749             : 
     750           0 :         if (pTable->ValuesIO(GF_Read, nCol, 0, nRows, pDoubleHisto) != CE_None)
     751           0 :             return CE_Failure;
     752             : 
     753             :         // convert to GUIntBig
     754           0 :         for (int n = 0; n < nRows; n++)
     755           0 :             (*ppanHistogram)[n] = static_cast<GUIntBig>(pDoubleHisto[n]);
     756             : 
     757           0 :         CPLFree(pDoubleHisto);
     758             : 
     759           0 :         *pnBuckets = nRows;
     760           0 :         *pdfMin = dfRow0Min;
     761           0 :         *pdfMax = dfRow0Min + ((nRows + 1) * dfBinSize);
     762           0 :         return CE_None;
     763             :     }
     764             : }
     765             : 
     766           0 : CPLErr KEARasterBand::SetDefaultHistogram(double /*dfMin*/, double /*dfMax*/,
     767             :                                           int nBuckets, GUIntBig *panHistogram)
     768             : {
     769             : 
     770           0 :     GDALRasterAttributeTable *pTable = this->GetDefaultRAT();
     771           0 :     if (pTable == nullptr)
     772           0 :         return CE_Failure;
     773           0 :     int nRows = pTable->GetRowCount();
     774             : 
     775             :     // find histogram column if it exists
     776           0 :     int nCol = pTable->GetColOfUsage(GFU_PixelCount);
     777           0 :     if (nCol == -1)
     778             :     {
     779           0 :         if (pTable->CreateColumn("Histogram", GFT_Real, GFU_PixelCount) !=
     780             :             CE_None)
     781           0 :             return CE_Failure;
     782             : 
     783           0 :         nCol = pTable->GetColumnCount() - 1;
     784             :     }
     785             : 
     786           0 :     if (nBuckets > nRows)
     787           0 :         pTable->SetRowCount(nBuckets);
     788             : 
     789             :     // convert to double (RATs don't take GUIntBig yet)
     790           0 :     double *pDoubleHist = (double *)VSIMalloc2(nBuckets, sizeof(double));
     791             : 
     792           0 :     if (pDoubleHist == nullptr)
     793             :     {
     794           0 :         CPLError(
     795             :             CE_Failure, CPLE_OutOfMemory,
     796             :             "Memory Allocation failed in KEARasterBand::SetDefaultHistogram");
     797           0 :         return CE_Failure;
     798             :     }
     799             : 
     800           0 :     for (int n = 0; n < nBuckets; n++)
     801           0 :         pDoubleHist[n] = static_cast<double>(panHistogram[n]);
     802             : 
     803           0 :     if (pTable->ValuesIO(GF_Write, nCol, 0, nBuckets, pDoubleHist) != CE_None)
     804             :     {
     805           0 :         CPLFree(pDoubleHist);
     806           0 :         return CE_Failure;
     807             :     }
     808             : 
     809           0 :     CPLFree(pDoubleHist);
     810             : 
     811           0 :     return CE_None;
     812             : }
     813             : 
     814         473 : GDALRasterAttributeTable *KEARasterBand::GetDefaultRAT()
     815             : {
     816         473 :     CPLMutexHolderD(&m_hMutex);
     817         473 :     if (this->m_pAttributeTable == nullptr)
     818             :     {
     819             :         try
     820             :         {
     821             :             // we assume this is never NULL - creates a new one if none exists
     822             :             // (or raises exception)
     823             :             kealib::KEAAttributeTable *pKEATable =
     824         810 :                 this->m_pImageIO->getAttributeTable(kealib::kea_att_file,
     825         405 :                                                     this->nBand);
     826         405 :             this->m_pAttributeTable =
     827         405 :                 new KEARasterAttributeTable(pKEATable, this);
     828             :         }
     829           0 :         catch (const kealib::KEAException &e)
     830             :         {
     831           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     832           0 :                      "Failed to read attributes: %s", e.what());
     833             :         }
     834             :     }
     835         946 :     return this->m_pAttributeTable;
     836             : }
     837             : 
     838           3 : CPLErr KEARasterBand::SetDefaultRAT(const GDALRasterAttributeTable *poRAT)
     839             : {
     840           3 :     if (poRAT == nullptr)
     841           1 :         return CE_Failure;
     842             : 
     843             :     try
     844             :     {
     845             :         KEARasterAttributeTable *pKEATable =
     846           2 :             cpl::down_cast<KEARasterAttributeTable *>(GetDefaultRAT());
     847           2 :         if (pKEATable == nullptr)
     848           0 :             return CE_Failure;
     849             : 
     850           2 :         int numRows = poRAT->GetRowCount();
     851           2 :         pKEATable->SetRowCount(numRows);
     852             : 
     853          13 :         for (int nGDALColumnIndex = 0;
     854          13 :              nGDALColumnIndex < poRAT->GetColumnCount(); nGDALColumnIndex++)
     855             :         {
     856          11 :             const char *pszColumnName = poRAT->GetNameOfCol(nGDALColumnIndex);
     857          11 :             GDALRATFieldType eFieldType = poRAT->GetTypeOfCol(nGDALColumnIndex);
     858             : 
     859             :             // do we have it?
     860          11 :             bool bExists = false;
     861             :             int nKEAColumnIndex;
     862          56 :             for (nKEAColumnIndex = 0;
     863          56 :                  nKEAColumnIndex < pKEATable->GetColumnCount();
     864             :                  nKEAColumnIndex++)
     865             :             {
     866          56 :                 if (EQUAL(pszColumnName,
     867             :                           pKEATable->GetNameOfCol(nKEAColumnIndex)))
     868             :                 {
     869          11 :                     bExists = true;
     870          11 :                     break;
     871             :                 }
     872             :             }
     873             : 
     874          11 :             if (!bExists)
     875             :             {
     876           0 :                 if (pKEATable->CreateColumn(
     877             :                         pszColumnName, eFieldType,
     878           0 :                         poRAT->GetUsageOfCol(nGDALColumnIndex)) != CE_None)
     879             :                 {
     880           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     881             :                              "Failed to create column");
     882           0 :                     return CE_Failure;
     883             :                 }
     884           0 :                 nKEAColumnIndex = pKEATable->GetColumnCount() - 1;
     885             :             }
     886             : 
     887          11 :             if (numRows == 0)
     888           1 :                 continue;
     889             : 
     890             :             // ok now copy data
     891          10 :             switch (eFieldType)
     892             :             {
     893           4 :                 case GFT_Integer:
     894             :                 {
     895             :                     int *panIntData =
     896           4 :                         (int *)VSI_MALLOC2_VERBOSE(numRows, sizeof(int));
     897           4 :                     if (panIntData == nullptr)
     898             :                     {
     899           0 :                         return CE_Failure;
     900             :                     }
     901             : 
     902           4 :                     if (((GDALRasterAttributeTable *)poRAT)
     903           8 :                             ->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows,
     904           4 :                                        panIntData) == CE_None)
     905             :                     {
     906           4 :                         pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0,
     907             :                                             numRows, panIntData);
     908             :                     }
     909           4 :                     CPLFree(panIntData);
     910           4 :                     break;
     911             :                 }
     912             : 
     913           1 :                 case GFT_Boolean:
     914             :                 {
     915             :                     bool *pabData =
     916           1 :                         (bool *)VSI_MALLOC2_VERBOSE(numRows, sizeof(bool));
     917           1 :                     if (pabData == nullptr)
     918             :                     {
     919           0 :                         return CE_Failure;
     920             :                     }
     921             : 
     922           1 :                     if (((GDALRasterAttributeTable *)poRAT)
     923           2 :                             ->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows,
     924           1 :                                        pabData) == CE_None)
     925             :                     {
     926           1 :                         pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0,
     927             :                                             numRows, pabData);
     928             :                     }
     929           1 :                     CPLFree(pabData);
     930           1 :                     break;
     931             :                 }
     932             : 
     933           2 :                 case GFT_Real:
     934             :                 {
     935             :                     double *padfFloatData =
     936           2 :                         (double *)VSI_MALLOC2_VERBOSE(numRows, sizeof(double));
     937           2 :                     if (padfFloatData == nullptr)
     938             :                     {
     939           0 :                         return CE_Failure;
     940             :                     }
     941             : 
     942           2 :                     if (((GDALRasterAttributeTable *)poRAT)
     943           4 :                             ->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows,
     944           2 :                                        padfFloatData) == CE_None)
     945             :                     {
     946           2 :                         pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0,
     947             :                                             numRows, padfFloatData);
     948             :                     }
     949           2 :                     CPLFree(padfFloatData);
     950           2 :                     break;
     951             :                 }
     952             : 
     953           3 :                 case GFT_String:
     954             :                 case GFT_DateTime:
     955             :                 case GFT_WKBGeometry:
     956             :                 {
     957             :                     char **papszStringData =
     958           3 :                         (char **)VSI_MALLOC2_VERBOSE(numRows, sizeof(char *));
     959           3 :                     if (papszStringData == nullptr)
     960             :                     {
     961           0 :                         return CE_Failure;
     962             :                     }
     963             : 
     964           3 :                     if (((GDALRasterAttributeTable *)poRAT)
     965           6 :                             ->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows,
     966           3 :                                        papszStringData) == CE_None)
     967             :                     {
     968           3 :                         pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0,
     969             :                                             numRows, papszStringData);
     970           6 :                         for (int n = 0; n < numRows; n++)
     971           3 :                             CPLFree(papszStringData[n]);
     972             :                     }
     973           3 :                     CPLFree(papszStringData);
     974           3 :                     break;
     975             :                 }
     976             :             }
     977             :         }
     978             :     }
     979           0 :     catch (const kealib::KEAException &e)
     980             :     {
     981           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to write attributes: %s",
     982           0 :                  e.what());
     983           0 :         return CE_Failure;
     984             :     }
     985           2 :     return CE_None;
     986             : }
     987             : 
     988           4 : GDALColorTable *KEARasterBand::GetColorTable()
     989             : {
     990           4 :     CPLMutexHolderD(&m_hMutex);
     991           4 :     if (this->m_pColorTable == nullptr)
     992             :     {
     993             :         try
     994             :         {
     995           4 :             GDALRasterAttributeTable *pKEATable = this->GetDefaultRAT();
     996           4 :             int nRedIdx = -1;
     997           4 :             int nGreenIdx = -1;
     998           4 :             int nBlueIdx = -1;
     999           4 :             int nAlphaIdx = -1;
    1000             : 
    1001          12 :             for (int nColIdx = 0; nColIdx < pKEATable->GetColumnCount();
    1002             :                  nColIdx++)
    1003             :             {
    1004           8 :                 if (pKEATable->GetTypeOfCol(nColIdx) == GFT_Integer)
    1005             :                 {
    1006             :                     GDALRATFieldUsage eFieldUsage =
    1007           8 :                         pKEATable->GetUsageOfCol(nColIdx);
    1008           8 :                     if (eFieldUsage == GFU_Red)
    1009           2 :                         nRedIdx = nColIdx;
    1010           6 :                     else if (eFieldUsage == GFU_Green)
    1011           2 :                         nGreenIdx = nColIdx;
    1012           4 :                     else if (eFieldUsage == GFU_Blue)
    1013           2 :                         nBlueIdx = nColIdx;
    1014           2 :                     else if (eFieldUsage == GFU_Alpha)
    1015           2 :                         nAlphaIdx = nColIdx;
    1016             :                 }
    1017             :             }
    1018             : 
    1019           4 :             if ((nRedIdx != -1) && (nGreenIdx != -1) && (nBlueIdx != -1) &&
    1020             :                 (nAlphaIdx != -1))
    1021             :             {
    1022             :                 // we need to create one - only do RGB palettes
    1023           2 :                 this->m_pColorTable = new GDALColorTable(GPI_RGB);
    1024             : 
    1025             :                 // OK go through each row and fill in the fields
    1026           8 :                 for (int nRowIndex = 0; nRowIndex < pKEATable->GetRowCount();
    1027             :                      nRowIndex++)
    1028             :                 {
    1029             :                     // maybe could be more efficient using ValuesIO
    1030             :                     GDALColorEntry colorEntry;
    1031           6 :                     colorEntry.c1 = static_cast<short>(
    1032           6 :                         pKEATable->GetValueAsInt(nRowIndex, nRedIdx));
    1033           6 :                     colorEntry.c2 = static_cast<short>(
    1034           6 :                         pKEATable->GetValueAsInt(nRowIndex, nGreenIdx));
    1035           6 :                     colorEntry.c3 = static_cast<short>(
    1036           6 :                         pKEATable->GetValueAsInt(nRowIndex, nBlueIdx));
    1037           6 :                     colorEntry.c4 = static_cast<short>(
    1038           6 :                         pKEATable->GetValueAsInt(nRowIndex, nAlphaIdx));
    1039           6 :                     this->m_pColorTable->SetColorEntry(nRowIndex, &colorEntry);
    1040             :                 }
    1041             :             }
    1042             :         }
    1043           0 :         catch (const kealib::KEAException &e)
    1044             :         {
    1045           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1046           0 :                      "Failed to read color table: %s", e.what());
    1047           0 :             delete this->m_pColorTable;
    1048           0 :             this->m_pColorTable = nullptr;
    1049             :         }
    1050             :     }
    1051           8 :     return this->m_pColorTable;
    1052             : }
    1053             : 
    1054           5 : CPLErr KEARasterBand::SetColorTable(GDALColorTable *poCT)
    1055             : {
    1056           5 :     if (poCT == nullptr)
    1057           2 :         return CE_Failure;
    1058             : 
    1059           6 :     CPLMutexHolderD(&m_hMutex);
    1060             :     try
    1061             :     {
    1062           3 :         GDALRasterAttributeTable *pKEATable = this->GetDefaultRAT();
    1063           3 :         if (pKEATable == nullptr)
    1064           0 :             return CE_Failure;
    1065           3 :         int nRedIdx = -1;
    1066           3 :         int nGreenIdx = -1;
    1067           3 :         int nBlueIdx = -1;
    1068           3 :         int nAlphaIdx = -1;
    1069             : 
    1070           3 :         if (poCT->GetColorEntryCount() > pKEATable->GetRowCount())
    1071             :         {
    1072           2 :             pKEATable->SetRowCount(poCT->GetColorEntryCount());
    1073             :         }
    1074             : 
    1075           7 :         for (int nColIdx = 0; nColIdx < pKEATable->GetColumnCount(); nColIdx++)
    1076             :         {
    1077           4 :             if (pKEATable->GetTypeOfCol(nColIdx) == GFT_Integer)
    1078             :             {
    1079             :                 GDALRATFieldUsage eFieldUsage =
    1080           4 :                     pKEATable->GetUsageOfCol(nColIdx);
    1081           4 :                 if (eFieldUsage == GFU_Red)
    1082           1 :                     nRedIdx = nColIdx;
    1083           3 :                 else if (eFieldUsage == GFU_Green)
    1084           1 :                     nGreenIdx = nColIdx;
    1085           2 :                 else if (eFieldUsage == GFU_Blue)
    1086           1 :                     nBlueIdx = nColIdx;
    1087           1 :                 else if (eFieldUsage == GFU_Alpha)
    1088           1 :                     nAlphaIdx = nColIdx;
    1089             :             }
    1090             :         }
    1091             : 
    1092             :         // create if needed
    1093           3 :         if (nRedIdx == -1)
    1094             :         {
    1095           2 :             if (pKEATable->CreateColumn("Red", GFT_Integer, GFU_Red) != CE_None)
    1096             :             {
    1097           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1098             :                          "Failed to create column");
    1099           0 :                 return CE_Failure;
    1100             :             }
    1101           2 :             nRedIdx = pKEATable->GetColumnCount() - 1;
    1102             :         }
    1103           3 :         if (nGreenIdx == -1)
    1104             :         {
    1105           2 :             if (pKEATable->CreateColumn("Green", GFT_Integer, GFU_Green) !=
    1106             :                 CE_None)
    1107             :             {
    1108           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1109             :                          "Failed to create column");
    1110           0 :                 return CE_Failure;
    1111             :             }
    1112           2 :             nGreenIdx = pKEATable->GetColumnCount() - 1;
    1113             :         }
    1114           3 :         if (nBlueIdx == -1)
    1115             :         {
    1116           2 :             if (pKEATable->CreateColumn("Blue", GFT_Integer, GFU_Blue) !=
    1117             :                 CE_None)
    1118             :             {
    1119           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1120             :                          "Failed to create column");
    1121           0 :                 return CE_Failure;
    1122             :             }
    1123           2 :             nBlueIdx = pKEATable->GetColumnCount() - 1;
    1124             :         }
    1125           3 :         if (nAlphaIdx == -1)
    1126             :         {
    1127           2 :             if (pKEATable->CreateColumn("Alpha", GFT_Integer, GFU_Alpha) !=
    1128             :                 CE_None)
    1129             :             {
    1130           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1131             :                          "Failed to create column");
    1132           0 :                 return CE_Failure;
    1133             :             }
    1134           2 :             nAlphaIdx = pKEATable->GetColumnCount() - 1;
    1135             :         }
    1136             : 
    1137             :         // OK go through each row and fill in the fields
    1138          12 :         for (int nRowIndex = 0; nRowIndex < poCT->GetColorEntryCount();
    1139             :              nRowIndex++)
    1140             :         {
    1141             :             // maybe could be more efficient using ValuesIO
    1142             :             GDALColorEntry colorEntry;
    1143           9 :             poCT->GetColorEntryAsRGB(nRowIndex, &colorEntry);
    1144           9 :             pKEATable->SetValue(nRowIndex, nRedIdx, colorEntry.c1);
    1145           9 :             pKEATable->SetValue(nRowIndex, nGreenIdx, colorEntry.c2);
    1146           9 :             pKEATable->SetValue(nRowIndex, nBlueIdx, colorEntry.c3);
    1147           9 :             pKEATable->SetValue(nRowIndex, nAlphaIdx, colorEntry.c4);
    1148             :         }
    1149             : 
    1150             :         // out of date
    1151           3 :         delete this->m_pColorTable;
    1152           3 :         this->m_pColorTable = nullptr;
    1153             :     }
    1154           0 :     catch (const kealib::KEAException &e)
    1155             :     {
    1156           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to write color table: %s",
    1157           0 :                  e.what());
    1158           0 :         return CE_Failure;
    1159             :     }
    1160           3 :     return CE_None;
    1161             : }
    1162             : 
    1163          72 : GDALColorInterp KEARasterBand::GetColorInterpretation()
    1164             : {
    1165             :     kealib::KEABandClrInterp ekeainterp;
    1166             :     try
    1167             :     {
    1168          72 :         ekeainterp = this->m_pImageIO->getImageBandClrInterp(this->nBand);
    1169             :     }
    1170           0 :     catch (const kealib::KEAException &)
    1171             :     {
    1172           0 :         return GCI_GrayIndex;
    1173             :     }
    1174             : 
    1175             :     GDALColorInterp egdalinterp;
    1176          72 :     switch (ekeainterp)
    1177             :     {
    1178          42 :         case kealib::kea_generic:
    1179             :         case kealib::kea_greyindex:
    1180          42 :             egdalinterp = GCI_GrayIndex;
    1181          42 :             break;
    1182           2 :         case kealib::kea_paletteindex:
    1183           2 :             egdalinterp = GCI_PaletteIndex;
    1184           2 :             break;
    1185           2 :         case kealib::kea_redband:
    1186           2 :             egdalinterp = GCI_RedBand;
    1187           2 :             break;
    1188           2 :         case kealib::kea_greenband:
    1189           2 :             egdalinterp = GCI_GreenBand;
    1190           2 :             break;
    1191           2 :         case kealib::kea_blueband:
    1192           2 :             egdalinterp = GCI_BlueBand;
    1193           2 :             break;
    1194           2 :         case kealib::kea_alphaband:
    1195           2 :             egdalinterp = GCI_AlphaBand;
    1196           2 :             break;
    1197           2 :         case kealib::kea_hueband:
    1198           2 :             egdalinterp = GCI_HueBand;
    1199           2 :             break;
    1200           2 :         case kealib::kea_saturationband:
    1201           2 :             egdalinterp = GCI_SaturationBand;
    1202           2 :             break;
    1203           2 :         case kealib::kea_lightnessband:
    1204           2 :             egdalinterp = GCI_LightnessBand;
    1205           2 :             break;
    1206           2 :         case kealib::kea_cyanband:
    1207           2 :             egdalinterp = GCI_CyanBand;
    1208           2 :             break;
    1209           2 :         case kealib::kea_magentaband:
    1210           2 :             egdalinterp = GCI_MagentaBand;
    1211           2 :             break;
    1212           2 :         case kealib::kea_yellowband:
    1213           2 :             egdalinterp = GCI_YellowBand;
    1214           2 :             break;
    1215           2 :         case kealib::kea_blackband:
    1216           2 :             egdalinterp = GCI_BlackBand;
    1217           2 :             break;
    1218           2 :         case kealib::kea_ycbcr_yband:
    1219           2 :             egdalinterp = GCI_YCbCr_YBand;
    1220           2 :             break;
    1221           2 :         case kealib::kea_ycbcr_cbband:
    1222           2 :             egdalinterp = GCI_YCbCr_CbBand;
    1223           2 :             break;
    1224           2 :         case kealib::kea_ycbcr_crband:
    1225           2 :             egdalinterp = GCI_YCbCr_CrBand;
    1226           2 :             break;
    1227           0 :         default:
    1228           0 :             egdalinterp = GCI_GrayIndex;
    1229           0 :             break;
    1230             :     }
    1231             : 
    1232          72 :     return egdalinterp;
    1233             : }
    1234             : 
    1235         105 : CPLErr KEARasterBand::SetColorInterpretation(GDALColorInterp egdalinterp)
    1236             : {
    1237             :     kealib::KEABandClrInterp ekeainterp;
    1238         105 :     switch (egdalinterp)
    1239             :     {
    1240          54 :         case GCI_GrayIndex:
    1241          54 :             ekeainterp = kealib::kea_greyindex;
    1242          54 :             break;
    1243           2 :         case GCI_PaletteIndex:
    1244           2 :             ekeainterp = kealib::kea_paletteindex;
    1245           2 :             break;
    1246           2 :         case GCI_RedBand:
    1247           2 :             ekeainterp = kealib::kea_redband;
    1248           2 :             break;
    1249           2 :         case GCI_GreenBand:
    1250           2 :             ekeainterp = kealib::kea_greenband;
    1251           2 :             break;
    1252           2 :         case GCI_BlueBand:
    1253           2 :             ekeainterp = kealib::kea_blueband;
    1254           2 :             break;
    1255           2 :         case GCI_AlphaBand:
    1256           2 :             ekeainterp = kealib::kea_alphaband;
    1257           2 :             break;
    1258           2 :         case GCI_HueBand:
    1259           2 :             ekeainterp = kealib::kea_hueband;
    1260           2 :             break;
    1261           2 :         case GCI_SaturationBand:
    1262           2 :             ekeainterp = kealib::kea_saturationband;
    1263           2 :             break;
    1264           2 :         case GCI_LightnessBand:
    1265           2 :             ekeainterp = kealib::kea_lightnessband;
    1266           2 :             break;
    1267           2 :         case GCI_CyanBand:
    1268           2 :             ekeainterp = kealib::kea_cyanband;
    1269           2 :             break;
    1270           2 :         case GCI_MagentaBand:
    1271           2 :             ekeainterp = kealib::kea_magentaband;
    1272           2 :             break;
    1273           2 :         case GCI_YellowBand:
    1274           2 :             ekeainterp = kealib::kea_yellowband;
    1275           2 :             break;
    1276           2 :         case GCI_BlackBand:
    1277           2 :             ekeainterp = kealib::kea_blackband;
    1278           2 :             break;
    1279           2 :         case GCI_YCbCr_YBand:
    1280           2 :             ekeainterp = kealib::kea_ycbcr_yband;
    1281           2 :             break;
    1282           2 :         case GCI_YCbCr_CbBand:
    1283           2 :             ekeainterp = kealib::kea_ycbcr_cbband;
    1284           2 :             break;
    1285           2 :         case GCI_YCbCr_CrBand:
    1286           2 :             ekeainterp = kealib::kea_ycbcr_crband;
    1287           2 :             break;
    1288          21 :         default:
    1289          21 :             ekeainterp = kealib::kea_greyindex;
    1290          21 :             break;
    1291             :     }
    1292             : 
    1293             :     try
    1294             :     {
    1295         105 :         this->m_pImageIO->setImageBandClrInterp(this->nBand, ekeainterp);
    1296             :     }
    1297           0 :     catch (const kealib::KEAException &)
    1298             :     {
    1299             :         // Do nothing? The docs say CE_Failure only if unsupported by format.
    1300             :     }
    1301         105 :     return CE_None;
    1302             : }
    1303             : 
    1304             : // clean up our overview objects
    1305             : // assumes mutex being held by caller
    1306         806 : void KEARasterBand::deleteOverviewObjects()
    1307             : {
    1308             :     // deletes the objects - not the overviews themselves
    1309             :     int nCount;
    1310         809 :     for (nCount = 0; nCount < m_nOverviews; nCount++)
    1311             :     {
    1312           3 :         delete m_panOverviewBands[nCount];
    1313             :     }
    1314         806 :     CPLFree(m_panOverviewBands);
    1315         806 :     m_panOverviewBands = nullptr;
    1316         806 :     m_nOverviews = 0;
    1317         806 : }
    1318             : 
    1319             : // read in any overviews in the file into our array of objects
    1320         400 : void KEARasterBand::readExistingOverviews()
    1321             : {
    1322         800 :     CPLMutexHolderD(&m_hMutex);
    1323             :     // delete any existing overview bands
    1324         400 :     this->deleteOverviewObjects();
    1325             : 
    1326         400 :     m_nOverviews = this->m_pImageIO->getNumOfOverviews(this->nBand);
    1327         400 :     m_panOverviewBands =
    1328         400 :         (KEAOverview **)CPLMalloc(sizeof(KEAOverview *) * m_nOverviews);
    1329             : 
    1330             :     uint64_t nXSize, nYSize;
    1331         402 :     for (int nCount = 0; nCount < m_nOverviews; nCount++)
    1332             :     {
    1333           2 :         this->m_pImageIO->getOverviewSize(this->nBand, nCount + 1, &nXSize,
    1334             :                                           &nYSize);
    1335           2 :         m_panOverviewBands[nCount] = new KEAOverview(
    1336           2 :             cpl::down_cast<KEADataset *>(poDS), this->nBand, GA_ReadOnly,
    1337           2 :             this->m_pImageIO, this->m_pRefCount, nCount + 1, nXSize, nYSize);
    1338             :     }
    1339         400 : }
    1340             : 
    1341             : // number of overviews
    1342          56 : int KEARasterBand::GetOverviewCount()
    1343             : {
    1344          56 :     return m_nOverviews;
    1345             : }
    1346             : 
    1347             : // get a given overview
    1348           6 : GDALRasterBand *KEARasterBand::GetOverview(int nOverview)
    1349             : {
    1350           6 :     if (nOverview < 0 || nOverview >= m_nOverviews)
    1351             :     {
    1352           2 :         return nullptr;
    1353             :     }
    1354             :     else
    1355             :     {
    1356           4 :         return m_panOverviewBands[nOverview];
    1357             :     }
    1358             : }
    1359             : 
    1360           2 : CPLErr KEARasterBand::CreateMaskBand(int)
    1361             : {
    1362           4 :     CPLMutexHolderD(&m_hMutex);
    1363           2 :     if (m_bMaskBandOwned)
    1364           0 :         delete m_pMaskBand;
    1365           2 :     m_pMaskBand = nullptr;
    1366             :     try
    1367             :     {
    1368           2 :         this->m_pImageIO->createMask(this->nBand);
    1369             :     }
    1370           0 :     catch (const kealib::KEAException &e)
    1371             :     {
    1372           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to create mask band: %s",
    1373           0 :                  e.what());
    1374           0 :         return CE_Failure;
    1375             :     }
    1376           2 :     return CE_None;
    1377             : }
    1378             : 
    1379         105 : GDALRasterBand *KEARasterBand::GetMaskBand()
    1380             : {
    1381         105 :     CPLMutexHolderD(&m_hMutex);
    1382         105 :     if (m_pMaskBand == nullptr)
    1383             :     {
    1384             :         try
    1385             :         {
    1386         100 :             if (this->m_pImageIO->maskCreated(this->nBand))
    1387             :             {
    1388           3 :                 m_pMaskBand =
    1389           3 :                     new KEAMaskBand(this, this->m_pImageIO, this->m_pRefCount);
    1390           3 :                 m_bMaskBandOwned = true;
    1391             :             }
    1392             :             else
    1393             :             {
    1394             :                 // use the base class implementation - GDAL will delete
    1395             :                 // fprintf( stderr, "returning base GetMaskBand()\n" );
    1396          97 :                 m_pMaskBand = GDALRasterBand::GetMaskBand();
    1397             :             }
    1398             :         }
    1399           0 :         catch (const kealib::KEAException &)
    1400             :         {
    1401             :             // do nothing?
    1402             :         }
    1403             :     }
    1404         210 :     return m_pMaskBand;
    1405             : }
    1406             : 
    1407         132 : int KEARasterBand::GetMaskFlags()
    1408             : {
    1409             :     try
    1410             :     {
    1411         132 :         if (!this->m_pImageIO->maskCreated(this->nBand))
    1412             :         {
    1413             :             // need to return the base class one since we are using
    1414             :             // the base class implementation of GetMaskBand()
    1415             :             // fprintf( stderr, "returning base GetMaskFlags()\n" );
    1416         129 :             return GDALRasterBand::GetMaskFlags();
    1417             :         }
    1418             :     }
    1419           0 :     catch (const kealib::KEAException &)
    1420             :     {
    1421             :         // do nothing?
    1422             :     }
    1423             : 
    1424             :     // none of the other flags seem to make sense...
    1425           3 :     return 0;
    1426             : }
    1427             : 
    1428           1 : kealib::KEALayerType KEARasterBand::getLayerType() const
    1429             : {
    1430           1 :     return m_pImageIO->getImageBandLayerType(nBand);
    1431             : }
    1432             : 
    1433           0 : void KEARasterBand::setLayerType(kealib::KEALayerType eLayerType)
    1434             : {
    1435           0 :     m_pImageIO->setImageBandLayerType(nBand, eLayerType);
    1436           0 : }

Generated by: LCOV version 1.14