LCOV - code coverage report
Current view: top level - frmts/kea - keaband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 517 716 72.2 %
Date: 2024-11-21 22:18:42 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         352 : KEARasterBand::KEARasterBand(KEADataset *pDataset, int nSrcBand,
      26             :                              GDALAccess eAccessIn, kealib::KEAImageIO *pImageIO,
      27         352 :                              LockedRefCount *pRefCount)
      28         704 :     : m_eKEADataType(pImageIO->getImageBandDataType(
      29         352 :           nSrcBand))  // get the data type as KEA enum
      30             : {
      31         352 :     this->m_hMutex = CPLCreateMutex();
      32         352 :     CPLReleaseMutex(this->m_hMutex);
      33             : 
      34         352 :     this->poDS = pDataset;   // our pointer onto the dataset
      35         352 :     this->nBand = nSrcBand;  // this is the band we are
      36         352 :     this->eDataType = KEA_to_GDAL_Type(m_eKEADataType);  // convert to GDAL enum
      37         352 :     this->nBlockXSize =
      38         352 :         pImageIO->getImageBlockSize(nSrcBand);  // get the native blocksize
      39         352 :     this->nBlockYSize = pImageIO->getImageBlockSize(nSrcBand);
      40         352 :     this->nRasterXSize =
      41         352 :         this->poDS
      42         352 :             ->GetRasterXSize();  // ask the dataset for the total image size
      43         352 :     this->nRasterYSize = this->poDS->GetRasterYSize();
      44         352 :     this->eAccess = eAccessIn;
      45             : 
      46         352 :     if (pImageIO->attributeTablePresent(nSrcBand))
      47             :     {
      48          10 :         this->m_nAttributeChunkSize =
      49          10 :             pImageIO->getAttributeTableChunkSize(nSrcBand);
      50             :     }
      51             :     else
      52             :     {
      53         342 :         this->m_nAttributeChunkSize = -1;  // don't report
      54             :     }
      55             : 
      56             :     // grab the imageio class and its refcount
      57         352 :     this->m_pImageIO = pImageIO;
      58         352 :     this->m_pRefCount = pRefCount;
      59             :     // increment the refcount as we now have a reference to imageio
      60         352 :     this->m_pRefCount->IncRef();
      61             : 
      62             :     // Initialize overview variables
      63         352 :     m_nOverviews = 0;
      64         352 :     m_panOverviewBands = nullptr;
      65             : 
      66             :     // mask band
      67         352 :     m_pMaskBand = nullptr;
      68         352 :     m_bMaskBandOwned = false;
      69             : 
      70             :     // grab the description here
      71         352 :     this->sDescription = pImageIO->getImageBandDescription(nSrcBand);
      72             : 
      73         352 :     this->m_pAttributeTable = nullptr;  // no RAT yet
      74         352 :     this->m_pColorTable = nullptr;      // no color table yet
      75             : 
      76             :     // Initialize the metadata as a CPLStringList.
      77         352 :     m_papszMetadataList = nullptr;
      78         352 :     this->UpdateMetadataList();
      79         352 :     m_pszHistoBinValues = nullptr;
      80         352 : }
      81             : 
      82             : // destructor
      83         701 : KEARasterBand::~KEARasterBand()
      84             : {
      85             :     {
      86         704 :         CPLMutexHolderD(&m_hMutex);
      87             :         // destroy RAT if any
      88         352 :         delete this->m_pAttributeTable;
      89             :         // destroy color table if any
      90         352 :         delete this->m_pColorTable;
      91             :         // destroy the metadata
      92         352 :         CSLDestroy(this->m_papszMetadataList);
      93         352 :         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         352 :         this->deleteOverviewObjects();
     100             : 
     101             :         // if GDAL created the mask it will delete it
     102         352 :         if (m_bMaskBandOwned)
     103             :         {
     104           3 :             delete m_pMaskBand;
     105             :         }
     106             :     }
     107             : 
     108             :     // according to the docs, this is required
     109         352 :     this->FlushCache(true);
     110             : 
     111             :     // decrement the recount and delete if needed
     112         352 :     if (m_pRefCount->DecRef())
     113             :     {
     114             :         try
     115             :         {
     116         246 :             m_pImageIO->close();
     117             :         }
     118           0 :         catch (const kealib::KEAIOException &)
     119             :         {
     120             :         }
     121         246 :         delete m_pImageIO;
     122         246 :         delete m_pRefCount;
     123             :     }
     124         701 : }
     125             : 
     126             : // internal method that updates the metadata into m_papszMetadataList
     127         352 : void KEARasterBand::UpdateMetadataList()
     128             : {
     129         704 :     CPLMutexHolderD(&m_hMutex);
     130         704 :     std::vector<std::pair<std::string, std::string>> data;
     131             : 
     132             :     // get all the metadata and iterate through
     133         352 :     data = this->m_pImageIO->getImageBandMetaData(this->nBand);
     134         127 :     for (std::vector<std::pair<std::string, std::string>>::iterator
     135         352 :              iterMetaData = data.begin();
     136         479 :          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         352 :     if (this->m_pImageIO->getImageBandLayerType(this->nBand) ==
     146             :         kealib::kea_continuous)
     147             :     {
     148         343 :         m_papszMetadataList =
     149         343 :             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         352 :     const GDALRasterAttributeTable *pTable = KEARasterBand::GetDefaultRAT();
     159         352 :     if (pTable != nullptr)
     160             :     {
     161         704 :         CPLString osWorkingResult;
     162         352 :         osWorkingResult.Printf("%lu", (unsigned long)pTable->GetRowCount());
     163         352 :         m_papszMetadataList = CSLSetNameValue(
     164             :             m_papszMetadataList, "STATISTICS_HISTONUMBINS", osWorkingResult);
     165             : 
     166             :         // attribute table chunksize
     167         352 :         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         352 : }
     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 :             (KEADataset *)this->poDS, this->nBand, GA_Update, this->m_pImageIO,
     308           1 :             this->m_pRefCount, nCount + 1, nXSize, nYSize);
     309             :     }
     310           1 : }
     311             : 
     312             : // virtual method to read a block
     313         144 : 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         144 :         int nxsize = this->nBlockXSize;
     320         144 :         int nxtotalsize = this->nBlockXSize * (nBlockXOff + 1);
     321         144 :         if (nxtotalsize > this->nRasterXSize)
     322             :         {
     323          11 :             nxsize -= (nxtotalsize - this->nRasterXSize);
     324             :         }
     325         144 :         int nysize = this->nBlockYSize;
     326         144 :         int nytotalsize = this->nBlockYSize * (nBlockYOff + 1);
     327         144 :         if (nytotalsize > this->nRasterYSize)
     328             :         {
     329          11 :             nysize -= (nytotalsize - this->nRasterYSize);
     330             :         }
     331         144 :         this->m_pImageIO->readImageBlock2Band(
     332         144 :             this->nBand, pImage, this->nBlockXSize * nBlockXOff,
     333         144 :             this->nBlockYSize * nBlockYOff, nxsize, nysize, this->nBlockXSize,
     334         144 :             this->nBlockYSize, this->m_eKEADataType);
     335         144 :         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          12 : 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          12 :         int nxsize = this->nBlockXSize;
     353          12 :         int nxtotalsize = this->nBlockXSize * (nBlockXOff + 1);
     354          12 :         if (nxtotalsize > this->nRasterXSize)
     355             :         {
     356           0 :             nxsize -= (nxtotalsize - this->nRasterXSize);
     357             :         }
     358          12 :         int nysize = this->nBlockYSize;
     359          12 :         int nytotalsize = this->nBlockYSize * (nBlockYOff + 1);
     360          12 :         if (nytotalsize > this->nRasterYSize)
     361             :         {
     362           0 :             nysize -= (nytotalsize - this->nRasterYSize);
     363             :         }
     364             : 
     365          12 :         this->m_pImageIO->writeImageBlock2Band(
     366          12 :             this->nBand, pImage, this->nBlockXSize * nBlockXOff,
     367          12 :             this->nBlockYSize * nBlockYOff, nxsize, nysize, this->nBlockXSize,
     368          12 :             this->nBlockYSize, this->m_eKEADataType);
     369          12 :         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 : char **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           4 : CPLErr KEARasterBand::SetMetadata(char **papszMetadata, const char *pszDomain)
     489             : {
     490           8 :     CPLMutexHolderD(&m_hMutex);
     491             :     // only deal with 'default' domain - no geolocation etc
     492           4 :     if ((pszDomain != nullptr) && (*pszDomain != '\0'))
     493           1 :         return CE_Failure;
     494           3 :     int nIndex = 0;
     495             :     try
     496             :     {
     497             :         // iterate through each one
     498           6 :         while (papszMetadata[nIndex] != nullptr)
     499             :         {
     500           3 :             char *pszName = nullptr;
     501             :             const char *pszValue =
     502           3 :                 CPLParseNameValue(papszMetadata[nIndex], &pszName);
     503           3 :             if (pszValue == nullptr)
     504           0 :                 pszValue = "";
     505           3 :             if (pszName != nullptr)
     506             :             {
     507             :                 // it is LAYER_TYPE? if so handle separately
     508           3 :                 if (EQUAL(pszName, "LAYER_TYPE"))
     509             :                 {
     510           2 :                     if (EQUAL(pszValue, "athematic"))
     511             :                     {
     512           1 :                         this->m_pImageIO->setImageBandLayerType(
     513           1 :                             this->nBand, kealib::kea_continuous);
     514             :                     }
     515             :                     else
     516             :                     {
     517           1 :                         this->m_pImageIO->setImageBandLayerType(
     518           1 :                             this->nBand, kealib::kea_thematic);
     519             :                     }
     520             :                 }
     521           1 :                 else if (EQUAL(pszName, "STATISTICS_HISTOBINVALUES"))
     522             :                 {
     523           0 :                     if (this->SetHistogramFromString(pszValue) != CE_None)
     524             :                     {
     525           0 :                         CPLFree(pszName);
     526           0 :                         return CE_Failure;
     527             :                     }
     528             :                 }
     529             :                 else
     530             :                 {
     531             :                     // write it into the image
     532           1 :                     this->m_pImageIO->setImageBandMetaData(this->nBand, pszName,
     533             :                                                            pszValue);
     534             :                 }
     535           3 :                 CPLFree(pszName);
     536             :             }
     537           3 :             nIndex++;
     538             :         }
     539             :     }
     540           0 :     catch (const kealib::KEAIOException &)
     541             :     {
     542           0 :         return CE_Failure;
     543             :     }
     544             :     // destroy our list and duplicate the one passed in
     545             :     // and use that as our list from now on
     546           3 :     CSLDestroy(m_papszMetadataList);
     547           3 :     m_papszMetadataList = CSLDuplicate(papszMetadata);
     548           3 :     return CE_None;
     549             : }
     550             : 
     551             : // get the no data value
     552         282 : double KEARasterBand::GetNoDataValue(int *pbSuccess)
     553             : {
     554             :     try
     555             :     {
     556             :         double dVal;
     557         282 :         this->m_pImageIO->getNoDataValue(this->nBand, &dVal,
     558             :                                          kealib::kea_64float);
     559          65 :         if (pbSuccess != nullptr)
     560          53 :             *pbSuccess = 1;
     561             : 
     562          65 :         return dVal;
     563             :     }
     564         217 :     catch (const kealib::KEAIOException &)
     565             :     {
     566         217 :         if (pbSuccess != nullptr)
     567         217 :             *pbSuccess = 0;
     568         217 :         return -1;
     569             :     }
     570             : }
     571             : 
     572          22 : int64_t KEARasterBand::GetNoDataValueAsInt64(int *pbSuccess)
     573             : {
     574             :     try
     575             :     {
     576             :         int64_t nVal;
     577          22 :         this->m_pImageIO->getNoDataValue(this->nBand, &nVal, kealib::kea_64int);
     578          12 :         if (pbSuccess != nullptr)
     579           9 :             *pbSuccess = 1;
     580             : 
     581          12 :         return nVal;
     582             :     }
     583          10 :     catch (const kealib::KEAIOException &)
     584             :     {
     585          10 :         if (pbSuccess != nullptr)
     586          10 :             *pbSuccess = 0;
     587          10 :         return -1;
     588             :     }
     589             : }
     590             : 
     591          16 : uint64_t KEARasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
     592             : {
     593             :     try
     594             :     {
     595             :         uint64_t nVal;
     596          16 :         this->m_pImageIO->getNoDataValue(this->nBand, &nVal,
     597             :                                          kealib::kea_64uint);
     598           8 :         if (pbSuccess != nullptr)
     599           6 :             *pbSuccess = 1;
     600             : 
     601           8 :         return nVal;
     602             :     }
     603           8 :     catch (const kealib::KEAIOException &)
     604             :     {
     605           8 :         if (pbSuccess != nullptr)
     606           8 :             *pbSuccess = 0;
     607           8 :         return std::numeric_limits<uint64_t>::max();
     608             :     }
     609             : }
     610             : 
     611             : // set the no data value
     612          22 : CPLErr KEARasterBand::SetNoDataValue(double dfNoData)
     613             : {
     614             :     // need to check for out of range values
     615          22 :     bool bSet = true;
     616          22 :     GDALDataType dtype = this->GetRasterDataType();
     617          22 :     switch (dtype)
     618             :     {
     619           5 :         case GDT_Byte:
     620           5 :             bSet = (dfNoData >= 0) && (dfNoData <= UCHAR_MAX);
     621           5 :             break;
     622           4 :         case GDT_UInt16:
     623           4 :             bSet = (dfNoData >= 0) && (dfNoData <= USHRT_MAX);
     624           4 :             break;
     625           4 :         case GDT_Int16:
     626           4 :             bSet = (dfNoData >= SHRT_MIN) && (dfNoData <= SHRT_MAX);
     627           4 :             break;
     628           4 :         case GDT_UInt32:
     629           4 :             bSet = (dfNoData >= 0) && (dfNoData <= UINT_MAX);
     630           4 :             break;
     631           4 :         case GDT_Int32:
     632           4 :             bSet = (dfNoData >= INT_MIN) && (dfNoData <= INT_MAX);
     633           4 :             break;
     634           1 :         default:
     635             :             // for other types we can't really tell if outside the range
     636           1 :             break;
     637             :     }
     638             : 
     639             :     try
     640             :     {
     641          22 :         if (bSet)
     642             :         {
     643          12 :             this->m_pImageIO->setNoDataValue(this->nBand, &dfNoData,
     644             :                                              kealib::kea_64float);
     645             :         }
     646             :         else
     647             :         {
     648          10 :             this->m_pImageIO->undefineNoDataValue(this->nBand);
     649             :         }
     650          12 :         return CE_None;
     651             :     }
     652          10 :     catch (const kealib::KEAIOException &)
     653             :     {
     654          10 :         return CE_Failure;
     655             :     }
     656             : }
     657             : 
     658           3 : CPLErr KEARasterBand::SetNoDataValueAsInt64(int64_t nNoData)
     659             : {
     660             :     try
     661             :     {
     662           3 :         this->m_pImageIO->setNoDataValue(this->nBand, &nNoData,
     663             :                                          kealib::kea_64int);
     664             :     }
     665           0 :     catch (const kealib::KEAIOException &)
     666             :     {
     667           0 :         return CE_Failure;
     668             :     }
     669           3 :     return CE_None;
     670             : }
     671             : 
     672           2 : CPLErr KEARasterBand::SetNoDataValueAsUInt64(uint64_t nNoData)
     673             : {
     674             :     try
     675             :     {
     676           2 :         this->m_pImageIO->setNoDataValue(this->nBand, &nNoData,
     677             :                                          kealib::kea_64uint);
     678             :     }
     679           0 :     catch (const kealib::KEAIOException &)
     680             :     {
     681           0 :         return CE_Failure;
     682             :     }
     683           2 :     return CE_None;
     684             : }
     685             : 
     686          27 : CPLErr KEARasterBand::DeleteNoDataValue()
     687             : {
     688             :     try
     689             :     {
     690          27 :         m_pImageIO->undefineNoDataValue(this->nBand);
     691          17 :         return CE_None;
     692             :     }
     693          10 :     catch (const kealib::KEAIOException &)
     694             :     {
     695          10 :         return CE_Failure;
     696             :     }
     697             : }
     698             : 
     699           0 : CPLErr KEARasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
     700             :                                           int *pnBuckets,
     701             :                                           GUIntBig **ppanHistogram, int bForce,
     702             :                                           GDALProgressFunc fn,
     703             :                                           void *pProgressData)
     704             : {
     705           0 :     if (bForce)
     706             :     {
     707           0 :         return GDALRasterBand::GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
     708             :                                                    ppanHistogram, bForce, fn,
     709           0 :                                                    pProgressData);
     710             :     }
     711             :     else
     712             :     {
     713             :         // returned cached if avail
     714             :         // I've used the RAT interface here as it deals with data type
     715             :         // conversions. Would be nice to have GUIntBig support in RAT though...
     716           0 :         GDALRasterAttributeTable *pTable = this->GetDefaultRAT();
     717           0 :         if (pTable == nullptr)
     718           0 :             return CE_Failure;
     719           0 :         int nRows = pTable->GetRowCount();
     720             : 
     721             :         // find histogram column if it exists
     722           0 :         int nCol = pTable->GetColOfUsage(GFU_PixelCount);
     723           0 :         if (nCol == -1)
     724           0 :             return CE_Warning;
     725             : 
     726             :         double dfRow0Min, dfBinSize;
     727           0 :         if (!pTable->GetLinearBinning(&dfRow0Min, &dfBinSize))
     728           0 :             return CE_Warning;
     729             : 
     730           0 :         *ppanHistogram = (GUIntBig *)VSIMalloc2(nRows, sizeof(GUIntBig));
     731           0 :         if (*ppanHistogram == nullptr)
     732             :         {
     733           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     734             :                      "Memory Allocation failed in "
     735             :                      "KEARasterBand::GetDefaultHistogram");
     736           0 :             return CE_Failure;
     737             :         }
     738             : 
     739           0 :         double *pDoubleHisto = (double *)VSIMalloc2(nRows, sizeof(double));
     740           0 :         if (pDoubleHisto == nullptr)
     741             :         {
     742           0 :             CPLFree(*ppanHistogram);
     743           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     744             :                      "Memory Allocation failed in "
     745             :                      "KEARasterBand::GetDefaultHistogram");
     746           0 :             return CE_Failure;
     747             :         }
     748             : 
     749           0 :         if (pTable->ValuesIO(GF_Read, nCol, 0, nRows, pDoubleHisto) != CE_None)
     750           0 :             return CE_Failure;
     751             : 
     752             :         // convert to GUIntBig
     753           0 :         for (int n = 0; n < nRows; n++)
     754           0 :             (*ppanHistogram)[n] = static_cast<GUIntBig>(pDoubleHisto[n]);
     755             : 
     756           0 :         CPLFree(pDoubleHisto);
     757             : 
     758           0 :         *pnBuckets = nRows;
     759           0 :         *pdfMin = dfRow0Min;
     760           0 :         *pdfMax = dfRow0Min + ((nRows + 1) * dfBinSize);
     761           0 :         return CE_None;
     762             :     }
     763             : }
     764             : 
     765           0 : CPLErr KEARasterBand::SetDefaultHistogram(double /*dfMin*/, double /*dfMax*/,
     766             :                                           int nBuckets, GUIntBig *panHistogram)
     767             : {
     768             : 
     769           0 :     GDALRasterAttributeTable *pTable = this->GetDefaultRAT();
     770           0 :     if (pTable == nullptr)
     771           0 :         return CE_Failure;
     772           0 :     int nRows = pTable->GetRowCount();
     773             : 
     774             :     // find histogram column if it exists
     775           0 :     int nCol = pTable->GetColOfUsage(GFU_PixelCount);
     776           0 :     if (nCol == -1)
     777             :     {
     778           0 :         if (pTable->CreateColumn("Histogram", GFT_Real, GFU_PixelCount) !=
     779             :             CE_None)
     780           0 :             return CE_Failure;
     781             : 
     782           0 :         nCol = pTable->GetColumnCount() - 1;
     783             :     }
     784             : 
     785           0 :     if (nBuckets > nRows)
     786           0 :         pTable->SetRowCount(nBuckets);
     787             : 
     788             :     // convert to double (RATs don't take GUIntBig yet)
     789           0 :     double *pDoubleHist = (double *)VSIMalloc2(nBuckets, sizeof(double));
     790             : 
     791           0 :     if (pDoubleHist == nullptr)
     792             :     {
     793           0 :         CPLError(
     794             :             CE_Failure, CPLE_OutOfMemory,
     795             :             "Memory Allocation failed in KEARasterBand::SetDefaultHistogram");
     796           0 :         return CE_Failure;
     797             :     }
     798             : 
     799           0 :     for (int n = 0; n < nBuckets; n++)
     800           0 :         pDoubleHist[n] = static_cast<double>(panHistogram[n]);
     801             : 
     802           0 :     if (pTable->ValuesIO(GF_Write, nCol, 0, nBuckets, pDoubleHist) != CE_None)
     803             :     {
     804           0 :         CPLFree(pDoubleHist);
     805           0 :         return CE_Failure;
     806             :     }
     807             : 
     808           0 :     CPLFree(pDoubleHist);
     809             : 
     810           0 :     return CE_None;
     811             : }
     812             : 
     813         420 : GDALRasterAttributeTable *KEARasterBand::GetDefaultRAT()
     814             : {
     815         420 :     CPLMutexHolderD(&m_hMutex);
     816         420 :     if (this->m_pAttributeTable == nullptr)
     817             :     {
     818             :         try
     819             :         {
     820             :             // we assume this is never NULL - creates a new one if none exists
     821             :             // (or raises exception)
     822             :             kealib::KEAAttributeTable *pKEATable =
     823         704 :                 this->m_pImageIO->getAttributeTable(kealib::kea_att_file,
     824         352 :                                                     this->nBand);
     825         352 :             this->m_pAttributeTable =
     826         352 :                 new KEARasterAttributeTable(pKEATable, this);
     827             :         }
     828           0 :         catch (const kealib::KEAException &e)
     829             :         {
     830           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     831           0 :                      "Failed to read attributes: %s", e.what());
     832             :         }
     833             :     }
     834         840 :     return this->m_pAttributeTable;
     835             : }
     836             : 
     837           3 : CPLErr KEARasterBand::SetDefaultRAT(const GDALRasterAttributeTable *poRAT)
     838             : {
     839           3 :     if (poRAT == nullptr)
     840           1 :         return CE_Failure;
     841             : 
     842             :     try
     843             :     {
     844             :         KEARasterAttributeTable *pKEATable =
     845           2 :             (KEARasterAttributeTable *)this->GetDefaultRAT();
     846           2 :         if (pKEATable == nullptr)
     847           0 :             return CE_Failure;
     848             : 
     849           2 :         int numRows = poRAT->GetRowCount();
     850           2 :         pKEATable->SetRowCount(numRows);
     851             : 
     852          10 :         for (int nGDALColumnIndex = 0;
     853          10 :              nGDALColumnIndex < poRAT->GetColumnCount(); nGDALColumnIndex++)
     854             :         {
     855           8 :             const char *pszColumnName = poRAT->GetNameOfCol(nGDALColumnIndex);
     856           8 :             GDALRATFieldType eFieldType = poRAT->GetTypeOfCol(nGDALColumnIndex);
     857             : 
     858             :             // do we have it?
     859           8 :             bool bExists = false;
     860             :             int nKEAColumnIndex;
     861          29 :             for (nKEAColumnIndex = 0;
     862          29 :                  nKEAColumnIndex < pKEATable->GetColumnCount();
     863             :                  nKEAColumnIndex++)
     864             :             {
     865          29 :                 if (EQUAL(pszColumnName,
     866             :                           pKEATable->GetNameOfCol(nKEAColumnIndex)))
     867             :                 {
     868           8 :                     bExists = true;
     869           8 :                     break;
     870             :                 }
     871             :             }
     872             : 
     873           8 :             if (!bExists)
     874             :             {
     875           0 :                 if (pKEATable->CreateColumn(
     876             :                         pszColumnName, eFieldType,
     877           0 :                         poRAT->GetUsageOfCol(nGDALColumnIndex)) != CE_None)
     878             :                 {
     879           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     880             :                              "Failed to create column");
     881           0 :                     return CE_Failure;
     882             :                 }
     883           0 :                 nKEAColumnIndex = pKEATable->GetColumnCount() - 1;
     884             :             }
     885             : 
     886           8 :             if (numRows == 0)
     887           1 :                 continue;
     888             : 
     889             :             // ok now copy data
     890           7 :             if (eFieldType == GFT_Integer)
     891             :             {
     892             :                 int *panIntData =
     893           4 :                     (int *)VSI_MALLOC2_VERBOSE(numRows, sizeof(int));
     894           4 :                 if (panIntData == nullptr)
     895             :                 {
     896           0 :                     return CE_Failure;
     897             :                 }
     898             : 
     899           4 :                 if (((GDALRasterAttributeTable *)poRAT)
     900           8 :                         ->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows,
     901           4 :                                    panIntData) == CE_None)
     902             :                 {
     903           4 :                     pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0, numRows,
     904           4 :                                         panIntData);
     905             :                 }
     906           4 :                 CPLFree(panIntData);
     907             :             }
     908           3 :             else if (eFieldType == GFT_Real)
     909             :             {
     910             :                 double *padfFloatData =
     911           2 :                     (double *)VSI_MALLOC2_VERBOSE(numRows, sizeof(double));
     912           2 :                 if (padfFloatData == nullptr)
     913             :                 {
     914           0 :                     return CE_Failure;
     915             :                 }
     916             : 
     917           2 :                 if (((GDALRasterAttributeTable *)poRAT)
     918           4 :                         ->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows,
     919           2 :                                    padfFloatData) == CE_None)
     920             :                 {
     921           2 :                     pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0, numRows,
     922           2 :                                         padfFloatData);
     923             :                 }
     924           2 :                 CPLFree(padfFloatData);
     925             :             }
     926             :             else
     927             :             {
     928             :                 char **papszStringData =
     929           1 :                     (char **)VSI_MALLOC2_VERBOSE(numRows, sizeof(char *));
     930           1 :                 if (papszStringData == nullptr)
     931             :                 {
     932           0 :                     return CE_Failure;
     933             :                 }
     934             : 
     935           1 :                 if (((GDALRasterAttributeTable *)poRAT)
     936           2 :                         ->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows,
     937           1 :                                    papszStringData) == CE_None)
     938             :                 {
     939           1 :                     pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0, numRows,
     940           1 :                                         papszStringData);
     941           2 :                     for (int n = 0; n < numRows; n++)
     942           1 :                         CPLFree(papszStringData[n]);
     943             :                 }
     944           1 :                 CPLFree(papszStringData);
     945             :             }
     946             :         }
     947             :     }
     948           0 :     catch (const kealib::KEAException &e)
     949             :     {
     950           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to write attributes: %s",
     951           0 :                  e.what());
     952           0 :         return CE_Failure;
     953             :     }
     954           2 :     return CE_None;
     955             : }
     956             : 
     957           4 : GDALColorTable *KEARasterBand::GetColorTable()
     958             : {
     959           4 :     CPLMutexHolderD(&m_hMutex);
     960           4 :     if (this->m_pColorTable == nullptr)
     961             :     {
     962             :         try
     963             :         {
     964           4 :             GDALRasterAttributeTable *pKEATable = this->GetDefaultRAT();
     965           4 :             int nRedIdx = -1;
     966           4 :             int nGreenIdx = -1;
     967           4 :             int nBlueIdx = -1;
     968           4 :             int nAlphaIdx = -1;
     969             : 
     970          12 :             for (int nColIdx = 0; nColIdx < pKEATable->GetColumnCount();
     971             :                  nColIdx++)
     972             :             {
     973           8 :                 if (pKEATable->GetTypeOfCol(nColIdx) == GFT_Integer)
     974             :                 {
     975             :                     GDALRATFieldUsage eFieldUsage =
     976           8 :                         pKEATable->GetUsageOfCol(nColIdx);
     977           8 :                     if (eFieldUsage == GFU_Red)
     978           2 :                         nRedIdx = nColIdx;
     979           6 :                     else if (eFieldUsage == GFU_Green)
     980           2 :                         nGreenIdx = nColIdx;
     981           4 :                     else if (eFieldUsage == GFU_Blue)
     982           2 :                         nBlueIdx = nColIdx;
     983           2 :                     else if (eFieldUsage == GFU_Alpha)
     984           2 :                         nAlphaIdx = nColIdx;
     985             :                 }
     986             :             }
     987             : 
     988           4 :             if ((nRedIdx != -1) && (nGreenIdx != -1) && (nBlueIdx != -1) &&
     989             :                 (nAlphaIdx != -1))
     990             :             {
     991             :                 // we need to create one - only do RGB palettes
     992           2 :                 this->m_pColorTable = new GDALColorTable(GPI_RGB);
     993             : 
     994             :                 // OK go through each row and fill in the fields
     995           8 :                 for (int nRowIndex = 0; nRowIndex < pKEATable->GetRowCount();
     996             :                      nRowIndex++)
     997             :                 {
     998             :                     // maybe could be more efficient using ValuesIO
     999             :                     GDALColorEntry colorEntry;
    1000           6 :                     colorEntry.c1 = static_cast<short>(
    1001           6 :                         pKEATable->GetValueAsInt(nRowIndex, nRedIdx));
    1002           6 :                     colorEntry.c2 = static_cast<short>(
    1003           6 :                         pKEATable->GetValueAsInt(nRowIndex, nGreenIdx));
    1004           6 :                     colorEntry.c3 = static_cast<short>(
    1005           6 :                         pKEATable->GetValueAsInt(nRowIndex, nBlueIdx));
    1006           6 :                     colorEntry.c4 = static_cast<short>(
    1007           6 :                         pKEATable->GetValueAsInt(nRowIndex, nAlphaIdx));
    1008           6 :                     this->m_pColorTable->SetColorEntry(nRowIndex, &colorEntry);
    1009             :                 }
    1010             :             }
    1011             :         }
    1012           0 :         catch (const kealib::KEAException &e)
    1013             :         {
    1014           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1015           0 :                      "Failed to read color table: %s", e.what());
    1016           0 :             delete this->m_pColorTable;
    1017           0 :             this->m_pColorTable = nullptr;
    1018             :         }
    1019             :     }
    1020           8 :     return this->m_pColorTable;
    1021             : }
    1022             : 
    1023           5 : CPLErr KEARasterBand::SetColorTable(GDALColorTable *poCT)
    1024             : {
    1025           5 :     if (poCT == nullptr)
    1026           2 :         return CE_Failure;
    1027             : 
    1028           6 :     CPLMutexHolderD(&m_hMutex);
    1029             :     try
    1030             :     {
    1031           3 :         GDALRasterAttributeTable *pKEATable = this->GetDefaultRAT();
    1032           3 :         if (pKEATable == nullptr)
    1033           0 :             return CE_Failure;
    1034           3 :         int nRedIdx = -1;
    1035           3 :         int nGreenIdx = -1;
    1036           3 :         int nBlueIdx = -1;
    1037           3 :         int nAlphaIdx = -1;
    1038             : 
    1039           3 :         if (poCT->GetColorEntryCount() > pKEATable->GetRowCount())
    1040             :         {
    1041           2 :             pKEATable->SetRowCount(poCT->GetColorEntryCount());
    1042             :         }
    1043             : 
    1044           7 :         for (int nColIdx = 0; nColIdx < pKEATable->GetColumnCount(); nColIdx++)
    1045             :         {
    1046           4 :             if (pKEATable->GetTypeOfCol(nColIdx) == GFT_Integer)
    1047             :             {
    1048             :                 GDALRATFieldUsage eFieldUsage =
    1049           4 :                     pKEATable->GetUsageOfCol(nColIdx);
    1050           4 :                 if (eFieldUsage == GFU_Red)
    1051           1 :                     nRedIdx = nColIdx;
    1052           3 :                 else if (eFieldUsage == GFU_Green)
    1053           1 :                     nGreenIdx = nColIdx;
    1054           2 :                 else if (eFieldUsage == GFU_Blue)
    1055           1 :                     nBlueIdx = nColIdx;
    1056           1 :                 else if (eFieldUsage == GFU_Alpha)
    1057           1 :                     nAlphaIdx = nColIdx;
    1058             :             }
    1059             :         }
    1060             : 
    1061             :         // create if needed
    1062           3 :         if (nRedIdx == -1)
    1063             :         {
    1064           2 :             if (pKEATable->CreateColumn("Red", GFT_Integer, GFU_Red) != CE_None)
    1065             :             {
    1066           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1067             :                          "Failed to create column");
    1068           0 :                 return CE_Failure;
    1069             :             }
    1070           2 :             nRedIdx = pKEATable->GetColumnCount() - 1;
    1071             :         }
    1072           3 :         if (nGreenIdx == -1)
    1073             :         {
    1074           2 :             if (pKEATable->CreateColumn("Green", GFT_Integer, GFU_Green) !=
    1075             :                 CE_None)
    1076             :             {
    1077           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1078             :                          "Failed to create column");
    1079           0 :                 return CE_Failure;
    1080             :             }
    1081           2 :             nGreenIdx = pKEATable->GetColumnCount() - 1;
    1082             :         }
    1083           3 :         if (nBlueIdx == -1)
    1084             :         {
    1085           2 :             if (pKEATable->CreateColumn("Blue", GFT_Integer, GFU_Blue) !=
    1086             :                 CE_None)
    1087             :             {
    1088           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1089             :                          "Failed to create column");
    1090           0 :                 return CE_Failure;
    1091             :             }
    1092           2 :             nBlueIdx = pKEATable->GetColumnCount() - 1;
    1093             :         }
    1094           3 :         if (nAlphaIdx == -1)
    1095             :         {
    1096           2 :             if (pKEATable->CreateColumn("Alpha", GFT_Integer, GFU_Alpha) !=
    1097             :                 CE_None)
    1098             :             {
    1099           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1100             :                          "Failed to create column");
    1101           0 :                 return CE_Failure;
    1102             :             }
    1103           2 :             nAlphaIdx = pKEATable->GetColumnCount() - 1;
    1104             :         }
    1105             : 
    1106             :         // OK go through each row and fill in the fields
    1107          12 :         for (int nRowIndex = 0; nRowIndex < poCT->GetColorEntryCount();
    1108             :              nRowIndex++)
    1109             :         {
    1110             :             // maybe could be more efficient using ValuesIO
    1111             :             GDALColorEntry colorEntry;
    1112           9 :             poCT->GetColorEntryAsRGB(nRowIndex, &colorEntry);
    1113           9 :             pKEATable->SetValue(nRowIndex, nRedIdx, colorEntry.c1);
    1114           9 :             pKEATable->SetValue(nRowIndex, nGreenIdx, colorEntry.c2);
    1115           9 :             pKEATable->SetValue(nRowIndex, nBlueIdx, colorEntry.c3);
    1116           9 :             pKEATable->SetValue(nRowIndex, nAlphaIdx, colorEntry.c4);
    1117             :         }
    1118             : 
    1119             :         // out of date
    1120           3 :         delete this->m_pColorTable;
    1121           3 :         this->m_pColorTable = nullptr;
    1122             :     }
    1123           0 :     catch (const kealib::KEAException &e)
    1124             :     {
    1125           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to write color table: %s",
    1126           0 :                  e.what());
    1127           0 :         return CE_Failure;
    1128             :     }
    1129           3 :     return CE_None;
    1130             : }
    1131             : 
    1132          72 : GDALColorInterp KEARasterBand::GetColorInterpretation()
    1133             : {
    1134             :     kealib::KEABandClrInterp ekeainterp;
    1135             :     try
    1136             :     {
    1137          72 :         ekeainterp = this->m_pImageIO->getImageBandClrInterp(this->nBand);
    1138             :     }
    1139           0 :     catch (const kealib::KEAException &)
    1140             :     {
    1141           0 :         return GCI_GrayIndex;
    1142             :     }
    1143             : 
    1144             :     GDALColorInterp egdalinterp;
    1145          72 :     switch (ekeainterp)
    1146             :     {
    1147          42 :         case kealib::kea_generic:
    1148             :         case kealib::kea_greyindex:
    1149          42 :             egdalinterp = GCI_GrayIndex;
    1150          42 :             break;
    1151           2 :         case kealib::kea_paletteindex:
    1152           2 :             egdalinterp = GCI_PaletteIndex;
    1153           2 :             break;
    1154           2 :         case kealib::kea_redband:
    1155           2 :             egdalinterp = GCI_RedBand;
    1156           2 :             break;
    1157           2 :         case kealib::kea_greenband:
    1158           2 :             egdalinterp = GCI_GreenBand;
    1159           2 :             break;
    1160           2 :         case kealib::kea_blueband:
    1161           2 :             egdalinterp = GCI_BlueBand;
    1162           2 :             break;
    1163           2 :         case kealib::kea_alphaband:
    1164           2 :             egdalinterp = GCI_AlphaBand;
    1165           2 :             break;
    1166           2 :         case kealib::kea_hueband:
    1167           2 :             egdalinterp = GCI_HueBand;
    1168           2 :             break;
    1169           2 :         case kealib::kea_saturationband:
    1170           2 :             egdalinterp = GCI_SaturationBand;
    1171           2 :             break;
    1172           2 :         case kealib::kea_lightnessband:
    1173           2 :             egdalinterp = GCI_LightnessBand;
    1174           2 :             break;
    1175           2 :         case kealib::kea_cyanband:
    1176           2 :             egdalinterp = GCI_CyanBand;
    1177           2 :             break;
    1178           2 :         case kealib::kea_magentaband:
    1179           2 :             egdalinterp = GCI_MagentaBand;
    1180           2 :             break;
    1181           2 :         case kealib::kea_yellowband:
    1182           2 :             egdalinterp = GCI_YellowBand;
    1183           2 :             break;
    1184           2 :         case kealib::kea_blackband:
    1185           2 :             egdalinterp = GCI_BlackBand;
    1186           2 :             break;
    1187           2 :         case kealib::kea_ycbcr_yband:
    1188           2 :             egdalinterp = GCI_YCbCr_YBand;
    1189           2 :             break;
    1190           2 :         case kealib::kea_ycbcr_cbband:
    1191           2 :             egdalinterp = GCI_YCbCr_CbBand;
    1192           2 :             break;
    1193           2 :         case kealib::kea_ycbcr_crband:
    1194           2 :             egdalinterp = GCI_YCbCr_CrBand;
    1195           2 :             break;
    1196           0 :         default:
    1197           0 :             egdalinterp = GCI_GrayIndex;
    1198           0 :             break;
    1199             :     }
    1200             : 
    1201          72 :     return egdalinterp;
    1202             : }
    1203             : 
    1204         104 : CPLErr KEARasterBand::SetColorInterpretation(GDALColorInterp egdalinterp)
    1205             : {
    1206             :     kealib::KEABandClrInterp ekeainterp;
    1207         104 :     switch (egdalinterp)
    1208             :     {
    1209          53 :         case GCI_GrayIndex:
    1210          53 :             ekeainterp = kealib::kea_greyindex;
    1211          53 :             break;
    1212           2 :         case GCI_PaletteIndex:
    1213           2 :             ekeainterp = kealib::kea_paletteindex;
    1214           2 :             break;
    1215           2 :         case GCI_RedBand:
    1216           2 :             ekeainterp = kealib::kea_redband;
    1217           2 :             break;
    1218           2 :         case GCI_GreenBand:
    1219           2 :             ekeainterp = kealib::kea_greenband;
    1220           2 :             break;
    1221           2 :         case GCI_BlueBand:
    1222           2 :             ekeainterp = kealib::kea_blueband;
    1223           2 :             break;
    1224           2 :         case GCI_AlphaBand:
    1225           2 :             ekeainterp = kealib::kea_alphaband;
    1226           2 :             break;
    1227           2 :         case GCI_HueBand:
    1228           2 :             ekeainterp = kealib::kea_hueband;
    1229           2 :             break;
    1230           2 :         case GCI_SaturationBand:
    1231           2 :             ekeainterp = kealib::kea_saturationband;
    1232           2 :             break;
    1233           2 :         case GCI_LightnessBand:
    1234           2 :             ekeainterp = kealib::kea_lightnessband;
    1235           2 :             break;
    1236           2 :         case GCI_CyanBand:
    1237           2 :             ekeainterp = kealib::kea_cyanband;
    1238           2 :             break;
    1239           2 :         case GCI_MagentaBand:
    1240           2 :             ekeainterp = kealib::kea_magentaband;
    1241           2 :             break;
    1242           2 :         case GCI_YellowBand:
    1243           2 :             ekeainterp = kealib::kea_yellowband;
    1244           2 :             break;
    1245           2 :         case GCI_BlackBand:
    1246           2 :             ekeainterp = kealib::kea_blackband;
    1247           2 :             break;
    1248           2 :         case GCI_YCbCr_YBand:
    1249           2 :             ekeainterp = kealib::kea_ycbcr_yband;
    1250           2 :             break;
    1251           2 :         case GCI_YCbCr_CbBand:
    1252           2 :             ekeainterp = kealib::kea_ycbcr_cbband;
    1253           2 :             break;
    1254           2 :         case GCI_YCbCr_CrBand:
    1255           2 :             ekeainterp = kealib::kea_ycbcr_crband;
    1256           2 :             break;
    1257          21 :         default:
    1258          21 :             ekeainterp = kealib::kea_greyindex;
    1259          21 :             break;
    1260             :     }
    1261             : 
    1262             :     try
    1263             :     {
    1264         104 :         this->m_pImageIO->setImageBandClrInterp(this->nBand, ekeainterp);
    1265             :     }
    1266           0 :     catch (const kealib::KEAException &)
    1267             :     {
    1268             :         // Do nothing? The docs say CE_Failure only if unsupported by format.
    1269             :     }
    1270         104 :     return CE_None;
    1271             : }
    1272             : 
    1273             : // clean up our overview objects
    1274             : // assumes mutex being held by caller
    1275         700 : void KEARasterBand::deleteOverviewObjects()
    1276             : {
    1277             :     // deletes the objects - not the overviews themselves
    1278             :     int nCount;
    1279         703 :     for (nCount = 0; nCount < m_nOverviews; nCount++)
    1280             :     {
    1281           3 :         delete m_panOverviewBands[nCount];
    1282             :     }
    1283         700 :     CPLFree(m_panOverviewBands);
    1284         700 :     m_panOverviewBands = nullptr;
    1285         700 :     m_nOverviews = 0;
    1286         700 : }
    1287             : 
    1288             : // read in any overviews in the file into our array of objects
    1289         347 : void KEARasterBand::readExistingOverviews()
    1290             : {
    1291         694 :     CPLMutexHolderD(&m_hMutex);
    1292             :     // delete any existing overview bands
    1293         347 :     this->deleteOverviewObjects();
    1294             : 
    1295         347 :     m_nOverviews = this->m_pImageIO->getNumOfOverviews(this->nBand);
    1296         347 :     m_panOverviewBands =
    1297         347 :         (KEAOverview **)CPLMalloc(sizeof(KEAOverview *) * m_nOverviews);
    1298             : 
    1299             :     uint64_t nXSize, nYSize;
    1300         349 :     for (int nCount = 0; nCount < m_nOverviews; nCount++)
    1301             :     {
    1302           2 :         this->m_pImageIO->getOverviewSize(this->nBand, nCount + 1, &nXSize,
    1303             :                                           &nYSize);
    1304           2 :         m_panOverviewBands[nCount] = new KEAOverview(
    1305           2 :             (KEADataset *)this->poDS, this->nBand, GA_ReadOnly,
    1306           2 :             this->m_pImageIO, this->m_pRefCount, nCount + 1, nXSize, nYSize);
    1307             :     }
    1308         347 : }
    1309             : 
    1310             : // number of overviews
    1311          56 : int KEARasterBand::GetOverviewCount()
    1312             : {
    1313          56 :     return m_nOverviews;
    1314             : }
    1315             : 
    1316             : // get a given overview
    1317           6 : GDALRasterBand *KEARasterBand::GetOverview(int nOverview)
    1318             : {
    1319           6 :     if (nOverview < 0 || nOverview >= m_nOverviews)
    1320             :     {
    1321           2 :         return nullptr;
    1322             :     }
    1323             :     else
    1324             :     {
    1325           4 :         return m_panOverviewBands[nOverview];
    1326             :     }
    1327             : }
    1328             : 
    1329           2 : CPLErr KEARasterBand::CreateMaskBand(int)
    1330             : {
    1331           4 :     CPLMutexHolderD(&m_hMutex);
    1332           2 :     if (m_bMaskBandOwned)
    1333           0 :         delete m_pMaskBand;
    1334           2 :     m_pMaskBand = nullptr;
    1335             :     try
    1336             :     {
    1337           2 :         this->m_pImageIO->createMask(this->nBand);
    1338             :     }
    1339           0 :     catch (const kealib::KEAException &e)
    1340             :     {
    1341           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to create mask band: %s",
    1342           0 :                  e.what());
    1343           0 :         return CE_Failure;
    1344             :     }
    1345           2 :     return CE_None;
    1346             : }
    1347             : 
    1348         105 : GDALRasterBand *KEARasterBand::GetMaskBand()
    1349             : {
    1350         105 :     CPLMutexHolderD(&m_hMutex);
    1351         105 :     if (m_pMaskBand == nullptr)
    1352             :     {
    1353             :         try
    1354             :         {
    1355         100 :             if (this->m_pImageIO->maskCreated(this->nBand))
    1356             :             {
    1357           3 :                 m_pMaskBand =
    1358           3 :                     new KEAMaskBand(this, this->m_pImageIO, this->m_pRefCount);
    1359           3 :                 m_bMaskBandOwned = true;
    1360             :             }
    1361             :             else
    1362             :             {
    1363             :                 // use the base class implementation - GDAL will delete
    1364             :                 // fprintf( stderr, "returning base GetMaskBand()\n" );
    1365          97 :                 m_pMaskBand = GDALRasterBand::GetMaskBand();
    1366             :             }
    1367             :         }
    1368           0 :         catch (const kealib::KEAException &)
    1369             :         {
    1370             :             // do nothing?
    1371             :         }
    1372             :     }
    1373         210 :     return m_pMaskBand;
    1374             : }
    1375             : 
    1376         100 : int KEARasterBand::GetMaskFlags()
    1377             : {
    1378             :     try
    1379             :     {
    1380         100 :         if (!this->m_pImageIO->maskCreated(this->nBand))
    1381             :         {
    1382             :             // need to return the base class one since we are using
    1383             :             // the base class implementation of GetMaskBand()
    1384             :             // fprintf( stderr, "returning base GetMaskFlags()\n" );
    1385          97 :             return GDALRasterBand::GetMaskFlags();
    1386             :         }
    1387             :     }
    1388           0 :     catch (const kealib::KEAException &)
    1389             :     {
    1390             :         // do nothing?
    1391             :     }
    1392             : 
    1393             :     // none of the other flags seem to make sense...
    1394           3 :     return 0;
    1395             : }
    1396             : 
    1397           1 : kealib::KEALayerType KEARasterBand::getLayerType() const
    1398             : {
    1399           1 :     return m_pImageIO->getImageBandLayerType(nBand);
    1400             : }
    1401             : 
    1402           0 : void KEARasterBand::setLayerType(kealib::KEALayerType eLayerType)
    1403             : {
    1404           0 :     m_pImageIO->setImageBandLayerType(nBand, eLayerType);
    1405           0 : }

Generated by: LCOV version 1.14