LCOV - code coverage report
Current view: top level - frmts/kea - keadataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 413 484 85.3 %
Date: 2026-05-29 23:25:07 Functions: 26 27 96.3 %

          Line data    Source code
       1             : /*
       2             :  *  keadataset.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 "keadataset.h"
      14             : #include "keaband.h"
      15             : #include "keacopy.h"
      16             : #include "keadrivercore.h"
      17             : #include <hdf5.h>
      18             : #include "../frmts/hdf5/hdf5vfl.h"
      19             : #include "cpl_vsi_virtual.h"
      20             : 
      21             : /************************************************************************/
      22             : /*                       KEADatasetDriverUnload()                       */
      23             : /************************************************************************/
      24             : 
      25           5 : void KEADatasetDriverUnload(GDALDriver *)
      26             : {
      27           5 :     HDF5VFLUnloadFileDriver();
      28           5 : }
      29             : 
      30             : // Function for converting a libkea type into a GDAL type
      31         405 : GDALDataType KEA_to_GDAL_Type(kealib::KEADataType ekeaType)
      32             : {
      33         405 :     GDALDataType egdalType = GDT_Unknown;
      34         405 :     switch (ekeaType)
      35             :     {
      36          14 :         case kealib::kea_8int:
      37          14 :             egdalType = GDT_Int8;
      38          14 :             break;
      39         183 :         case kealib::kea_8uint:
      40         183 :             egdalType = GDT_UInt8;
      41         183 :             break;
      42          33 :         case kealib::kea_16int:
      43          33 :             egdalType = GDT_Int16;
      44          33 :             break;
      45          31 :         case kealib::kea_32int:
      46          31 :             egdalType = GDT_Int32;
      47          31 :             break;
      48          26 :         case kealib::kea_64int:
      49          26 :             egdalType = GDT_Int64;
      50          26 :             break;
      51          31 :         case kealib::kea_16uint:
      52          31 :             egdalType = GDT_UInt16;
      53          31 :             break;
      54          31 :         case kealib::kea_32uint:
      55          31 :             egdalType = GDT_UInt32;
      56          31 :             break;
      57          22 :         case kealib::kea_64uint:
      58          22 :             egdalType = GDT_UInt64;
      59          22 :             break;
      60          19 :         case kealib::kea_32float:
      61          19 :             egdalType = GDT_Float32;
      62          19 :             break;
      63          15 :         case kealib::kea_64float:
      64          15 :             egdalType = GDT_Float64;
      65          15 :             break;
      66           0 :         default:
      67           0 :             egdalType = GDT_Unknown;
      68           0 :             break;
      69             :     }
      70         405 :     return egdalType;
      71             : }
      72             : 
      73             : // function for converting a GDAL type to a kealib type
      74         155 : kealib::KEADataType GDAL_to_KEA_Type(GDALDataType egdalType)
      75             : {
      76         155 :     kealib::KEADataType ekeaType = kealib::kea_undefined;
      77         155 :     switch (egdalType)
      78             :     {
      79           4 :         case GDT_Int8:
      80           4 :             ekeaType = kealib::kea_8int;
      81           4 :             break;
      82          54 :         case GDT_UInt8:
      83          54 :             ekeaType = kealib::kea_8uint;
      84          54 :             break;
      85          14 :         case GDT_Int16:
      86          14 :             ekeaType = kealib::kea_16int;
      87          14 :             break;
      88          13 :         case GDT_Int32:
      89          13 :             ekeaType = kealib::kea_32int;
      90          13 :             break;
      91          10 :         case GDT_Int64:
      92          10 :             ekeaType = kealib::kea_64int;
      93          10 :             break;
      94          13 :         case GDT_UInt16:
      95          13 :             ekeaType = kealib::kea_16uint;
      96          13 :             break;
      97          13 :         case GDT_UInt32:
      98          13 :             ekeaType = kealib::kea_32uint;
      99          13 :             break;
     100           8 :         case GDT_UInt64:
     101           8 :             ekeaType = kealib::kea_64uint;
     102           8 :             break;
     103           7 :         case GDT_Float32:
     104           7 :             ekeaType = kealib::kea_32float;
     105           7 :             break;
     106           5 :         case GDT_Float64:
     107           5 :             ekeaType = kealib::kea_64float;
     108           5 :             break;
     109          14 :         default:
     110          14 :             ekeaType = kealib::kea_undefined;
     111          14 :             break;
     112             :     }
     113         155 :     return ekeaType;
     114             : }
     115             : 
     116             : // static function - pointer set in driver
     117         142 : GDALDataset *KEADataset::Open(GDALOpenInfo *poOpenInfo)
     118             : {
     119         142 :     if (KEADriverIdentify(poOpenInfo))
     120             :     {
     121             :         try
     122             :         {
     123             :             // try and open it in the appropriate mode
     124             :             HDF5Ptr pH5File;
     125         142 :             if (poOpenInfo->eAccess == GA_ReadOnly)
     126             :             {
     127             : #if LIBKEA_VERSION_MAJOR < 2
     128             :                 // use the virtual driver so we can open files using
     129             :                 // /vsicurl etc
     130             :                 // do this same as libkea
     131             :                 H5::FileAccPropList keaAccessPlist =
     132         280 :                     H5::FileAccPropList(H5::FileAccPropList::DEFAULT);
     133         140 :                 keaAccessPlist.setCache(
     134             :                     kealib::KEA_MDC_NELMTS, kealib::KEA_RDCC_NELMTS,
     135             :                     kealib::KEA_RDCC_NBYTES, kealib::KEA_RDCC_W0);
     136         140 :                 keaAccessPlist.setSieveBufSize(kealib::KEA_SIEVE_BUF);
     137         140 :                 hsize_t blockSize = kealib::KEA_META_BLOCKSIZE;
     138         140 :                 keaAccessPlist.setMetaBlockSize(blockSize);
     139             :                 // but set the driver
     140         140 :                 keaAccessPlist.setDriver(HDF5VFLGetFileDriver(), nullptr);
     141             : 
     142         140 :                 const H5std_string keaImgFilePath(poOpenInfo->pszFilename);
     143         280 :                 pH5File = new H5::H5File(keaImgFilePath, H5F_ACC_RDONLY,
     144             :                                          H5::FileCreatPropList::DEFAULT,
     145         140 :                                          keaAccessPlist);
     146             : #else
     147             :                 // use the virtual driver so we can open files using
     148             :                 // /vsicurl etc
     149             :                 pH5File = kealib::KEAImageIO::openKeaH5RDOnly(
     150             :                     poOpenInfo->pszFilename, kealib::KEA_MDC_NELMTS,
     151             :                     kealib::KEA_RDCC_NELMTS, kealib::KEA_RDCC_NBYTES,
     152             :                     kealib::KEA_RDCC_W0, kealib::KEA_SIEVE_BUF,
     153             :                     kealib::KEA_META_BLOCKSIZE, HDF5VFLGetFileDriver(),
     154             :                     nullptr);
     155             : #endif
     156             :             }
     157             :             else
     158             :             {
     159             :                 // Must be a local file
     160             :                 pH5File =
     161           2 :                     kealib::KEAImageIO::openKeaH5RW(poOpenInfo->pszFilename);
     162             :             }
     163             :             // create the KEADataset object
     164         142 :             KEADataset *pDataset = new KEADataset(pH5File, poOpenInfo->eAccess);
     165             : 
     166             :             // set the description as the name
     167         142 :             pDataset->SetDescription(poOpenInfo->pszFilename);
     168             : 
     169         142 :             return pDataset;
     170             :         }
     171           0 :         catch (const kealib::KEAIOException &e)
     172             :         {
     173             :             // was a problem - can't be a valid file
     174           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     175             :                      "Attempt to open file `%s' failed. Error: %s\n",
     176           0 :                      poOpenInfo->pszFilename, e.what());
     177           0 :             return nullptr;
     178             :         }
     179           0 :         catch (...)
     180             :         {
     181             :             // was a problem - can't be a valid file
     182           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     183             :                      "Attempt to open file `%s' failed. Error: unknown\n",
     184             :                      poOpenInfo->pszFilename);
     185           0 :             return nullptr;
     186             :         }
     187             :     }
     188             :     else
     189             :     {
     190             :         // not a KEA file
     191           0 :         return nullptr;
     192             :     }
     193             : }
     194             : 
     195             : // static function
     196         163 : HDF5Ptr KEADataset::CreateLL(const char *pszFilename, int nXSize, int nYSize,
     197             :                              int nBandsIn, GDALDataType eType,
     198             :                              CSLConstList papszParamList)
     199             : {
     200         163 :     GDALDriverH hDriver = GDALGetDriverByName("KEA");
     201         326 :     if ((hDriver == nullptr) ||
     202         163 :         !GDALValidateCreationOptions(hDriver, papszParamList))
     203             :     {
     204           0 :         CPLError(
     205             :             CE_Failure, CPLE_OpenFailed,
     206             :             "Attempt to create file `%s' failed. Invalid creation option(s)\n",
     207             :             pszFilename);
     208           0 :         return nullptr;
     209             :     }
     210             : 
     211             :     // This helps avoiding issues with H5File handles in a bad state, that
     212             :     // may cause crashes at process termination
     213             :     // Cf https://github.com/OSGeo/gdal/issues/8743
     214         163 :     if (VSIFileManager::GetHandler(pszFilename) !=
     215         163 :         VSIFileManager::GetHandler(""))
     216             :     {
     217          11 :         CPLError(CE_Failure, CPLE_OpenFailed,
     218             :                  "Attempt to create file `%s' failed. /vsi file systems not "
     219             :                  "supported\n",
     220             :                  pszFilename);
     221          11 :         return nullptr;
     222             :     }
     223             : 
     224             :     // process any creation options in papszParamList
     225             :     // default value
     226         152 :     unsigned int nimageblockSize = kealib::KEA_IMAGE_CHUNK_SIZE;
     227             :     // see if they have provided a different value
     228         152 :     const char *pszValue = CSLFetchNameValue(papszParamList, "IMAGEBLOCKSIZE");
     229         152 :     if (pszValue != nullptr)
     230           2 :         nimageblockSize = (unsigned int)atol(pszValue);
     231             : 
     232         152 :     unsigned int nattblockSize = kealib::KEA_ATT_CHUNK_SIZE;
     233         152 :     pszValue = CSLFetchNameValue(papszParamList, "ATTBLOCKSIZE");
     234         152 :     if (pszValue != nullptr)
     235           1 :         nattblockSize = (unsigned int)atol(pszValue);
     236             : 
     237         152 :     unsigned int nmdcElmts = kealib::KEA_MDC_NELMTS;
     238         152 :     pszValue = CSLFetchNameValue(papszParamList, "MDC_NELMTS");
     239         152 :     if (pszValue != nullptr)
     240           1 :         nmdcElmts = (unsigned int)atol(pszValue);
     241             : 
     242         152 :     hsize_t nrdccNElmts = kealib::KEA_RDCC_NELMTS;
     243         152 :     pszValue = CSLFetchNameValue(papszParamList, "RDCC_NELMTS");
     244         152 :     if (pszValue != nullptr)
     245           1 :         nrdccNElmts = (unsigned int)atol(pszValue);
     246             : 
     247         152 :     hsize_t nrdccNBytes = kealib::KEA_RDCC_NBYTES;
     248         152 :     pszValue = CSLFetchNameValue(papszParamList, "RDCC_NBYTES");
     249         152 :     if (pszValue != nullptr)
     250           1 :         nrdccNBytes = (unsigned int)atol(pszValue);
     251             : 
     252         152 :     double nrdccW0 = kealib::KEA_RDCC_W0;
     253         152 :     pszValue = CSLFetchNameValue(papszParamList, "RDCC_W0");
     254         152 :     if (pszValue != nullptr)
     255           1 :         nrdccW0 = CPLAtof(pszValue);
     256             : 
     257         152 :     hsize_t nsieveBuf = kealib::KEA_SIEVE_BUF;
     258         152 :     pszValue = CSLFetchNameValue(papszParamList, "SIEVE_BUF");
     259         152 :     if (pszValue != nullptr)
     260           1 :         nsieveBuf = (unsigned int)atol(pszValue);
     261             : 
     262         152 :     hsize_t nmetaBlockSize = kealib::KEA_META_BLOCKSIZE;
     263         152 :     pszValue = CSLFetchNameValue(papszParamList, "META_BLOCKSIZE");
     264         152 :     if (pszValue != nullptr)
     265           1 :         nmetaBlockSize = (unsigned int)atol(pszValue);
     266             : 
     267         152 :     unsigned int ndeflate = kealib::KEA_DEFLATE;
     268         152 :     pszValue = CSLFetchNameValue(papszParamList, "DEFLATE");
     269         152 :     if (pszValue != nullptr)
     270           1 :         ndeflate = (unsigned int)atol(pszValue);
     271             : 
     272         152 :     kealib::KEADataType keaDataType = GDAL_to_KEA_Type(eType);
     273         152 :     if (nBandsIn > 0 && keaDataType == kealib::kea_undefined)
     274             :     {
     275          12 :         CPLError(CE_Failure, CPLE_NotSupported,
     276             :                  "Data type %s not supported in KEA",
     277             :                  GDALGetDataTypeName(eType));
     278          12 :         return nullptr;
     279             :     }
     280             : 
     281             :     try
     282             :     {
     283             :         // now create it
     284         148 :         HDF5Ptr keaImgH5File = kealib::KEAImageIO::createKEAImage(
     285             :             pszFilename, keaDataType, nXSize, nYSize, nBandsIn, nullptr,
     286             :             nullptr, nimageblockSize, nattblockSize, nmdcElmts, nrdccNElmts,
     287             :             nrdccNBytes, nrdccW0, nsieveBuf, nmetaBlockSize, ndeflate);
     288         136 :         return keaImgH5File;
     289             :     }
     290           4 :     catch (kealib::KEAIOException &e)
     291             :     {
     292           4 :         CPLError(CE_Failure, CPLE_OpenFailed,
     293             :                  "Attempt to create file `%s' failed. Error: %s\n", pszFilename,
     294           4 :                  e.what());
     295           4 :         return nullptr;
     296             :     }
     297           0 :     catch (...)
     298             :     {
     299           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     300             :                  "Attempt to create file `%s' failed. Error: unknown\n",
     301             :                  pszFilename);
     302           0 :         return nullptr;
     303             :     }
     304             : }
     305             : 
     306             : // static function- pointer set in driver
     307          84 : GDALDataset *KEADataset::Create(const char *pszFilename, int nXSize, int nYSize,
     308             :                                 int nBandsIn, GDALDataType eType,
     309             :                                 CSLConstList papszParamList)
     310             : {
     311             :     HDF5Ptr keaImgH5File =
     312          84 :         CreateLL(pszFilename, nXSize, nYSize, nBandsIn, eType, papszParamList);
     313          84 :     if (keaImgH5File == nullptr)
     314          10 :         return nullptr;
     315             : 
     316             :     bool bThematic =
     317          74 :         CPLTestBool(CSLFetchNameValueDef(papszParamList, "THEMATIC", "FALSE"));
     318             : 
     319             :     try
     320             :     {
     321             :         // create our dataset object
     322          74 :         KEADataset *pDataset = new KEADataset(keaImgH5File, GA_Update);
     323             : 
     324          74 :         pDataset->SetDescription(pszFilename);
     325             : 
     326             :         // set all to thematic if asked
     327          74 :         if (bThematic)
     328             :         {
     329           4 :             for (int nCount = 0; nCount < nBandsIn; nCount++)
     330             :             {
     331           3 :                 GDALRasterBand *pBand = pDataset->GetRasterBand(nCount + 1);
     332           3 :                 pBand->SetMetadataItem("LAYER_TYPE", "thematic");
     333             :             }
     334             :         }
     335             : 
     336          74 :         return pDataset;
     337             :     }
     338           0 :     catch (kealib::KEAIOException &e)
     339             :     {
     340           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     341             :                  "Attempt to create file `%s' failed. Error: %s\n", pszFilename,
     342           0 :                  e.what());
     343           0 :         return nullptr;
     344             :     }
     345             : }
     346             : 
     347          79 : GDALDataset *KEADataset::CreateCopy(const char *pszFilename,
     348             :                                     GDALDataset *pSrcDs, CPL_UNUSED int bStrict,
     349             :                                     CSLConstList papszParamList,
     350             :                                     GDALProgressFunc pfnProgress,
     351             :                                     void *pProgressData)
     352             : {
     353             :     // get the data out of the input dataset
     354          79 :     int nXSize = pSrcDs->GetRasterXSize();
     355          79 :     int nYSize = pSrcDs->GetRasterYSize();
     356          79 :     int nBands = pSrcDs->GetRasterCount();
     357             : 
     358             :     GDALDataType eType = (nBands == 0)
     359          79 :                              ? GDT_Unknown
     360          77 :                              : pSrcDs->GetRasterBand(1)->GetRasterDataType();
     361             :     HDF5Ptr keaImgH5File =
     362          79 :         CreateLL(pszFilename, nXSize, nYSize, nBands, eType, papszParamList);
     363          79 :     if (keaImgH5File == nullptr)
     364          17 :         return nullptr;
     365             : 
     366             :     bool bThematic =
     367          62 :         CPLTestBool(CSLFetchNameValueDef(papszParamList, "THEMATIC", "FALSE"));
     368             : 
     369             :     try
     370             :     {
     371             :         // create the imageio
     372          62 :         kealib::KEAImageIO *pImageIO = new kealib::KEAImageIO();
     373             : 
     374             :         // open the file
     375          62 :         pImageIO->openKEAImageHeader(keaImgH5File);
     376             : 
     377             :         // copy file
     378          62 :         if (!KEACopyFile(pSrcDs, pImageIO, pfnProgress, pProgressData))
     379             :         {
     380           0 :             delete pImageIO;
     381           0 :             return nullptr;
     382             :         }
     383             : 
     384             :         // close it
     385             :         try
     386             :         {
     387          62 :             pImageIO->close();
     388             :         }
     389           0 :         catch (const kealib::KEAIOException &)
     390             :         {
     391             :         }
     392          62 :         delete pImageIO;
     393             : 
     394             :         // now open it again - because the constructor loads all the info
     395             :         // in we need to copy the data first....
     396          62 :         keaImgH5File = kealib::KEAImageIO::openKeaH5RW(pszFilename);
     397             : 
     398             :         // and wrap it in a dataset
     399          62 :         KEADataset *pDataset = new KEADataset(keaImgH5File, GA_Update);
     400          62 :         pDataset->SetDescription(pszFilename);
     401             : 
     402             :         // set all to thematic if asked - overrides whatever set by CopyFile
     403          62 :         if (bThematic)
     404             :         {
     405           2 :             for (int nCount = 0; nCount < nBands; nCount++)
     406             :             {
     407           1 :                 GDALRasterBand *pBand = pDataset->GetRasterBand(nCount + 1);
     408           1 :                 pBand->SetMetadataItem("LAYER_TYPE", "thematic");
     409             :             }
     410             :         }
     411             : 
     412         151 :         for (int nCount = 0; nCount < nBands; nCount++)
     413             :         {
     414          89 :             pDataset->GetRasterBand(nCount + 1)
     415          89 :                 ->SetColorInterpretation(pSrcDs->GetRasterBand(nCount + 1)
     416          89 :                                              ->GetColorInterpretation());
     417             :         }
     418             : 
     419             :         // KEA has no concept of per-dataset mask band for now.
     420         151 :         for (int nCount = 0; nCount < nBands; nCount++)
     421             :         {
     422          89 :             if (pSrcDs->GetRasterBand(nCount + 1)->GetMaskFlags() ==
     423             :                 0)  // Per-band mask
     424             :             {
     425           1 :                 pDataset->GetRasterBand(nCount + 1)->CreateMaskBand(0);
     426           2 :                 if (GDALRasterBandCopyWholeRaster(
     427           2 :                         (GDALRasterBandH)pSrcDs->GetRasterBand(nCount + 1)
     428           1 :                             ->GetMaskBand(),
     429           1 :                         (GDALRasterBandH)pDataset->GetRasterBand(nCount + 1)
     430           1 :                             ->GetMaskBand(),
     431           1 :                         nullptr, nullptr, nullptr) != CE_None)
     432             :                 {
     433           0 :                     delete pDataset;
     434           0 :                     return nullptr;
     435             :                 }
     436             :             }
     437             :         }
     438             : 
     439          62 :         return pDataset;
     440             :     }
     441           0 :     catch (kealib::KEAException &e)
     442             :     {
     443           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     444             :                  "Attempt to create file `%s' failed. Error: %s\n", pszFilename,
     445           0 :                  e.what());
     446           0 :         return nullptr;
     447             :     }
     448             : }
     449             : 
     450             : // constructor
     451         278 : KEADataset::KEADataset(HDF5Ptr keaImgH5File, GDALAccess eAccessIn)
     452             : {
     453         278 :     this->m_hMutex = CPLCreateMutex();
     454         278 :     CPLReleaseMutex(this->m_hMutex);
     455             :     try
     456             :     {
     457             :         // Create the image IO and initialize the refcount.
     458         278 :         m_pImageIO = new kealib::KEAImageIO();
     459         278 :         m_pRefcount = new LockedRefCount();
     460             : 
     461             :         // NULL until we read them in.
     462         278 :         m_papszMetadataList = nullptr;
     463         278 :         m_pGCPs = nullptr;
     464             : 
     465             :         // open the file
     466         278 :         m_pImageIO->openKEAImageHeader(keaImgH5File);
     467             :         kealib::KEAImageSpatialInfo *pSpatialInfo =
     468         278 :             m_pImageIO->getSpatialInfo();
     469             : 
     470             :         // get the dimensions
     471         278 :         this->nBands = m_pImageIO->getNumOfImageBands();
     472         278 :         this->nRasterXSize = static_cast<int>(pSpatialInfo->xSize);
     473         278 :         this->nRasterYSize = static_cast<int>(pSpatialInfo->ySize);
     474         278 :         this->eAccess = eAccessIn;
     475             : 
     476             :         // create all the bands
     477         678 :         for (int nCount = 0; nCount < nBands; nCount++)
     478             :         {
     479             :             // Note: GDAL uses indices starting at 1 and so does kealib.
     480             :             // Create band object.
     481             :             KEARasterBand *pBand = new KEARasterBand(this, nCount + 1, eAccess,
     482         400 :                                                      m_pImageIO, m_pRefcount);
     483             :             // read in overviews
     484         400 :             pBand->readExistingOverviews();
     485             :             // set the band into this dataset
     486         400 :             this->SetBand(nCount + 1, pBand);
     487             :         }
     488             : 
     489             :         // read in the metadata
     490         278 :         this->UpdateMetadataList();
     491             :     }
     492           0 :     catch (const kealib::KEAIOException &e)
     493             :     {
     494             :         // ignore?
     495           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     496           0 :                  "Caught exception in KEADataset constructor %s", e.what());
     497             :     }
     498         278 : }
     499             : 
     500         556 : KEADataset::~KEADataset()
     501             : {
     502             :     {
     503         556 :         CPLMutexHolderD(&m_hMutex);
     504             :         // destroy the metadata
     505         278 :         CSLDestroy(m_papszMetadataList);
     506         278 :         this->DestroyGCPs();
     507             :     }
     508         278 :     if (m_pRefcount->DecRef())
     509             :     {
     510             :         try
     511             :         {
     512           7 :             m_pImageIO->close();
     513             :         }
     514           0 :         catch (const kealib::KEAIOException &)
     515             :         {
     516             :         }
     517           7 :         delete m_pImageIO;
     518           7 :         delete m_pRefcount;
     519             :     }
     520             : 
     521         278 :     CPLDestroyMutex(m_hMutex);
     522         278 :     m_hMutex = nullptr;
     523         556 : }
     524             : 
     525             : // read in the metadata into our CSLStringList
     526         278 : void KEADataset::UpdateMetadataList()
     527             : {
     528         556 :     CPLMutexHolderD(&m_hMutex);
     529         556 :     std::vector<std::pair<std::string, std::string>> odata;
     530             :     // get all the metadata
     531         278 :     odata = this->m_pImageIO->getImageMetaData();
     532          40 :     for (std::vector<std::pair<std::string, std::string>>::iterator
     533         278 :              iterMetaData = odata.begin();
     534         318 :          iterMetaData != odata.end(); ++iterMetaData)
     535             :     {
     536          40 :         m_papszMetadataList =
     537          40 :             CSLSetNameValue(m_papszMetadataList, iterMetaData->first.c_str(),
     538          40 :                             iterMetaData->second.c_str());
     539             :     }
     540         278 : }
     541             : 
     542             : // read in the geotransform
     543          64 : CPLErr KEADataset::GetGeoTransform(GDALGeoTransform &gt) const
     544             : {
     545             :     try
     546             :     {
     547             :         kealib::KEAImageSpatialInfo *pSpatialInfo =
     548          64 :             m_pImageIO->getSpatialInfo();
     549             :         // GDAL uses an array format
     550          64 :         gt.xorig = pSpatialInfo->tlX;
     551          64 :         gt.xscale = pSpatialInfo->xRes;
     552          64 :         gt.xrot = pSpatialInfo->xRot;
     553          64 :         gt.yorig = pSpatialInfo->tlY;
     554          64 :         gt.yrot = pSpatialInfo->yRot;
     555          64 :         gt.yscale = pSpatialInfo->yRes;
     556             : 
     557          64 :         return CE_None;
     558             :     }
     559           0 :     catch (const kealib::KEAIOException &e)
     560             :     {
     561           0 :         CPLError(CE_Warning, CPLE_AppDefined, "Unable to read geotransform: %s",
     562           0 :                  e.what());
     563           0 :         return CE_Failure;
     564             :     }
     565             : }
     566             : 
     567             : // read in the projection ref
     568          40 : const OGRSpatialReference *KEADataset::GetSpatialRef() const
     569             : {
     570          40 :     if (!m_oSRS.IsEmpty())
     571           0 :         return &m_oSRS;
     572             : 
     573             :     try
     574             :     {
     575             :         kealib::KEAImageSpatialInfo *pSpatialInfo =
     576          40 :             m_pImageIO->getSpatialInfo();
     577          40 :         m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     578          40 :         m_oSRS.importFromWkt(pSpatialInfo->wktString.c_str());
     579          40 :         return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
     580             :     }
     581           0 :     catch (const kealib::KEAIOException &)
     582             :     {
     583           0 :         return nullptr;
     584             :     }
     585             : }
     586             : 
     587             : // set the geotransform
     588          27 : CPLErr KEADataset::SetGeoTransform(const GDALGeoTransform &gt)
     589             : {
     590             :     try
     591             :     {
     592             :         // get the spatial info and update it
     593             :         kealib::KEAImageSpatialInfo *pSpatialInfo =
     594          27 :             m_pImageIO->getSpatialInfo();
     595             :         // convert back from GDAL's array format
     596          27 :         pSpatialInfo->tlX = gt.xorig;
     597          27 :         pSpatialInfo->xRes = gt.xscale;
     598          27 :         pSpatialInfo->xRot = gt.xrot;
     599          27 :         pSpatialInfo->tlY = gt.yorig;
     600          27 :         pSpatialInfo->yRot = gt.yrot;
     601          27 :         pSpatialInfo->yRes = gt.yscale;
     602             : 
     603          27 :         m_pImageIO->setSpatialInfo(pSpatialInfo);
     604          26 :         return CE_None;
     605             :     }
     606           1 :     catch (const kealib::KEAIOException &e)
     607             :     {
     608           1 :         CPLError(CE_Warning, CPLE_AppDefined,
     609           1 :                  "Unable to write geotransform: %s", e.what());
     610           1 :         return CE_Failure;
     611             :     }
     612             : }
     613             : 
     614             : // set the projection
     615          26 : CPLErr KEADataset::SetSpatialRef(const OGRSpatialReference *poSRS)
     616             : {
     617             :     try
     618             :     {
     619             :         // get the spatial info and update it
     620             :         kealib::KEAImageSpatialInfo *pSpatialInfo =
     621          26 :             m_pImageIO->getSpatialInfo();
     622             : 
     623          26 :         m_oSRS.Clear();
     624          26 :         if (poSRS)
     625             :         {
     626          26 :             m_oSRS = *poSRS;
     627          26 :             char *pszWKT = nullptr;
     628          26 :             m_oSRS.exportToWkt(&pszWKT);
     629          26 :             pSpatialInfo->wktString = pszWKT ? pszWKT : "";
     630          26 :             CPLFree(pszWKT);
     631             :         }
     632             :         else
     633             :         {
     634           0 :             pSpatialInfo->wktString.clear();
     635             :         }
     636             : 
     637          26 :         m_pImageIO->setSpatialInfo(pSpatialInfo);
     638          26 :         return CE_None;
     639             :     }
     640           0 :     catch (const kealib::KEAIOException &e)
     641             :     {
     642           0 :         CPLError(CE_Warning, CPLE_AppDefined, "Unable to write projection: %s",
     643           0 :                  e.what());
     644           0 :         return CE_Failure;
     645             :     }
     646             : }
     647             : 
     648             : // Thought this might be handy to pass back to the application
     649           0 : void *KEADataset::GetInternalHandle(const char *)
     650             : {
     651           0 :     return m_pImageIO;
     652             : }
     653             : 
     654             : // this is called by GDALDataset::BuildOverviews. we implement this function to
     655             : // support building of overviews
     656           1 : CPLErr KEADataset::IBuildOverviews(const char *pszResampling, int nOverviews,
     657             :                                    const int *panOverviewList, int nListBands,
     658             :                                    const int *panBandList,
     659             :                                    GDALProgressFunc pfnProgress,
     660             :                                    void *pProgressData,
     661             :                                    CSLConstList papszOptions)
     662             : {
     663             :     // go through the list of bands that have been passed in
     664           1 :     int nCurrentBand, nOK = 1;
     665           2 :     for (int nBandCount = 0; (nBandCount < nListBands) && nOK; nBandCount++)
     666             :     {
     667             :         // get the band number
     668           1 :         nCurrentBand = panBandList[nBandCount];
     669             :         // get the band
     670             :         KEARasterBand *pBand =
     671           1 :             cpl::down_cast<KEARasterBand *>(GetRasterBand(nCurrentBand));
     672             :         // create the overview object
     673           1 :         pBand->CreateOverviews(nOverviews, panOverviewList);
     674             : 
     675             :         // get GDAL to do the hard work. It will calculate the overviews and
     676             :         // write them back into the objects
     677           1 :         if (GDALRegenerateOverviewsEx(
     678             :                 (GDALRasterBandH)pBand, nOverviews,
     679           1 :                 (GDALRasterBandH *)pBand->GetOverviewList(), pszResampling,
     680           1 :                 pfnProgress, pProgressData, papszOptions) != CE_None)
     681             :         {
     682           0 :             nOK = 0;
     683             :         }
     684             :     }
     685           1 :     if (!nOK)
     686             :     {
     687           0 :         return CE_Failure;
     688             :     }
     689             :     else
     690             :     {
     691           1 :         return CE_None;
     692             :     }
     693             : }
     694             : 
     695             : // set a single metadata item
     696           2 : CPLErr KEADataset::SetMetadataItem(const char *pszName, const char *pszValue,
     697             :                                    const char *pszDomain)
     698             : {
     699           4 :     CPLMutexHolderD(&m_hMutex);
     700             :     // only deal with 'default' domain - no geolocation etc
     701           2 :     if ((pszDomain != nullptr) && (*pszDomain != '\0'))
     702           1 :         return CE_Failure;
     703             : 
     704             :     try
     705             :     {
     706           1 :         this->m_pImageIO->setImageMetaData(pszName, pszValue);
     707             :         // CSLSetNameValue will update if already there
     708           1 :         m_papszMetadataList =
     709           1 :             CSLSetNameValue(m_papszMetadataList, pszName, pszValue);
     710           1 :         return CE_None;
     711             :     }
     712           0 :     catch (const kealib::KEAIOException &e)
     713             :     {
     714           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Unable to write metadata: %s",
     715           0 :                  e.what());
     716           0 :         return CE_Failure;
     717             :     }
     718             : }
     719             : 
     720             : // get a single metadata item
     721         150 : const char *KEADataset::GetMetadataItem(const char *pszName,
     722             :                                         const char *pszDomain)
     723             : {
     724         300 :     CPLMutexHolderD(&m_hMutex);
     725             :     // only deal with 'default' domain - no geolocation etc
     726         150 :     if ((pszDomain != nullptr) && (*pszDomain != '\0'))
     727          38 :         return nullptr;
     728             :     // string returned from CSLFetchNameValue should be persistent
     729         112 :     return CSLFetchNameValue(m_papszMetadataList, pszName);
     730             : }
     731             : 
     732             : // get the whole metadata as CSLStringList - note may be thread safety issues
     733          51 : CSLConstList KEADataset::GetMetadata(const char *pszDomain)
     734             : {
     735             :     // only deal with 'default' domain - no geolocation etc
     736          51 :     if ((pszDomain != nullptr) && (*pszDomain != '\0'))
     737           1 :         return nullptr;
     738             :     // this is what we store it as anyway
     739          50 :     return m_papszMetadataList;
     740             : }
     741             : 
     742             : // set the whole metadata as a CSLStringList
     743           3 : CPLErr KEADataset::SetMetadata(CSLConstList papszMetadata,
     744             :                                const char *pszDomain)
     745             : {
     746           6 :     CPLMutexHolderD(&m_hMutex);
     747             :     // only deal with 'default' domain - no geolocation etc
     748           3 :     if ((pszDomain != nullptr) && (*pszDomain != '\0'))
     749           1 :         return CE_Failure;
     750             : 
     751           2 :     int nIndex = 0;
     752             :     try
     753             :     {
     754             :         // go through each item
     755           4 :         while (papszMetadata[nIndex] != nullptr)
     756             :         {
     757             :             // get the value/name
     758           2 :             char *pszName = nullptr;
     759             :             const char *pszValue =
     760           2 :                 CPLParseNameValue(papszMetadata[nIndex], &pszName);
     761           2 :             if (pszValue == nullptr)
     762           0 :                 pszValue = "";
     763           2 :             if (pszName != nullptr)
     764             :             {
     765             :                 // set it with imageio
     766           2 :                 this->m_pImageIO->setImageMetaData(pszName, pszValue);
     767           2 :                 CPLFree(pszName);
     768             :             }
     769           2 :             nIndex++;
     770             :         }
     771             :     }
     772           0 :     catch (const kealib::KEAIOException &e)
     773             :     {
     774           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Unable to write metadata: %s",
     775           0 :                  e.what());
     776           0 :         return CE_Failure;
     777             :     }
     778             : 
     779             :     // destroy our one and replace it
     780           2 :     CSLDestroy(m_papszMetadataList);
     781           2 :     m_papszMetadataList = CSLDuplicate(papszMetadata);
     782           2 :     return CE_None;
     783             : }
     784             : 
     785           3 : CPLErr KEADataset::AddBand(GDALDataType eType, CSLConstList papszOptions)
     786             : {
     787             :     // process any creation options in papszOptions
     788           3 :     unsigned int nimageBlockSize = kealib::KEA_IMAGE_CHUNK_SIZE;
     789           3 :     unsigned int nattBlockSize = kealib::KEA_ATT_CHUNK_SIZE;
     790           3 :     unsigned int ndeflate = kealib::KEA_DEFLATE;
     791           3 :     if (papszOptions != nullptr)
     792             :     {
     793             :         const char *pszValue =
     794           1 :             CSLFetchNameValue(papszOptions, "IMAGEBLOCKSIZE");
     795           1 :         if (pszValue != nullptr)
     796             :         {
     797           0 :             nimageBlockSize = atoi(pszValue);
     798             :         }
     799             : 
     800           1 :         pszValue = CSLFetchNameValue(papszOptions, "ATTBLOCKSIZE");
     801           1 :         if (pszValue != nullptr)
     802             :         {
     803           0 :             nattBlockSize = atoi(pszValue);
     804             :         }
     805             : 
     806           1 :         pszValue = CSLFetchNameValue(papszOptions, "DEFLATE");
     807           1 :         if (pszValue != nullptr)
     808             :         {
     809           1 :             ndeflate = atoi(pszValue);
     810             :         }
     811             :     }
     812             : 
     813           3 :     kealib::KEADataType keaDataType = GDAL_to_KEA_Type(eType);
     814           3 :     if (keaDataType == kealib::kea_undefined)
     815             :     {
     816           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     817             :                  "Data type %s not supported in KEA",
     818             :                  GDALGetDataTypeName(eType));
     819           0 :         return CE_Failure;
     820             :     }
     821             : 
     822             :     try
     823             :     {
     824           5 :         m_pImageIO->addImageBand(keaDataType, "", nimageBlockSize,
     825           3 :                                  nattBlockSize, ndeflate);
     826             :     }
     827           1 :     catch (const kealib::KEAIOException &e)
     828             :     {
     829           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Unable to create band: %s",
     830           1 :                  e.what());
     831           1 :         return CE_Failure;
     832             :     }
     833             : 
     834             :     // create a new band and add it to the dataset
     835             :     // note GDAL uses indices starting at 1 and so does kealib
     836             :     KEARasterBand *pBand = new KEARasterBand(
     837           2 :         this, this->nBands + 1, this->eAccess, m_pImageIO, m_pRefcount);
     838           2 :     this->SetBand(this->nBands + 1, pBand);
     839             : 
     840           2 :     return CE_None;
     841             : }
     842             : 
     843          43 : int KEADataset::GetGCPCount()
     844             : {
     845             :     try
     846             :     {
     847          43 :         return m_pImageIO->getGCPCount();
     848             :     }
     849          38 :     catch (const kealib::KEAIOException &)
     850             :     {
     851          38 :         return 0;
     852             :     }
     853             : }
     854             : 
     855           2 : const OGRSpatialReference *KEADataset::GetGCPSpatialRef() const
     856             : {
     857           4 :     CPLMutexHolderD(&m_hMutex);
     858           2 :     if (m_oGCPSRS.IsEmpty())
     859             :     {
     860             :         try
     861             :         {
     862           4 :             std::string sProj = m_pImageIO->getGCPProjection();
     863           2 :             m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     864           2 :             m_oGCPSRS.Clear();
     865           2 :             if (!sProj.empty())
     866           2 :                 m_oGCPSRS.importFromWkt(sProj.c_str());
     867             :         }
     868           0 :         catch (const kealib::KEAIOException &)
     869             :         {
     870           0 :             return nullptr;
     871             :         }
     872             :     }
     873           2 :     return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
     874             : }
     875             : 
     876           2 : const GDAL_GCP *KEADataset::GetGCPs()
     877             : {
     878           4 :     CPLMutexHolderD(&m_hMutex);
     879           2 :     if (m_pGCPs == nullptr)
     880             :     {
     881             :         // convert to GDAL data structures
     882             :         try
     883             :         {
     884           2 :             unsigned int nCount = m_pImageIO->getGCPCount();
     885             :             std::vector<kealib::KEAImageGCP *> *pKEAGCPs =
     886           2 :                 m_pImageIO->getGCPs();
     887             : 
     888           2 :             m_pGCPs = (GDAL_GCP *)CPLCalloc(nCount, sizeof(GDAL_GCP));
     889           6 :             for (unsigned int nIndex = 0; nIndex < nCount; nIndex++)
     890             :             {
     891           4 :                 GDAL_GCP *pGCP = &m_pGCPs[nIndex];
     892           4 :                 kealib::KEAImageGCP *pKEAGCP = pKEAGCPs->at(nIndex);
     893           4 :                 pGCP->pszId = CPLStrdup(pKEAGCP->pszId.c_str());
     894           4 :                 pGCP->pszInfo = CPLStrdup(pKEAGCP->pszInfo.c_str());
     895           4 :                 pGCP->dfGCPPixel = pKEAGCP->dfGCPPixel;
     896           4 :                 pGCP->dfGCPLine = pKEAGCP->dfGCPLine;
     897           4 :                 pGCP->dfGCPX = pKEAGCP->dfGCPX;
     898           4 :                 pGCP->dfGCPY = pKEAGCP->dfGCPY;
     899           4 :                 pGCP->dfGCPZ = pKEAGCP->dfGCPZ;
     900             : 
     901           4 :                 delete pKEAGCP;
     902             :             }
     903             : 
     904           2 :             delete pKEAGCPs;
     905             :         }
     906           0 :         catch (const kealib::KEAIOException &)
     907             :         {
     908           0 :             return nullptr;
     909             :         }
     910             :     }
     911           2 :     return m_pGCPs;
     912             : }
     913             : 
     914           1 : CPLErr KEADataset::SetGCPs(int nGCPCount, const GDAL_GCP *pasGCPList,
     915             :                            const OGRSpatialReference *poSRS)
     916             : {
     917           1 :     CPLMutexHolderD(&m_hMutex);
     918           1 :     this->DestroyGCPs();
     919           1 :     m_oGCPSRS.Clear();
     920           1 :     CPLErr result = CE_None;
     921             : 
     922             :     std::vector<kealib::KEAImageGCP *> *pKEAGCPs =
     923           1 :         new std::vector<kealib::KEAImageGCP *>(nGCPCount);
     924           3 :     for (int nIndex = 0; nIndex < nGCPCount; nIndex++)
     925             :     {
     926           2 :         const GDAL_GCP *pGCP = &pasGCPList[nIndex];
     927           2 :         kealib::KEAImageGCP *pKEA = new kealib::KEAImageGCP;
     928           2 :         pKEA->pszId = pGCP->pszId;
     929           2 :         pKEA->pszInfo = pGCP->pszInfo;
     930           2 :         pKEA->dfGCPPixel = pGCP->dfGCPPixel;
     931           2 :         pKEA->dfGCPLine = pGCP->dfGCPLine;
     932           2 :         pKEA->dfGCPX = pGCP->dfGCPX;
     933           2 :         pKEA->dfGCPY = pGCP->dfGCPY;
     934           2 :         pKEA->dfGCPZ = pGCP->dfGCPZ;
     935           2 :         pKEAGCPs->at(nIndex) = pKEA;
     936             :     }
     937             :     try
     938             :     {
     939           1 :         char *pszGCPProjection = nullptr;
     940           1 :         if (poSRS)
     941             :         {
     942           1 :             m_oGCPSRS = *poSRS;
     943           1 :             poSRS->exportToWkt(&pszGCPProjection);
     944           2 :             m_pImageIO->setGCPs(pKEAGCPs,
     945           1 :                                 pszGCPProjection ? pszGCPProjection : "");
     946           1 :             CPLFree(pszGCPProjection);
     947             :         }
     948             :         else
     949             :         {
     950           0 :             m_pImageIO->setGCPs(pKEAGCPs, "");
     951             :         }
     952             :     }
     953           0 :     catch (const kealib::KEAIOException &e)
     954             :     {
     955           0 :         CPLError(CE_Warning, CPLE_AppDefined, "Unable to write GCPs: %s",
     956           0 :                  e.what());
     957           0 :         result = CE_Failure;
     958             :     }
     959             : 
     960           3 :     for (std::vector<kealib::KEAImageGCP *>::iterator itr = pKEAGCPs->begin();
     961           5 :          itr != pKEAGCPs->end(); ++itr)
     962             :     {
     963           2 :         kealib::KEAImageGCP *pKEA = (*itr);
     964           2 :         delete pKEA;
     965             :     }
     966           1 :     delete pKEAGCPs;
     967             : 
     968           2 :     return result;
     969             : }
     970             : 
     971         279 : void KEADataset::DestroyGCPs()
     972             : {
     973         558 :     CPLMutexHolderD(&m_hMutex);
     974         279 :     if (m_pGCPs != nullptr)
     975             :     {
     976             :         // we assume this is always the same as the internal list...
     977           2 :         int nCount = this->GetGCPCount();
     978           6 :         for (int nIndex = 0; nIndex < nCount; nIndex++)
     979             :         {
     980           4 :             GDAL_GCP *pGCP = &m_pGCPs[nIndex];
     981           4 :             CPLFree(pGCP->pszId);
     982           4 :             CPLFree(pGCP->pszInfo);
     983             :         }
     984           2 :         CPLFree(m_pGCPs);
     985           2 :         m_pGCPs = nullptr;
     986             :     }
     987         279 : }

Generated by: LCOV version 1.14