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

Generated by: LCOV version 1.14