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

Generated by: LCOV version 1.14