LCOV - code coverage report
Current view: top level - frmts/pcidsk - pcidskdataset2.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 598 882 67.8 %
Date: 2024-04-27 17:22:41 Functions: 43 45 95.6 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  PCIDSK Database File
       4             :  * Purpose:  Read/write PCIDSK Database File used by the PCI software, using
       5             :  *           the external PCIDSK library.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
      10             :  * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * Permission is hereby granted, free of charge, to any person obtaining a
      13             :  * copy of this software and associated documentation files (the "Software"),
      14             :  * to deal in the Software without restriction, including without limitation
      15             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16             :  * and/or sell copies of the Software, and to permit persons to whom the
      17             :  * Software is furnished to do so, subject to the following conditions:
      18             :  *
      19             :  * The above copyright notice and this permission notice shall be included
      20             :  * in all copies or substantial portions of the Software.
      21             :  *
      22             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28             :  * DEALINGS IN THE SOFTWARE.
      29             :  ****************************************************************************/
      30             : 
      31             : #include "gdal_frmts.h"
      32             : #include "pcidskdataset2.h"
      33             : #include "pcidskdrivercore.h"
      34             : 
      35             : #include <algorithm>
      36             : 
      37             : const PCIDSK::PCIDSKInterfaces *PCIDSK2GetInterfaces(void);
      38             : 
      39             : /************************************************************************/
      40             : /* ==================================================================== */
      41             : /*                            PCIDSK2Band                               */
      42             : /* ==================================================================== */
      43             : /************************************************************************/
      44             : 
      45             : /************************************************************************/
      46             : /*                            PCIDSK2Band()                             */
      47             : /*                                                                      */
      48             : /*      This constructor is used for main file channels.                */
      49             : /************************************************************************/
      50             : 
      51         231 : PCIDSK2Band::PCIDSK2Band(PCIDSKFile *poFileIn, PCIDSKChannel *poChannelIn)
      52             : 
      53             : {
      54         231 :     Initialize();
      55             : 
      56         231 :     poFile = poFileIn;
      57         231 :     poChannel = poChannelIn;
      58             : 
      59         231 :     nBlockXSize = static_cast<int>(poChannel->GetBlockWidth());
      60         231 :     nBlockYSize = static_cast<int>(poChannel->GetBlockHeight());
      61             : 
      62         231 :     eDataType = PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType());
      63             : 
      64         231 :     if (!STARTS_WITH_CI(poChannel->GetDescription().c_str(),
      65             :                         "Contents Not Specified"))
      66          10 :         GDALMajorObject::SetDescription(poChannel->GetDescription().c_str());
      67             : 
      68             :     /* -------------------------------------------------------------------- */
      69             :     /*      Do we have overviews?                                           */
      70             :     /* -------------------------------------------------------------------- */
      71         231 :     RefreshOverviewList();
      72         231 : }
      73             : 
      74             : /************************************************************************/
      75             : /*                            PCIDSK2Band()                             */
      76             : /*                                                                      */
      77             : /*      This constructor is used for overviews and bitmap segments      */
      78             : /*      as bands.                                                       */
      79             : /************************************************************************/
      80             : 
      81          11 : PCIDSK2Band::PCIDSK2Band(PCIDSKChannel *poChannelIn)
      82             : 
      83             : {
      84          11 :     Initialize();
      85             : 
      86          11 :     this->poChannel = poChannelIn;
      87             : 
      88          11 :     nBand = 1;
      89             : 
      90          11 :     nBlockXSize = static_cast<int>(poChannel->GetBlockWidth());
      91          11 :     nBlockYSize = static_cast<int>(poChannel->GetBlockHeight());
      92             : 
      93          11 :     nRasterXSize = static_cast<int>(poChannel->GetWidth());
      94          11 :     nRasterYSize = static_cast<int>(poChannel->GetHeight());
      95             : 
      96          11 :     eDataType = PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType());
      97             : 
      98          11 :     if (poChannel->GetType() == CHN_BIT)
      99             :     {
     100           0 :         PCIDSK2Band::SetMetadataItem("NBITS", "1", "IMAGE_STRUCTURE");
     101             : 
     102           0 :         if (!STARTS_WITH_CI(poChannel->GetDescription().c_str(),
     103             :                             "Contents Not Specified"))
     104           0 :             GDALMajorObject::SetDescription(
     105           0 :                 poChannel->GetDescription().c_str());
     106             :     }
     107          11 : }
     108             : 
     109             : /************************************************************************/
     110             : /*                             Initialize()                             */
     111             : /************************************************************************/
     112             : 
     113         242 : void PCIDSK2Band::Initialize()
     114             : 
     115             : {
     116         242 :     papszLastMDListValue = nullptr;
     117             : 
     118         242 :     poChannel = nullptr;
     119         242 :     poFile = nullptr;
     120         242 :     poDS = nullptr;
     121             : 
     122         242 :     bCheckedForColorTable = false;
     123         242 :     poColorTable = nullptr;
     124         242 :     nPCTSegNumber = -1;
     125             : 
     126         242 :     papszCategoryNames = nullptr;
     127         242 : }
     128             : 
     129             : /************************************************************************/
     130             : /*                            ~PCIDSK2Band()                            */
     131             : /************************************************************************/
     132             : 
     133         726 : PCIDSK2Band::~PCIDSK2Band()
     134             : 
     135             : {
     136         253 :     while (!apoOverviews.empty())
     137             :     {
     138          11 :         delete apoOverviews.back();
     139          11 :         apoOverviews.pop_back();
     140             :     }
     141         242 :     CSLDestroy(papszLastMDListValue);
     142         242 :     CSLDestroy(papszCategoryNames);
     143             : 
     144         242 :     delete poColorTable;
     145         484 : }
     146             : 
     147             : /************************************************************************/
     148             : /*                           SetDescription()                           */
     149             : /************************************************************************/
     150             : 
     151           3 : void PCIDSK2Band::SetDescription(const char *pszDescription)
     152             : 
     153             : {
     154           3 :     if (GetAccess() == GA_ReadOnly)
     155             :     {
     156           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
     157             :                  "Unable to set description on read-only file.");
     158           0 :         return;
     159             :     }
     160             : 
     161             :     try
     162             :     {
     163           3 :         poChannel->SetDescription(pszDescription);
     164             : 
     165           3 :         if (!STARTS_WITH_CI(poChannel->GetDescription().c_str(),
     166             :                             "Contents Not Specified"))
     167           3 :             GDALMajorObject::SetDescription(
     168           6 :                 poChannel->GetDescription().c_str());
     169             :     }
     170           0 :     catch (const PCIDSKException &ex)
     171             :     {
     172           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     173             :     }
     174             : }
     175             : 
     176             : /************************************************************************/
     177             : /*                          GetCategoryNames()                          */
     178             : /*                                                                      */
     179             : /*      Offer category names from Class_*_ metadata.                    */
     180             : /************************************************************************/
     181             : 
     182           4 : char **PCIDSK2Band::GetCategoryNames()
     183             : 
     184             : {
     185             :     // already scanned?
     186           4 :     if (papszCategoryNames != nullptr)
     187           0 :         return papszCategoryNames;
     188             : 
     189             :     try
     190             :     {
     191           8 :         std::vector<std::string> aosMDKeys = poChannel->GetMetadataKeys();
     192           4 :         int nClassCount = 0;
     193           4 :         constexpr int nMaxClasses = 10000;
     194           4 :         papszCategoryNames = reinterpret_cast<char **>(
     195           4 :             CPLCalloc(nMaxClasses + 1, sizeof(char *)));
     196             : 
     197           7 :         for (size_t i = 0; i < aosMDKeys.size(); i++)
     198             :         {
     199           3 :             CPLString osKey = aosMDKeys[i];
     200             : 
     201             :             // is this a "Class_n_name" keyword?
     202           3 :             if (!STARTS_WITH_CI(osKey, "Class_"))
     203           3 :                 continue;
     204             : 
     205           0 :             if (!EQUAL(osKey.c_str() + osKey.size() - 5, "_name"))
     206           0 :                 continue;
     207             : 
     208             :             // Ignore unreasonable class values.
     209           0 :             int iClass = atoi(osKey.c_str() + 6);
     210             : 
     211           0 :             if (iClass < 0 || iClass > 10000)
     212           0 :                 continue;
     213             : 
     214             :             // Fetch the name.
     215           0 :             CPLString osName = poChannel->GetMetadataValue(osKey);
     216             : 
     217             :             // do we need to put in place dummy class names for missing values?
     218           0 :             if (iClass >= nClassCount)
     219             :             {
     220           0 :                 while (iClass >= nClassCount)
     221             :                 {
     222           0 :                     papszCategoryNames[nClassCount++] = CPLStrdup("");
     223           0 :                     papszCategoryNames[nClassCount] = nullptr;
     224             :                 }
     225             :             }
     226             : 
     227             :             // Replace target category name.
     228           0 :             CPLFree(papszCategoryNames[iClass]);
     229           0 :             papszCategoryNames[iClass] = nullptr;
     230             : 
     231           0 :             papszCategoryNames[iClass] = CPLStrdup(osName);
     232             :         }
     233             : 
     234           4 :         if (nClassCount == 0)
     235           4 :             return GDALPamRasterBand::GetCategoryNames();
     236             : 
     237           0 :         return papszCategoryNames;
     238             :     }
     239           0 :     catch (const PCIDSKException &ex)
     240             :     {
     241           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     242           0 :         return nullptr;
     243             :     }
     244             : }
     245             : 
     246             : /************************************************************************/
     247             : /*                         CheckForColorTable()                         */
     248             : /************************************************************************/
     249             : 
     250          25 : bool PCIDSK2Band::CheckForColorTable()
     251             : 
     252             : {
     253          25 :     if (bCheckedForColorTable || poFile == nullptr)
     254          13 :         return true;
     255             : 
     256          12 :     bCheckedForColorTable = true;
     257             : 
     258             :     try
     259             :     {
     260             :         /* --------------------------------------------------------------------
     261             :          */
     262             :         /*      Try to find an appropriate PCT segment to use. */
     263             :         /* --------------------------------------------------------------------
     264             :          */
     265             :         std::string osDefaultPCT =
     266          36 :             poChannel->GetMetadataValue("DEFAULT_PCT_REF");
     267          12 :         PCIDSKSegment *poPCTSeg = nullptr;
     268             : 
     269             :         // If there is no metadata, assume a single PCT in a file with only
     270             :         // one raster band must be intended for it.
     271          23 :         if (osDefaultPCT.empty() && poDS != nullptr &&
     272          11 :             poDS->GetRasterCount() == 1)
     273             :         {
     274          11 :             poPCTSeg = poFile->GetSegment(SEG_PCT, "");
     275          11 :             if (poPCTSeg != nullptr &&
     276          11 :                 poFile->GetSegment(SEG_PCT, "", poPCTSeg->GetSegmentNumber()) !=
     277             :                     nullptr)
     278           0 :                 poPCTSeg = nullptr;
     279             :         }
     280             :         // Parse default PCT ref assuming an in file reference.
     281           2 :         else if (!osDefaultPCT.empty() &&
     282           1 :                  strstr(osDefaultPCT.c_str(), "PCT:") != nullptr)
     283             :         {
     284           1 :             poPCTSeg = poFile->GetSegment(
     285           1 :                 atoi(strstr(osDefaultPCT.c_str(), "PCT:") + 4));
     286             :         }
     287             : 
     288          12 :         if (poPCTSeg != nullptr)
     289             :         {
     290           1 :             poColorTable = new GDALColorTable();
     291             :             unsigned char abyPCT[768];
     292             : 
     293           1 :             PCIDSK_PCT *poPCT = dynamic_cast<PCIDSK_PCT *>(poPCTSeg);
     294           1 :             if (poPCT)
     295             :             {
     296           1 :                 nPCTSegNumber = poPCTSeg->GetSegmentNumber();
     297             : 
     298           1 :                 poPCT->ReadPCT(abyPCT);
     299             : 
     300         257 :                 for (int i = 0; i < 256; i++)
     301             :                 {
     302             :                     GDALColorEntry sEntry;
     303             : 
     304         256 :                     sEntry.c1 = abyPCT[256 * 0 + i];
     305         256 :                     sEntry.c2 = abyPCT[256 * 1 + i];
     306         256 :                     sEntry.c3 = abyPCT[256 * 2 + i];
     307         256 :                     sEntry.c4 = 255;
     308         256 :                     poColorTable->SetColorEntry(i, &sEntry);
     309             :                 }
     310             :             }
     311             :         }
     312             : 
     313             :         /* --------------------------------------------------------------------
     314             :          */
     315             :         /*      If we did not find an appropriate PCT segment, check for */
     316             :         /*      Class_n color data from which to construct a color table. */
     317             :         /* --------------------------------------------------------------------
     318             :          */
     319          24 :         std::vector<std::string> aosMDKeys = poChannel->GetMetadataKeys();
     320             : 
     321          22 :         for (size_t i = 0; i < aosMDKeys.size(); i++)
     322             :         {
     323          10 :             CPLString osKey = aosMDKeys[i];
     324             : 
     325             :             // is this a "Class_n_name" keyword?
     326             : 
     327          10 :             if (!STARTS_WITH_CI(osKey, "Class_"))
     328          10 :                 continue;
     329             : 
     330           0 :             if (!EQUAL(osKey.c_str() + osKey.size() - 6, "_Color"))
     331           0 :                 continue;
     332             : 
     333             :             // Ignore unreasonable class values.
     334           0 :             const int iClass = atoi(osKey.c_str() + 6);
     335             : 
     336           0 :             if (iClass < 0 || iClass > 10000)
     337           0 :                 continue;
     338             : 
     339             :             // Fetch and parse the RGB value "(RGB:red green blue)"
     340           0 :             CPLString osRGB = poChannel->GetMetadataValue(osKey);
     341             : 
     342           0 :             if (!STARTS_WITH_CI(osRGB, "(RGB:"))
     343           0 :                 continue;
     344             : 
     345             :             int nRed, nGreen, nBlue;
     346           0 :             if (sscanf(osRGB.c_str() + 5, "%d %d %d", &nRed, &nGreen, &nBlue) !=
     347             :                 3)
     348           0 :                 continue;
     349             : 
     350             :             // we have an entry - apply to the color table.
     351             :             GDALColorEntry sEntry;
     352             : 
     353           0 :             sEntry.c1 = (short)nRed;
     354           0 :             sEntry.c2 = (short)nGreen;
     355           0 :             sEntry.c3 = (short)nBlue;
     356           0 :             sEntry.c4 = 255;
     357             : 
     358           0 :             if (poColorTable == nullptr)
     359             :             {
     360           0 :                 CPLDebug("PCIDSK",
     361             :                          "Using Class_n_Color metadata for color table.");
     362           0 :                 poColorTable = new GDALColorTable();
     363             :             }
     364             : 
     365           0 :             poColorTable->SetColorEntry(iClass, &sEntry);
     366             :         }
     367             :     }
     368           0 :     catch (const PCIDSKException &ex)
     369             :     {
     370           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     371           0 :         return false;
     372             :     }
     373             : 
     374          12 :     return true;
     375             : }
     376             : 
     377             : /************************************************************************/
     378             : /*                           GetColorTable()                            */
     379             : /************************************************************************/
     380             : 
     381          10 : GDALColorTable *PCIDSK2Band::GetColorTable()
     382             : 
     383             : {
     384          10 :     CheckForColorTable();
     385             : 
     386          10 :     if (poColorTable)
     387           2 :         return poColorTable;
     388             : 
     389           8 :     return GDALPamRasterBand::GetColorTable();
     390             : }
     391             : 
     392             : /************************************************************************/
     393             : /*                           SetColorTable()                            */
     394             : /************************************************************************/
     395             : 
     396           2 : CPLErr PCIDSK2Band::SetColorTable(GDALColorTable *poCT)
     397             : 
     398             : {
     399           2 :     if (!CheckForColorTable())
     400           0 :         return CE_Failure;
     401             : 
     402             :     // no color tables on overviews.
     403           2 :     if (poFile == nullptr)
     404           0 :         return CE_Failure;
     405             : 
     406           2 :     if (GetAccess() == GA_ReadOnly)
     407             :     {
     408           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
     409             :                  "Unable to set color table on read-only file.");
     410           0 :         return CE_Failure;
     411             :     }
     412             : 
     413             :     try
     414             :     {
     415             :         /* --------------------------------------------------------------------
     416             :          */
     417             :         /*      Are we trying to delete the color table? */
     418             :         /* --------------------------------------------------------------------
     419             :          */
     420           2 :         if (poCT == nullptr)
     421             :         {
     422           1 :             delete poColorTable;
     423           1 :             poColorTable = nullptr;
     424             : 
     425           1 :             if (nPCTSegNumber != -1)
     426           1 :                 poFile->DeleteSegment(nPCTSegNumber);
     427           1 :             poChannel->SetMetadataValue("DEFAULT_PCT_REF", "");
     428           1 :             nPCTSegNumber = -1;
     429             : 
     430           1 :             return CE_None;
     431             :         }
     432             : 
     433             :         /* --------------------------------------------------------------------
     434             :          */
     435             :         /*      Do we need to create the segment?  If so, also set the */
     436             :         /*      default pct metadata. */
     437             :         /* --------------------------------------------------------------------
     438             :          */
     439           1 :         if (nPCTSegNumber == -1)
     440             :         {
     441           1 :             nPCTSegNumber = poFile->CreateSegment(
     442           1 :                 "PCTTable", "Default Pseudo-Color Table", SEG_PCT, 0);
     443             : 
     444           1 :             CPLString osRef;
     445           1 :             osRef.Printf("gdb:/{PCT:%d}", nPCTSegNumber);
     446           1 :             poChannel->SetMetadataValue("DEFAULT_PCT_REF", osRef);
     447             :         }
     448             : 
     449             :         /* --------------------------------------------------------------------
     450             :          */
     451             :         /*      Write out the PCT. */
     452             :         /* --------------------------------------------------------------------
     453             :          */
     454           1 :         const int nColorCount = std::min(256, poCT->GetColorEntryCount());
     455             : 
     456             :         unsigned char abyPCT[768];
     457           1 :         memset(abyPCT, 0, 768);
     458             : 
     459           4 :         for (int i = 0; i < nColorCount; i++)
     460             :         {
     461             :             GDALColorEntry sEntry;
     462             : 
     463           3 :             poCT->GetColorEntryAsRGB(i, &sEntry);
     464           3 :             abyPCT[256 * 0 + i] = (unsigned char)sEntry.c1;
     465           3 :             abyPCT[256 * 1 + i] = (unsigned char)sEntry.c2;
     466           3 :             abyPCT[256 * 2 + i] = (unsigned char)sEntry.c3;
     467             :         }
     468             : 
     469             :         PCIDSK_PCT *poPCT =
     470           1 :             dynamic_cast<PCIDSK_PCT *>(poFile->GetSegment(nPCTSegNumber));
     471           1 :         if (poPCT)
     472           1 :             poPCT->WritePCT(abyPCT);
     473             : 
     474           1 :         delete poColorTable;
     475           1 :         poColorTable = poCT->Clone();
     476             :     }
     477             : 
     478             :     /* -------------------------------------------------------------------- */
     479             :     /*      Trap exceptions.                                                */
     480             :     /* -------------------------------------------------------------------- */
     481           0 :     catch (const PCIDSKException &ex)
     482             :     {
     483           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     484           0 :         return CE_Failure;
     485             :     }
     486             : 
     487           1 :     return CE_None;
     488             : }
     489             : 
     490             : /************************************************************************/
     491             : /*                       GetColorInterpretation()                       */
     492             : /************************************************************************/
     493             : 
     494          13 : GDALColorInterp PCIDSK2Band::GetColorInterpretation()
     495             : 
     496             : {
     497          13 :     CheckForColorTable();
     498             : 
     499          13 :     if (poColorTable != nullptr)
     500           1 :         return GCI_PaletteIndex;
     501             : 
     502          12 :     return GDALPamRasterBand::GetColorInterpretation();
     503             : }
     504             : 
     505             : /************************************************************************/
     506             : /*                        RefreshOverviewList()                         */
     507             : /************************************************************************/
     508             : 
     509         232 : void PCIDSK2Band::RefreshOverviewList()
     510             : 
     511             : {
     512             :     /* -------------------------------------------------------------------- */
     513             :     /*      Clear existing overviews.                                       */
     514             :     /* -------------------------------------------------------------------- */
     515         232 :     while (!apoOverviews.empty())
     516             :     {
     517           0 :         delete apoOverviews.back();
     518           0 :         apoOverviews.pop_back();
     519             :     }
     520             : 
     521             :     /* -------------------------------------------------------------------- */
     522             :     /*      Fetch overviews.                                                */
     523             :     /* -------------------------------------------------------------------- */
     524         243 :     for (int iOver = 0; iOver < poChannel->GetOverviewCount(); iOver++)
     525             :     {
     526          11 :         auto poOvrBand = new PCIDSK2Band(poChannel->GetOverview(iOver));
     527          11 :         poOvrBand->eAccess = eAccess;
     528          11 :         apoOverviews.push_back(poOvrBand);
     529             :     }
     530         232 : }
     531             : 
     532             : /************************************************************************/
     533             : /*                             IReadBlock()                             */
     534             : /************************************************************************/
     535             : 
     536         261 : CPLErr PCIDSK2Band::IReadBlock(int iBlockX, int iBlockY, void *pData)
     537             : 
     538             : {
     539             :     try
     540             :     {
     541         261 :         poChannel->ReadBlock(iBlockX + iBlockY * nBlocksPerRow, pData);
     542             : 
     543             :         // Do we need to upsample 1bit to 8bit?
     544         261 :         if (poChannel->GetType() == CHN_BIT)
     545             :         {
     546           0 :             GByte *pabyData = reinterpret_cast<GByte *>(pData);
     547             : 
     548           0 :             for (int ii = nBlockXSize * nBlockYSize - 1; ii >= 0; ii--)
     549             :             {
     550           0 :                 if ((pabyData[ii >> 3] & (0x80 >> (ii & 0x7))))
     551           0 :                     pabyData[ii] = 1;
     552             :                 else
     553           0 :                     pabyData[ii] = 0;
     554             :             }
     555             :         }
     556             : 
     557         261 :         return CE_None;
     558             :     }
     559           0 :     catch (const PCIDSKException &ex)
     560             :     {
     561           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     562           0 :         return CE_Failure;
     563             :     }
     564             : }
     565             : 
     566             : /************************************************************************/
     567             : /*                             IWriteBlock()                            */
     568             : /************************************************************************/
     569             : 
     570         516 : CPLErr PCIDSK2Band::IWriteBlock(int iBlockX, int iBlockY, void *pData)
     571             : 
     572             : {
     573             :     try
     574             :     {
     575         516 :         poChannel->WriteBlock(iBlockX + iBlockY * nBlocksPerRow, pData);
     576             :     }
     577           0 :     catch (const PCIDSKException &ex)
     578             :     {
     579           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     580           0 :         return CE_Failure;
     581             :     }
     582             : 
     583         516 :     return CE_None;
     584             : }
     585             : 
     586             : /************************************************************************/
     587             : /*                          GetOverviewCount()                          */
     588             : /************************************************************************/
     589             : 
     590          16 : int PCIDSK2Band::GetOverviewCount()
     591             : 
     592             : {
     593          16 :     if (!apoOverviews.empty())
     594           5 :         return static_cast<int>(apoOverviews.size());
     595             : 
     596          11 :     return GDALPamRasterBand::GetOverviewCount();
     597             : }
     598             : 
     599             : /************************************************************************/
     600             : /*                            GetOverview()                             */
     601             : /************************************************************************/
     602             : 
     603           6 : GDALRasterBand *PCIDSK2Band::GetOverview(int iOverview)
     604             : 
     605             : {
     606           6 :     if (iOverview < 0 || iOverview >= static_cast<int>(apoOverviews.size()))
     607           1 :         return GDALPamRasterBand::GetOverview(iOverview);
     608             : 
     609           5 :     return apoOverviews[iOverview];
     610             : }
     611             : 
     612             : /************************************************************************/
     613             : /*                            SetMetadata()                             */
     614             : /************************************************************************/
     615             : 
     616           1 : CPLErr PCIDSK2Band::SetMetadata(char **papszMD, const char *pszDomain)
     617             : 
     618             : {
     619             :     /* -------------------------------------------------------------------- */
     620             :     /*      PCIDSK only supports metadata in the default domain.            */
     621             :     /* -------------------------------------------------------------------- */
     622           1 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
     623           0 :         return GDALPamRasterBand::SetMetadata(papszMD, pszDomain);
     624             : 
     625             :     /* -------------------------------------------------------------------- */
     626             :     /*      Set each item individually.                                     */
     627             :     /* -------------------------------------------------------------------- */
     628           1 :     CSLDestroy(papszLastMDListValue);
     629           1 :     papszLastMDListValue = nullptr;
     630           1 :     m_oCacheMetadataItem.clear();
     631             : 
     632           1 :     if (GetAccess() == GA_ReadOnly)
     633             :     {
     634           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
     635             :                  "Unable to set metadata on read-only file.");
     636           0 :         return CE_Failure;
     637             :     }
     638             : 
     639             :     try
     640             :     {
     641           3 :         for (int iItem = 0; papszMD && papszMD[iItem]; iItem++)
     642             :         {
     643           2 :             char *pszItemName = nullptr;
     644             : 
     645             :             const char *pszItemValue =
     646           2 :                 CPLParseNameValue(papszMD[iItem], &pszItemName);
     647           2 :             if (pszItemName != nullptr)
     648             :             {
     649           2 :                 poChannel->SetMetadataValue(pszItemName, pszItemValue);
     650           2 :                 CPLFree(pszItemName);
     651             :             }
     652             :         }
     653             :     }
     654           0 :     catch (const PCIDSKException &ex)
     655             :     {
     656           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     657           0 :         return CE_Failure;
     658             :     }
     659             : 
     660           1 :     return CE_None;
     661             : }
     662             : 
     663             : /************************************************************************/
     664             : /*                          SetMetadataItem()                           */
     665             : /************************************************************************/
     666             : 
     667           5 : CPLErr PCIDSK2Band::SetMetadataItem(const char *pszName, const char *pszValue,
     668             :                                     const char *pszDomain)
     669             : 
     670             : {
     671             :     /* -------------------------------------------------------------------- */
     672             :     /*      PCIDSK only supports metadata in the default domain.            */
     673             :     /* -------------------------------------------------------------------- */
     674           5 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
     675           1 :         return GDALPamRasterBand::SetMetadataItem(pszName, pszValue, pszDomain);
     676             : 
     677             :     /* -------------------------------------------------------------------- */
     678             :     /*      Set on the file.                                                */
     679             :     /* -------------------------------------------------------------------- */
     680           4 :     CSLDestroy(papszLastMDListValue);
     681           4 :     papszLastMDListValue = nullptr;
     682           4 :     m_oCacheMetadataItem.clear();
     683             : 
     684           4 :     if (GetAccess() == GA_ReadOnly)
     685             :     {
     686           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
     687             :                  "Unable to set metadata on read-only file.");
     688           0 :         return CE_Failure;
     689             :     }
     690             : 
     691             :     try
     692             :     {
     693           4 :         if (!pszValue)
     694           0 :             pszValue = "";
     695           4 :         poChannel->SetMetadataValue(pszName, pszValue);
     696             :     }
     697           0 :     catch (const PCIDSKException &ex)
     698             :     {
     699           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     700           0 :         return CE_Failure;
     701             :     }
     702             : 
     703           4 :     return CE_None;
     704             : }
     705             : 
     706             : /************************************************************************/
     707             : /*                      GetMetadataDomainList()                         */
     708             : /************************************************************************/
     709             : 
     710           0 : char **PCIDSK2Band::GetMetadataDomainList()
     711             : {
     712           0 :     return BuildMetadataDomainList(GDALPamRasterBand::GetMetadataDomainList(),
     713           0 :                                    TRUE, "", nullptr);
     714             : }
     715             : 
     716             : /************************************************************************/
     717             : /*                          GetMetadataItem()                           */
     718             : /************************************************************************/
     719             : 
     720          33 : const char *PCIDSK2Band::GetMetadataItem(const char *pszName,
     721             :                                          const char *pszDomain)
     722             : 
     723             : {
     724             :     /* -------------------------------------------------------------------- */
     725             :     /*      PCIDSK only supports metadata in the default domain.            */
     726             :     /* -------------------------------------------------------------------- */
     727          33 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
     728          22 :         return GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
     729             : 
     730             :     /* -------------------------------------------------------------------- */
     731             :     /*      Try and fetch (use cached value if available)                   */
     732             :     /* -------------------------------------------------------------------- */
     733          11 :     auto oIter = m_oCacheMetadataItem.find(pszName);
     734          11 :     if (oIter != m_oCacheMetadataItem.end())
     735             :     {
     736           5 :         return oIter->second.empty() ? nullptr : oIter->second.c_str();
     737             :     }
     738             : 
     739          12 :     CPLString osValue;
     740             :     try
     741             :     {
     742           6 :         osValue = poChannel->GetMetadataValue(pszName);
     743             :     }
     744           0 :     catch (const PCIDSKException &ex)
     745             :     {
     746           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     747           0 :         return nullptr;
     748             :     }
     749             : 
     750           6 :     oIter = m_oCacheMetadataItem
     751           6 :                 .insert(std::pair<std::string, std::string>(pszName, osValue))
     752             :                 .first;
     753           6 :     return oIter->second.empty() ? nullptr : oIter->second.c_str();
     754             : }
     755             : 
     756             : /************************************************************************/
     757             : /*                            GetMetadata()                             */
     758             : /************************************************************************/
     759             : 
     760           6 : char **PCIDSK2Band::GetMetadata(const char *pszDomain)
     761             : 
     762             : {
     763             :     /* -------------------------------------------------------------------- */
     764             :     /*      PCIDSK only supports metadata in the default domain.            */
     765             :     /* -------------------------------------------------------------------- */
     766           6 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
     767           1 :         return GDALPamRasterBand::GetMetadata(pszDomain);
     768             : 
     769             :     /* -------------------------------------------------------------------- */
     770             :     /*      If we have a cached result, just use that.                      */
     771             :     /* -------------------------------------------------------------------- */
     772           5 :     if (papszLastMDListValue != nullptr)
     773           0 :         return papszLastMDListValue;
     774             : 
     775             :     /* -------------------------------------------------------------------- */
     776             :     /*      Fetch and build the list.                                       */
     777             :     /* -------------------------------------------------------------------- */
     778             :     try
     779             :     {
     780          10 :         std::vector<std::string> aosKeys = poChannel->GetMetadataKeys();
     781             : 
     782          11 :         for (unsigned int i = 0; i < aosKeys.size(); i++)
     783             :         {
     784           6 :             if (aosKeys[i].c_str()[0] == '_')
     785           3 :                 continue;
     786             : 
     787           6 :             papszLastMDListValue = CSLSetNameValue(
     788           3 :                 papszLastMDListValue, aosKeys[i].c_str(),
     789           6 :                 poChannel->GetMetadataValue(aosKeys[i]).c_str());
     790             :         }
     791             :     }
     792           0 :     catch (const PCIDSKException &ex)
     793             :     {
     794           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     795           0 :         return nullptr;
     796             :     }
     797             : 
     798           5 :     return papszLastMDListValue;
     799             : }
     800             : 
     801             : /************************************************************************/
     802             : /* ==================================================================== */
     803             : /*                            PCIDSK2Dataset                            */
     804             : /* ==================================================================== */
     805             : /************************************************************************/
     806             : 
     807             : /************************************************************************/
     808             : /*                           PCIDSK2Dataset()                            */
     809             : /************************************************************************/
     810             : 
     811         243 : PCIDSK2Dataset::PCIDSK2Dataset()
     812         243 :     : papszLastMDListValue(nullptr), poFile(nullptr)
     813             : {
     814         243 : }
     815             : 
     816             : /************************************************************************/
     817             : /*                            ~PCIDSK2Dataset()                          */
     818             : /************************************************************************/
     819             : 
     820             : // FIXME? is an exception can really be thrown in the destructor, then it is
     821             : // very dangerous !
     822             : #ifdef _MSC_VER
     823             : #pragma warning(push)
     824             : #pragma warning(disable : 4702) /*  unreachable code */
     825             : #endif
     826         486 : PCIDSK2Dataset::~PCIDSK2Dataset()
     827             : {
     828         243 :     PCIDSK2Dataset::FlushCache(true);
     829             : 
     830        1426 :     while (!apoLayers.empty())
     831             :     {
     832        1183 :         delete apoLayers.back();
     833        1183 :         apoLayers.pop_back();
     834             :     }
     835             : 
     836         243 :     if (m_poSRS)
     837           7 :         m_poSRS->Release();
     838             : 
     839             :     try
     840             :     {
     841         243 :         if (poFile != nullptr)
     842         243 :             delete poFile;
     843             :     }
     844             : 
     845             :     /* -------------------------------------------------------------------- */
     846             :     /*      Trap exceptions.                                                */
     847             :     /* -------------------------------------------------------------------- */
     848             :     catch (const PCIDSKException &ex)
     849             :     {
     850             :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     851             :     }
     852             :     catch (...)
     853             :     {
     854             :         CPLError(CE_Failure, CPLE_AppDefined,
     855             :                  "PCIDSK SDK Failure in Close(), unexpected exception.");
     856             :     }
     857             : 
     858         243 :     CSLDestroy(papszLastMDListValue);
     859         486 : }
     860             : #ifdef _MSC_VER
     861             : #pragma warning(pop)
     862             : #endif
     863             : 
     864             : /************************************************************************/
     865             : /*                            GetFileList()                             */
     866             : /************************************************************************/
     867             : 
     868          57 : char **PCIDSK2Dataset::GetFileList()
     869             : 
     870             : {
     871          57 :     char **papszFileList = GDALPamDataset::GetFileList();
     872         114 :     CPLString osBaseDir = CPLGetPath(GetDescription());
     873             : 
     874             :     try
     875             :     {
     876          77 :         for (int nChan = 1; nChan <= poFile->GetChannels(); nChan++)
     877             :         {
     878          20 :             PCIDSKChannel *poChannel = poFile->GetChannel(nChan);
     879          40 :             CPLString osChanFilename;
     880             :             uint64 image_offset, pixel_offset, line_offset;
     881             :             bool little_endian;
     882             : 
     883          20 :             poChannel->GetChanInfo(osChanFilename, image_offset, pixel_offset,
     884          20 :                                    line_offset, little_endian);
     885             : 
     886          20 :             if (osChanFilename != "")
     887             :             {
     888           1 :                 papszFileList = CSLAddString(
     889             :                     papszFileList,
     890             :                     CPLProjectRelativeFilename(osBaseDir, osChanFilename));
     891             :             }
     892             :         }
     893             : 
     894          57 :         return papszFileList;
     895             :     }
     896           0 :     catch (const PCIDSKException &ex)
     897             :     {
     898           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     899           0 :         return papszFileList;
     900             :     }
     901             : }
     902             : 
     903             : /************************************************************************/
     904             : /*                             ProcessRPC()                             */
     905             : /************************************************************************/
     906             : 
     907         243 : void PCIDSK2Dataset::ProcessRPC()
     908             : 
     909             : {
     910             :     /* -------------------------------------------------------------------- */
     911             :     /*      Search all BIN segments looking for an RPC segment.             */
     912             :     /* -------------------------------------------------------------------- */
     913         243 :     PCIDSKSegment *poSeg = poFile->GetSegment(SEG_BIN, "");
     914         243 :     PCIDSKRPCSegment *poRPCSeg = nullptr;
     915             : 
     916         243 :     while (poSeg != nullptr &&
     917           0 :            (poRPCSeg = dynamic_cast<PCIDSKRPCSegment *>(poSeg)) == nullptr)
     918             : 
     919             :     {
     920           0 :         poSeg = poFile->GetSegment(SEG_BIN, "", poSeg->GetSegmentNumber());
     921             :     }
     922             : 
     923         243 :     if (poRPCSeg == nullptr)
     924         243 :         return;
     925             : 
     926             :     /* -------------------------------------------------------------------- */
     927             :     /*      Turn RPC segment into GDAL RFC 22 style metadata.               */
     928             :     /* -------------------------------------------------------------------- */
     929             :     try
     930             :     {
     931           0 :         CPLString osValue;
     932             :         double dfLineOffset, dfLineScale, dfSampOffset, dfSampScale;
     933             :         double dfLatOffset, dfLatScale, dfLongOffset, dfLongScale,
     934             :             dfHeightOffset, dfHeightScale;
     935             : 
     936           0 :         poRPCSeg->GetRPCTranslationCoeffs(
     937             :             dfLongOffset, dfLongScale, dfLatOffset, dfLatScale, dfHeightOffset,
     938             :             dfHeightScale, dfSampOffset, dfSampScale, dfLineOffset,
     939           0 :             dfLineScale);
     940             : 
     941           0 :         osValue.Printf("%.16g", dfLineOffset);
     942           0 :         GDALPamDataset::SetMetadataItem("LINE_OFF", osValue, "RPC");
     943             : 
     944           0 :         osValue.Printf("%.16g", dfLineScale);
     945           0 :         GDALPamDataset::SetMetadataItem("LINE_SCALE", osValue, "RPC");
     946             : 
     947           0 :         osValue.Printf("%.16g", dfSampOffset);
     948           0 :         GDALPamDataset::SetMetadataItem("SAMP_OFF", osValue, "RPC");
     949             : 
     950           0 :         osValue.Printf("%.16g", dfSampScale);
     951           0 :         GDALPamDataset::SetMetadataItem("SAMP_SCALE", osValue, "RPC");
     952             : 
     953           0 :         osValue.Printf("%.16g", dfLongOffset);
     954           0 :         GDALPamDataset::SetMetadataItem("LONG_OFF", osValue, "RPC");
     955             : 
     956           0 :         osValue.Printf("%.16g", dfLongScale);
     957           0 :         GDALPamDataset::SetMetadataItem("LONG_SCALE", osValue, "RPC");
     958             : 
     959           0 :         osValue.Printf("%.16g", dfLatOffset);
     960           0 :         GDALPamDataset::SetMetadataItem("LAT_OFF", osValue, "RPC");
     961             : 
     962           0 :         osValue.Printf("%.16g", dfLatScale);
     963           0 :         GDALPamDataset::SetMetadataItem("LAT_SCALE", osValue, "RPC");
     964             : 
     965           0 :         osValue.Printf("%.16g", dfHeightOffset);
     966           0 :         GDALPamDataset::SetMetadataItem("HEIGHT_OFF", osValue, "RPC");
     967             : 
     968           0 :         osValue.Printf("%.16g", dfHeightScale);
     969           0 :         GDALPamDataset::SetMetadataItem("HEIGHT_SCALE", osValue, "RPC");
     970             : 
     971           0 :         if (poRPCSeg->GetXNumerator().size() != 20 ||
     972           0 :             poRPCSeg->GetXDenominator().size() != 20 ||
     973           0 :             poRPCSeg->GetYNumerator().size() != 20 ||
     974           0 :             poRPCSeg->GetYDenominator().size() != 20)
     975             :         {
     976           0 :             GDALPamDataset::SetMetadata(nullptr, "RPC");
     977           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     978             :                      "Did not get 20 values in the RPC coefficients lists.");
     979           0 :             return;
     980             :         }
     981             : 
     982           0 :         std::vector<double> adfCoef = poRPCSeg->GetYNumerator();
     983           0 :         CPLString osCoefList = "";
     984           0 :         for (int i = 0; i < 20; i++)
     985             :         {
     986           0 :             osValue.Printf("%.16g ", adfCoef[i]);
     987           0 :             osCoefList += osValue;
     988             :         }
     989           0 :         GDALPamDataset::SetMetadataItem("LINE_NUM_COEFF", osCoefList, "RPC");
     990             : 
     991           0 :         adfCoef = poRPCSeg->GetYDenominator();
     992           0 :         osCoefList = "";
     993           0 :         for (int i = 0; i < 20; i++)
     994             :         {
     995           0 :             osValue.Printf("%.16g ", adfCoef[i]);
     996           0 :             osCoefList += osValue;
     997             :         }
     998           0 :         GDALPamDataset::SetMetadataItem("LINE_DEN_COEFF", osCoefList, "RPC");
     999             : 
    1000           0 :         adfCoef = poRPCSeg->GetXNumerator();
    1001           0 :         osCoefList = "";
    1002           0 :         for (int i = 0; i < 20; i++)
    1003             :         {
    1004           0 :             osValue.Printf("%.16g ", adfCoef[i]);
    1005           0 :             osCoefList += osValue;
    1006             :         }
    1007           0 :         GDALPamDataset::SetMetadataItem("SAMP_NUM_COEFF", osCoefList, "RPC");
    1008             : 
    1009           0 :         adfCoef = poRPCSeg->GetXDenominator();
    1010           0 :         osCoefList = "";
    1011           0 :         for (int i = 0; i < 20; i++)
    1012             :         {
    1013           0 :             osValue.Printf("%.16g ", adfCoef[i]);
    1014           0 :             osCoefList += osValue;
    1015             :         }
    1016           0 :         GDALPamDataset::SetMetadataItem("SAMP_DEN_COEFF", osCoefList, "RPC");
    1017             :     }
    1018           0 :     catch (const PCIDSKException &ex)
    1019             :     {
    1020           0 :         GDALPamDataset::SetMetadata(nullptr, "RPC");
    1021           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1022             :     }
    1023             : }
    1024             : 
    1025             : /************************************************************************/
    1026             : /*                             FlushCache()                             */
    1027             : /************************************************************************/
    1028             : 
    1029         254 : CPLErr PCIDSK2Dataset::FlushCache(bool bAtClosing)
    1030             : 
    1031             : {
    1032         254 :     CPLErr eErr = GDALPamDataset::FlushCache(bAtClosing);
    1033             : 
    1034         254 :     if (poFile)
    1035             :     {
    1036             :         try
    1037             :         {
    1038         254 :             poFile->Synchronize();
    1039             :         }
    1040           0 :         catch (const PCIDSKException &ex)
    1041             :         {
    1042           0 :             eErr = CE_Failure;
    1043           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1044             :         }
    1045             :     }
    1046         254 :     return eErr;
    1047             : }
    1048             : 
    1049             : /************************************************************************/
    1050             : /*                            SetMetadata()                             */
    1051             : /************************************************************************/
    1052             : 
    1053          25 : CPLErr PCIDSK2Dataset::SetMetadata(char **papszMD, const char *pszDomain)
    1054             : 
    1055             : {
    1056             :     /* -------------------------------------------------------------------- */
    1057             :     /*      PCIDSK only supports metadata in the default domain.            */
    1058             :     /* -------------------------------------------------------------------- */
    1059          25 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
    1060           0 :         return GDALPamDataset::SetMetadata(papszMD, pszDomain);
    1061             : 
    1062             :     /* -------------------------------------------------------------------- */
    1063             :     /*      Set each item individually.                                     */
    1064             :     /* -------------------------------------------------------------------- */
    1065          25 :     CSLDestroy(papszLastMDListValue);
    1066          25 :     papszLastMDListValue = nullptr;
    1067          25 :     m_oCacheMetadataItem.clear();
    1068             : 
    1069          25 :     if (GetAccess() == GA_ReadOnly)
    1070             :     {
    1071           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    1072             :                  "Unable to set metadata on read-only file.");
    1073           0 :         return CE_Failure;
    1074             :     }
    1075             : 
    1076             :     try
    1077             :     {
    1078          57 :         for (int iItem = 0; papszMD && papszMD[iItem]; iItem++)
    1079             :         {
    1080          32 :             char *pszItemName = nullptr;
    1081             :             const char *pszItemValue =
    1082          32 :                 CPLParseNameValue(papszMD[iItem], &pszItemName);
    1083          32 :             if (pszItemName != nullptr)
    1084             :             {
    1085          16 :                 poFile->SetMetadataValue(pszItemName, pszItemValue);
    1086          16 :                 CPLFree(pszItemName);
    1087             :             }
    1088             :         }
    1089             :     }
    1090           0 :     catch (const PCIDSKException &ex)
    1091             :     {
    1092           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1093           0 :         return CE_Failure;
    1094             :     }
    1095             : 
    1096          25 :     return CE_None;
    1097             : }
    1098             : 
    1099             : /************************************************************************/
    1100             : /*                          SetMetadataItem()                           */
    1101             : /************************************************************************/
    1102             : 
    1103         220 : CPLErr PCIDSK2Dataset::SetMetadataItem(const char *pszName,
    1104             :                                        const char *pszValue,
    1105             :                                        const char *pszDomain)
    1106             : 
    1107             : {
    1108             :     /* -------------------------------------------------------------------- */
    1109             :     /*      PCIDSK only supports metadata in the default domain.            */
    1110             :     /* -------------------------------------------------------------------- */
    1111         220 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
    1112         216 :         return GDALPamDataset::SetMetadataItem(pszName, pszValue, pszDomain);
    1113             : 
    1114             :     /* -------------------------------------------------------------------- */
    1115             :     /*      Set on the file.                                                */
    1116             :     /* -------------------------------------------------------------------- */
    1117           4 :     CSLDestroy(papszLastMDListValue);
    1118           4 :     papszLastMDListValue = nullptr;
    1119           4 :     m_oCacheMetadataItem.clear();
    1120             : 
    1121           4 :     if (GetAccess() == GA_ReadOnly)
    1122             :     {
    1123           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    1124             :                  "Unable to set metadata on read-only file.");
    1125           0 :         return CE_Failure;
    1126             :     }
    1127             : 
    1128             :     try
    1129             :     {
    1130           4 :         poFile->SetMetadataValue(pszName, pszValue);
    1131             :     }
    1132           0 :     catch (const PCIDSKException &ex)
    1133             :     {
    1134           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1135           0 :         return CE_Failure;
    1136             :     }
    1137             : 
    1138           4 :     return CE_None;
    1139             : }
    1140             : 
    1141             : /************************************************************************/
    1142             : /*                      GetMetadataDomainList()                         */
    1143             : /************************************************************************/
    1144             : 
    1145           0 : char **PCIDSK2Dataset::GetMetadataDomainList()
    1146             : {
    1147           0 :     return BuildMetadataDomainList(GDALPamDataset::GetMetadataDomainList(),
    1148           0 :                                    TRUE, "", nullptr);
    1149             : }
    1150             : 
    1151             : /************************************************************************/
    1152             : /*                          GetMetadataItem()                           */
    1153             : /************************************************************************/
    1154             : 
    1155        1239 : const char *PCIDSK2Dataset::GetMetadataItem(const char *pszName,
    1156             :                                             const char *pszDomain)
    1157             : 
    1158             : {
    1159             :     /* -------------------------------------------------------------------- */
    1160             :     /*      PCIDSK only supports metadata in the default domain.            */
    1161             :     /* -------------------------------------------------------------------- */
    1162        1239 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
    1163          96 :         return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
    1164             : 
    1165             :     /* -------------------------------------------------------------------- */
    1166             :     /*      Try and fetch (use cached value if available)                   */
    1167             :     /* -------------------------------------------------------------------- */
    1168        1143 :     auto oIter = m_oCacheMetadataItem.find(pszName);
    1169        1143 :     if (oIter != m_oCacheMetadataItem.end())
    1170             :     {
    1171        1054 :         return oIter->second.empty() ? nullptr : oIter->second.c_str();
    1172             :     }
    1173             : 
    1174         178 :     CPLString osValue;
    1175             :     try
    1176             :     {
    1177          89 :         osValue = poFile->GetMetadataValue(pszName);
    1178             :     }
    1179           0 :     catch (const PCIDSKException &ex)
    1180             :     {
    1181           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1182           0 :         return nullptr;
    1183             :     }
    1184             : 
    1185          89 :     oIter = m_oCacheMetadataItem
    1186          89 :                 .insert(std::pair<std::string, std::string>(pszName, osValue))
    1187             :                 .first;
    1188          89 :     return oIter->second.empty() ? nullptr : oIter->second.c_str();
    1189             : }
    1190             : 
    1191             : /************************************************************************/
    1192             : /*                            GetMetadata()                             */
    1193             : /************************************************************************/
    1194             : 
    1195          52 : char **PCIDSK2Dataset::GetMetadata(const char *pszDomain)
    1196             : 
    1197             : {
    1198             :     /* -------------------------------------------------------------------- */
    1199             :     /*      PCIDSK only supports metadata in the default domain.            */
    1200             :     /* -------------------------------------------------------------------- */
    1201          52 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
    1202          25 :         return GDALPamDataset::GetMetadata(pszDomain);
    1203             : 
    1204             :     /* -------------------------------------------------------------------- */
    1205             :     /*      If we have a cached result, just use that.                      */
    1206             :     /* -------------------------------------------------------------------- */
    1207          27 :     if (papszLastMDListValue != nullptr)
    1208           3 :         return papszLastMDListValue;
    1209             : 
    1210             :     /* -------------------------------------------------------------------- */
    1211             :     /*      Fetch and build the list.                                       */
    1212             :     /* -------------------------------------------------------------------- */
    1213             :     try
    1214             :     {
    1215          48 :         std::vector<std::string> aosKeys = poFile->GetMetadataKeys();
    1216             : 
    1217          38 :         for (unsigned int i = 0; i < aosKeys.size(); i++)
    1218             :         {
    1219          14 :             if (aosKeys[i].c_str()[0] == '_')
    1220           2 :                 continue;
    1221             : 
    1222          12 :             papszLastMDListValue =
    1223          12 :                 CSLSetNameValue(papszLastMDListValue, aosKeys[i].c_str(),
    1224          24 :                                 poFile->GetMetadataValue(aosKeys[i]).c_str());
    1225             :         }
    1226             :     }
    1227           0 :     catch (const PCIDSKException &ex)
    1228             :     {
    1229           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1230           0 :         return nullptr;
    1231             :     }
    1232             : 
    1233          24 :     return papszLastMDListValue;
    1234             : }
    1235             : 
    1236             : /************************************************************************/
    1237             : /*                          SetGeoTransform()                           */
    1238             : /************************************************************************/
    1239             : 
    1240          56 : CPLErr PCIDSK2Dataset::SetGeoTransform(double *padfTransform)
    1241             : {
    1242          56 :     PCIDSKGeoref *poGeoref = nullptr;
    1243             :     try
    1244             :     {
    1245          56 :         PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
    1246          56 :         poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
    1247             :     }
    1248           0 :     catch (const PCIDSKException &)
    1249             :     {
    1250             :         // I should really check whether this is an expected issue.
    1251             :     }
    1252             : 
    1253          56 :     if (poGeoref == nullptr)
    1254           0 :         return GDALPamDataset::SetGeoTransform(padfTransform);
    1255             : 
    1256          56 :     if (GetAccess() == GA_ReadOnly)
    1257             :     {
    1258           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    1259             :                  "Unable to set GeoTransform on read-only file.");
    1260           0 :         return CE_Failure;
    1261             :     }
    1262             : 
    1263             :     try
    1264             :     {
    1265          56 :         poGeoref->WriteSimple(poGeoref->GetGeosys(), padfTransform[0],
    1266          56 :                               padfTransform[1], padfTransform[2],
    1267          56 :                               padfTransform[3], padfTransform[4],
    1268          56 :                               padfTransform[5]);
    1269             :     }
    1270           0 :     catch (const PCIDSKException &ex)
    1271             :     {
    1272           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1273           0 :         return CE_Failure;
    1274             :     }
    1275             : 
    1276          56 :     return CE_None;
    1277             : }
    1278             : 
    1279             : /************************************************************************/
    1280             : /*                          GetGeoTransform()                           */
    1281             : /************************************************************************/
    1282             : 
    1283          44 : CPLErr PCIDSK2Dataset::GetGeoTransform(double *padfTransform)
    1284             : {
    1285          44 :     PCIDSKGeoref *poGeoref = nullptr;
    1286             :     try
    1287             :     {
    1288          44 :         PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
    1289          44 :         poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
    1290             :     }
    1291           0 :     catch (const PCIDSKException &)
    1292             :     {
    1293             :         // I should really check whether this is an expected issue.
    1294             :     }
    1295             : 
    1296          44 :     if (poGeoref != nullptr)
    1297             :     {
    1298             :         try
    1299             :         {
    1300          44 :             poGeoref->GetTransform(padfTransform[0], padfTransform[1],
    1301          44 :                                    padfTransform[2], padfTransform[3],
    1302          44 :                                    padfTransform[4], padfTransform[5]);
    1303             :         }
    1304           0 :         catch (const PCIDSKException &ex)
    1305             :         {
    1306           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1307           0 :             return CE_Failure;
    1308             :         }
    1309             : 
    1310             :         // If we got anything non-default return it.
    1311          44 :         if (padfTransform[0] != 0.0 || padfTransform[1] != 1.0 ||
    1312           3 :             padfTransform[2] != 0.0 || padfTransform[3] != 0.0 ||
    1313           3 :             padfTransform[4] != 0.0 || padfTransform[5] != 1.0)
    1314          41 :             return CE_None;
    1315             :     }
    1316             : 
    1317             :     /* -------------------------------------------------------------------- */
    1318             :     /*      Check for worldfile if we have no other georeferencing.         */
    1319             :     /* -------------------------------------------------------------------- */
    1320           3 :     if (GDALReadWorldFile(GetDescription(), "pxw", padfTransform))
    1321           0 :         return CE_None;
    1322             : 
    1323           3 :     return GDALPamDataset::GetGeoTransform(padfTransform);
    1324             : }
    1325             : 
    1326             : /************************************************************************/
    1327             : /*                           SetSpatialRef()                            */
    1328             : /************************************************************************/
    1329             : 
    1330          56 : CPLErr PCIDSK2Dataset::SetSpatialRef(const OGRSpatialReference *poSRS)
    1331             : 
    1332             : {
    1333          56 :     PCIDSKGeoref *poGeoref = nullptr;
    1334             : 
    1335             :     try
    1336             :     {
    1337          56 :         PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
    1338          56 :         poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
    1339             :     }
    1340           0 :     catch (const PCIDSKException &)
    1341             :     {
    1342             :         // I should really check whether this is an expected issue.
    1343             :     }
    1344             : 
    1345          56 :     if (poGeoref == nullptr)
    1346             :     {
    1347           0 :         return GDALPamDataset::SetSpatialRef(poSRS);
    1348             :     }
    1349             : 
    1350          56 :     char *pszGeosys = nullptr;
    1351          56 :     char *pszUnits = nullptr;
    1352          56 :     double *padfPrjParams = nullptr;
    1353             : 
    1354          56 :     if (poSRS == nullptr || poSRS->exportToPCI(&pszGeosys, &pszUnits,
    1355             :                                                &padfPrjParams) != OGRERR_NONE)
    1356             :     {
    1357           0 :         return GDALPamDataset::SetSpatialRef(poSRS);
    1358             :     }
    1359             : 
    1360          56 :     if (GetAccess() == GA_ReadOnly)
    1361             :     {
    1362           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    1363             :                  "Unable to set projection on read-only file.");
    1364           0 :         CPLFree(pszGeosys);
    1365           0 :         CPLFree(pszUnits);
    1366           0 :         CPLFree(padfPrjParams);
    1367           0 :         return CE_Failure;
    1368             :     }
    1369             : 
    1370             :     try
    1371             :     {
    1372             :         double adfGT[6];
    1373          56 :         poGeoref->GetTransform(adfGT[0], adfGT[1], adfGT[2], adfGT[3], adfGT[4],
    1374          56 :                                adfGT[5]);
    1375             : 
    1376          56 :         poGeoref->WriteSimple(pszGeosys, adfGT[0], adfGT[1], adfGT[2], adfGT[3],
    1377          56 :                               adfGT[4], adfGT[5]);
    1378             : 
    1379         112 :         std::vector<double> adfPCIParameters;
    1380        1008 :         for (unsigned int i = 0; i < 17; i++)
    1381         952 :             adfPCIParameters.push_back(padfPrjParams[i]);
    1382             : 
    1383          56 :         if (STARTS_WITH_CI(pszUnits, "FOOT"))
    1384           0 :             adfPCIParameters.push_back(
    1385           0 :                 static_cast<double>(static_cast<int>(PCIDSK::UNIT_US_FOOT)));
    1386          56 :         else if (EQUALN(pszUnits, "INTL FOOT", 9))
    1387           0 :             adfPCIParameters.push_back(
    1388           0 :                 static_cast<double>(static_cast<int>(PCIDSK::UNIT_INTL_FOOT)));
    1389          56 :         else if (EQUALN(pszUnits, "DEGREE", 6))
    1390          48 :             adfPCIParameters.push_back(
    1391          48 :                 static_cast<double>(static_cast<int>(PCIDSK::UNIT_DEGREE)));
    1392             :         else
    1393           8 :             adfPCIParameters.push_back(
    1394           8 :                 static_cast<double>(static_cast<int>(PCIDSK::UNIT_METER)));
    1395             : 
    1396          56 :         poGeoref->WriteParameters(adfPCIParameters);
    1397             :     }
    1398           0 :     catch (const PCIDSKException &ex)
    1399             :     {
    1400           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1401           0 :         return CE_Failure;
    1402             :     }
    1403             : 
    1404          56 :     CPLFree(pszGeosys);
    1405          56 :     CPLFree(pszUnits);
    1406          56 :     CPLFree(padfPrjParams);
    1407             : 
    1408          56 :     return CE_None;
    1409             : }
    1410             : 
    1411             : /************************************************************************/
    1412             : /*                          GetSpatialRef()                             */
    1413             : /************************************************************************/
    1414             : 
    1415          13 : const OGRSpatialReference *PCIDSK2Dataset::GetSpatialRef() const
    1416             : {
    1417          13 :     if (m_poSRS)
    1418           3 :         return m_poSRS;
    1419             : 
    1420          10 :     PCIDSKGeoref *poGeoref = nullptr;
    1421             : 
    1422             :     try
    1423             :     {
    1424          10 :         PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
    1425          10 :         poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
    1426             :     }
    1427           0 :     catch (const PCIDSKException &)
    1428             :     {
    1429             :         // I should really check whether this is an expected issue.
    1430             :     }
    1431             : 
    1432          10 :     if (poGeoref == nullptr)
    1433             :     {
    1434           0 :         return GDALPamDataset::GetSpatialRef();
    1435             :     }
    1436             : 
    1437          20 :     CPLString osGeosys;
    1438          10 :     const char *pszUnits = nullptr;
    1439             : 
    1440          20 :     std::vector<double> adfParameters;
    1441          10 :     adfParameters.resize(18);
    1442             : 
    1443             :     try
    1444             :     {
    1445          10 :         osGeosys = poGeoref->GetGeosys();
    1446          10 :         adfParameters = poGeoref->GetParameters();
    1447             :         const UnitCode code =
    1448          10 :             static_cast<UnitCode>(static_cast<int>(adfParameters[16]));
    1449             : 
    1450          10 :         if (code == PCIDSK::UNIT_DEGREE)
    1451           0 :             pszUnits = "DEGREE";
    1452          10 :         else if (code == PCIDSK::UNIT_METER)
    1453           0 :             pszUnits = "METER";
    1454          10 :         else if (code == PCIDSK::UNIT_US_FOOT)
    1455           0 :             pszUnits = "FOOT";
    1456          10 :         else if (code == PCIDSK::UNIT_INTL_FOOT)
    1457           0 :             pszUnits = "INTL FOOT";
    1458             :     }
    1459           0 :     catch (const PCIDSKException &ex)
    1460             :     {
    1461           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1462             :     }
    1463             : 
    1464          20 :     OGRSpatialReference oSRS;
    1465          10 :     oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    1466          10 :     if (oSRS.importFromPCI(osGeosys, pszUnits, &(adfParameters[0])) ==
    1467             :         OGRERR_NONE)
    1468             :     {
    1469           7 :         m_poSRS = oSRS.Clone();
    1470           7 :         return m_poSRS;
    1471             :     }
    1472             :     else
    1473             :     {
    1474           3 :         return GDALPamDataset::GetSpatialRef();
    1475             :     }
    1476             : }
    1477             : 
    1478             : /************************************************************************/
    1479             : /*                          IBuildOverviews()                           */
    1480             : /************************************************************************/
    1481             : 
    1482           3 : CPLErr PCIDSK2Dataset::IBuildOverviews(
    1483             :     const char *pszResampling, int nOverviews, const int *panOverviewList,
    1484             :     int nListBands, const int *panBandList, GDALProgressFunc pfnProgress,
    1485             :     void *pProgressData, CSLConstList papszOptions)
    1486             : 
    1487             : {
    1488             :     PCIDSK2Band *poBand =
    1489           3 :         reinterpret_cast<PCIDSK2Band *>(GetRasterBand(panBandList[0]));
    1490             : 
    1491             :     /* -------------------------------------------------------------------- */
    1492             :     /*      If RRD overviews requested, then invoke generic handling.       */
    1493             :     /* -------------------------------------------------------------------- */
    1494           3 :     bool bUseGenericHandling = false;
    1495             : 
    1496           3 :     if (CPLTestBool(CPLGetConfigOption("USE_RRD", "NO")))
    1497             :     {
    1498           1 :         bUseGenericHandling = true;
    1499             :     }
    1500             : 
    1501             :     /* -------------------------------------------------------------------- */
    1502             :     /*      If we don't have read access, then create the overviews         */
    1503             :     /*      externally.                                                     */
    1504             :     /* -------------------------------------------------------------------- */
    1505           3 :     if (GetAccess() != GA_Update)
    1506             :     {
    1507           1 :         CPLDebug("PCIDSK", "File open for read-only accessing, "
    1508             :                            "creating overviews externally.");
    1509             : 
    1510           1 :         bUseGenericHandling = true;
    1511             :     }
    1512             : 
    1513           3 :     if (bUseGenericHandling)
    1514             :     {
    1515           2 :         if (poBand->GetOverviewCount() != 0)
    1516             :         {
    1517           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    1518             :                      "Cannot add external overviews when there are already "
    1519             :                      "internal overviews");
    1520           0 :             return CE_Failure;
    1521             :         }
    1522             : 
    1523           2 :         return GDALDataset::IBuildOverviews(
    1524             :             pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
    1525           2 :             pfnProgress, pProgressData, papszOptions);
    1526             :     }
    1527             : 
    1528           1 :     if (nListBands == 0)
    1529           0 :         return CE_None;
    1530             : 
    1531             :     /* -------------------------------------------------------------------- */
    1532             :     /*      Currently no support for clearing overviews.                    */
    1533             :     /* -------------------------------------------------------------------- */
    1534           1 :     if (nOverviews == 0)
    1535             :     {
    1536           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1537             :                  "PCIDSK2 driver does not currently support clearing existing "
    1538             :                  "overviews. ");
    1539           0 :         return CE_Failure;
    1540             :     }
    1541             : 
    1542             :     /* -------------------------------------------------------------------- */
    1543             :     /*      Establish which of the overview levels we already have, and     */
    1544             :     /*      which are new.  We assume that band 1 of the file is            */
    1545             :     /*      representative.                                                 */
    1546             :     /* -------------------------------------------------------------------- */
    1547             : 
    1548           1 :     int nNewOverviews = 0;
    1549             :     int *panNewOverviewList =
    1550           1 :         reinterpret_cast<int *>(CPLCalloc(sizeof(int), nOverviews));
    1551           2 :     std::vector<bool> abFoundOverviewFactor(nOverviews);
    1552           2 :     for (int i = 0; i < nOverviews && poBand != nullptr; i++)
    1553             :     {
    1554           1 :         for (int j = 0; j < poBand->GetOverviewCount(); j++)
    1555             :         {
    1556           0 :             GDALRasterBand *poOverview = poBand->GetOverview(j);
    1557             : 
    1558             :             int nOvFactor =
    1559           0 :                 GDALComputeOvFactor(poOverview->GetXSize(), poBand->GetXSize(),
    1560             :                                     poOverview->GetYSize(), poBand->GetYSize());
    1561             : 
    1562           0 :             if (nOvFactor == panOverviewList[i] ||
    1563           0 :                 nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
    1564             :                                                 poBand->GetXSize(),
    1565             :                                                 poBand->GetYSize()))
    1566           0 :                 abFoundOverviewFactor[i] = true;
    1567             :         }
    1568             : 
    1569           1 :         if (!abFoundOverviewFactor[i])
    1570           1 :             panNewOverviewList[nNewOverviews++] = panOverviewList[i];
    1571             :     }
    1572             : 
    1573             :     /* -------------------------------------------------------------------- */
    1574             :     /*      Create the overviews that are missing.                          */
    1575             :     /* -------------------------------------------------------------------- */
    1576           2 :     for (int i = 0; i < nNewOverviews; i++)
    1577             :     {
    1578             :         try
    1579             :         {
    1580             :             // conveniently our resampling values mostly match PCIDSK.
    1581           2 :             poFile->CreateOverviews(nListBands, panBandList,
    1582           2 :                                     panNewOverviewList[i], pszResampling);
    1583             :         }
    1584           0 :         catch (const PCIDSKException &ex)
    1585             :         {
    1586           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1587           0 :             CPLFree(panNewOverviewList);
    1588           0 :             return CE_Failure;
    1589             :         }
    1590             :     }
    1591             : 
    1592           1 :     CPLFree(panNewOverviewList);
    1593           1 :     panNewOverviewList = nullptr;
    1594             : 
    1595           2 :     for (int iBand = 0; iBand < nListBands; iBand++)
    1596             :     {
    1597             :         poBand =
    1598           1 :             reinterpret_cast<PCIDSK2Band *>(GetRasterBand(panBandList[iBand]));
    1599           1 :         reinterpret_cast<PCIDSK2Band *>(poBand)->RefreshOverviewList();
    1600             :     }
    1601             : 
    1602             :     /* -------------------------------------------------------------------- */
    1603             :     /*      Actually generate the overview imagery.                         */
    1604             :     /* -------------------------------------------------------------------- */
    1605           1 :     CPLErr eErr = CE_None;
    1606           1 :     std::vector<int> anRegenLevels;
    1607             : 
    1608             :     GDALRasterBand **papoOverviewBands = reinterpret_cast<GDALRasterBand **>(
    1609           1 :         CPLCalloc(sizeof(void *), nOverviews));
    1610             : 
    1611           2 :     for (int iBand = 0; iBand < nListBands && eErr == CE_None; iBand++)
    1612             :     {
    1613           1 :         nNewOverviews = 0;
    1614             : 
    1615             :         poBand =
    1616           1 :             reinterpret_cast<PCIDSK2Band *>(GetRasterBand(panBandList[iBand]));
    1617             : 
    1618           2 :         for (int i = 0; i < nOverviews && poBand != nullptr; i++)
    1619             :         {
    1620           1 :             for (int j = 0; j < poBand->GetOverviewCount(); j++)
    1621             :             {
    1622           1 :                 GDALRasterBand *poOverview = poBand->GetOverview(j);
    1623             : 
    1624           1 :                 int nOvFactor = GDALComputeOvFactor(
    1625             :                     poOverview->GetXSize(), poBand->GetXSize(),
    1626             :                     poOverview->GetYSize(), poBand->GetYSize());
    1627             : 
    1628           1 :                 if (nOvFactor == panOverviewList[i] ||
    1629           0 :                     nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
    1630             :                                                     poBand->GetXSize(),
    1631             :                                                     poBand->GetYSize()))
    1632             :                 {
    1633           1 :                     papoOverviewBands[nNewOverviews++] = poOverview;
    1634           1 :                     anRegenLevels.push_back(j);
    1635           1 :                     break;
    1636             :                 }
    1637             :             }
    1638             :         }
    1639             : 
    1640           1 :         if (nNewOverviews > 0)
    1641             :         {
    1642           1 :             eErr = GDALRegenerateOverviewsEx(
    1643             :                 (GDALRasterBandH)poBand, nNewOverviews,
    1644             :                 reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
    1645             :                 pszResampling, pfnProgress, pProgressData, papszOptions);
    1646             : 
    1647             :             // Mark the regenerated overviews as valid.
    1648           2 :             for (int i = 0; i < static_cast<int>(anRegenLevels.size()); i++)
    1649           1 :                 poBand->poChannel->SetOverviewValidity(anRegenLevels[i], true);
    1650             :         }
    1651             :     }
    1652             : 
    1653           1 :     CPLFree(papoOverviewBands);
    1654             : 
    1655           1 :     return eErr;
    1656             : }
    1657             : 
    1658             : /************************************************************************/
    1659             : /*                         PCIDSKTypeToGDAL()                           */
    1660             : /************************************************************************/
    1661             : 
    1662         473 : GDALDataType PCIDSK2Dataset::PCIDSKTypeToGDAL(eChanType eType)
    1663             : {
    1664         473 :     switch (eType)
    1665             :     {
    1666         335 :         case CHN_8U:
    1667         335 :             return GDT_Byte;
    1668             : 
    1669          66 :         case CHN_16U:
    1670          66 :             return GDT_UInt16;
    1671             : 
    1672          18 :         case CHN_16S:
    1673          18 :             return GDT_Int16;
    1674             : 
    1675          18 :         case CHN_32R:
    1676          18 :             return GDT_Float32;
    1677             : 
    1678           0 :         case CHN_BIT:
    1679           0 :             return GDT_Byte;
    1680             : 
    1681           0 :         case CHN_C16U:
    1682           0 :             return GDT_CInt16;
    1683             : 
    1684          18 :         case CHN_C16S:
    1685          18 :             return GDT_CInt16;
    1686             : 
    1687          18 :         case CHN_C32R:
    1688          18 :             return GDT_CFloat32;
    1689             : 
    1690           0 :         default:
    1691           0 :             return GDT_Unknown;
    1692             :     }
    1693             : }
    1694             : 
    1695             : /************************************************************************/
    1696             : /*                                Open()                                */
    1697             : /************************************************************************/
    1698             : 
    1699         137 : GDALDataset *PCIDSK2Dataset::Open(GDALOpenInfo *poOpenInfo)
    1700             : {
    1701         137 :     if (!PCIDSKDriverIdentify(poOpenInfo))
    1702           0 :         return nullptr;
    1703             : 
    1704             :     /* -------------------------------------------------------------------- */
    1705             :     /*      Try opening the file.                                           */
    1706             :     /* -------------------------------------------------------------------- */
    1707         137 :     PCIDSKFile *poFile = nullptr;
    1708             :     const int nMaxBandCount =
    1709         137 :         atoi(CPLGetConfigOption("GDAL_MAX_BAND_COUNT", "65536"));
    1710             :     try
    1711             :     {
    1712         278 :         poFile = PCIDSK::Open(poOpenInfo->pszFilename,
    1713         137 :                               poOpenInfo->eAccess == GA_ReadOnly ? "r" : "r+",
    1714             :                               PCIDSK2GetInterfaces(), nMaxBandCount);
    1715         136 :         if (poFile == nullptr)
    1716             :         {
    1717           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
    1718             :                      "Failed to re-open %s within PCIDSK driver.\n",
    1719             :                      poOpenInfo->pszFilename);
    1720           0 :             return nullptr;
    1721             :         }
    1722             : 
    1723             :         const bool bValidRasterDimensions =
    1724         136 :             poFile->GetWidth() && poFile->GetHeight();
    1725         136 :         if (!bValidRasterDimensions &&
    1726           0 :             (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
    1727           0 :             (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) == 0)
    1728             :         {
    1729           0 :             delete poFile;
    1730           0 :             return nullptr;
    1731             :         }
    1732             : 
    1733             :         /* Check if this is a vector-only PCIDSK file and that we are */
    1734             :         /* opened in raster-only mode */
    1735         402 :         if (poOpenInfo->eAccess == GA_ReadOnly &&
    1736         130 :             (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
    1737         120 :             (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) == 0 &&
    1738         269 :             poFile->GetChannels() == 0 &&
    1739         139 :             poFile->GetSegment(PCIDSK::SEG_VEC, "") != nullptr)
    1740             :         {
    1741           2 :             CPLDebug("PCIDSK",
    1742             :                      "This is a vector-only PCIDSK dataset, "
    1743             :                      "but it has been opened in read-only in raster-only mode");
    1744           2 :             delete poFile;
    1745           2 :             return nullptr;
    1746             :         }
    1747             :         /* Reverse test */
    1748         396 :         if (poOpenInfo->eAccess == GA_ReadOnly &&
    1749         128 :             (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
    1750          10 :             (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0 &&
    1751         262 :             poFile->GetChannels() != 0 &&
    1752         134 :             poFile->GetSegment(PCIDSK::SEG_VEC, "") == nullptr)
    1753             :         {
    1754           0 :             CPLDebug("PCIDSK",
    1755             :                      "This is a raster-only PCIDSK dataset, "
    1756             :                      "but it has been opened in read-only in vector-only mode");
    1757           0 :             delete poFile;
    1758           0 :             return nullptr;
    1759             :         }
    1760             : 
    1761         134 :         return LLOpen(poOpenInfo->pszFilename, poFile, poOpenInfo->eAccess,
    1762         134 :                       poOpenInfo->GetSiblingFiles());
    1763             :     }
    1764             :     /* -------------------------------------------------------------------- */
    1765             :     /*      Trap exceptions.                                                */
    1766             :     /* -------------------------------------------------------------------- */
    1767           1 :     catch (const PCIDSKException &ex)
    1768             :     {
    1769           1 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1770           1 :         delete poFile;
    1771           1 :         return nullptr;
    1772             :     }
    1773           0 :     catch (...)
    1774             :     {
    1775           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1776             :                  "PCIDSK::Create() failed, unexpected exception.");
    1777           0 :         delete poFile;
    1778           0 :         return nullptr;
    1779             :     }
    1780             : }
    1781             : 
    1782             : /************************************************************************/
    1783             : /*                               LLOpen()                               */
    1784             : /*                                                                      */
    1785             : /*      Low level variant of open that takes the preexisting            */
    1786             : /*      PCIDSKFile.                                                     */
    1787             : /************************************************************************/
    1788             : 
    1789         243 : GDALDataset *PCIDSK2Dataset::LLOpen(const char *pszFilename,
    1790             :                                     PCIDSK::PCIDSKFile *poFile,
    1791             :                                     GDALAccess eAccessIn,
    1792             :                                     char **papszSiblingFiles)
    1793             : 
    1794             : {
    1795         243 :     PCIDSK2Dataset *poDS = new PCIDSK2Dataset();
    1796             :     /* -------------------------------------------------------------------- */
    1797             :     /*      Create a corresponding GDALDataset.                             */
    1798             :     /* -------------------------------------------------------------------- */
    1799         243 :     poDS->poFile = poFile;
    1800         243 :     poDS->eAccess = eAccessIn;
    1801         243 :     poDS->nRasterXSize = poFile->GetWidth();
    1802         243 :     poDS->nRasterYSize = poFile->GetHeight();
    1803             : 
    1804             :     const bool bValidRasterDimensions =
    1805         243 :         poFile->GetWidth() && poFile->GetHeight();
    1806         243 :     if (!bValidRasterDimensions)
    1807             :     {
    1808           0 :         poDS->nRasterXSize = 512;
    1809           0 :         poDS->nRasterYSize = 512;
    1810             :     }
    1811             : 
    1812             :     try
    1813             :     {
    1814             : 
    1815             :         /* --------------------------------------------------------------------
    1816             :          */
    1817             :         /*      Are we specifically PIXEL or BAND interleaving? */
    1818             :         /*                                                                      */
    1819             :         /*      We don't set anything for FILE since it is harder to know if */
    1820             :         /*      this is tiled or what the on disk interleaving is. */
    1821             :         /* --------------------------------------------------------------------
    1822             :          */
    1823         243 :         if (EQUAL(poFile->GetInterleaving().c_str(), "PIXEL"))
    1824           0 :             poDS->SetMetadataItem("IMAGE_STRUCTURE", "PIXEL",
    1825             :                                   "IMAGE_STRUCTURE");
    1826         243 :         else if (EQUAL(poFile->GetInterleaving().c_str(), "BAND"))
    1827         215 :             poDS->SetMetadataItem("IMAGE_STRUCTURE", "BAND", "IMAGE_STRUCTURE");
    1828             : 
    1829             :         /* --------------------------------------------------------------------
    1830             :          */
    1831             :         /*      Create band objects. */
    1832             :         /* --------------------------------------------------------------------
    1833             :          */
    1834         474 :         for (int iBand = 0;
    1835         474 :              bValidRasterDimensions && iBand < poFile->GetChannels(); iBand++)
    1836             :         {
    1837         231 :             PCIDSKChannel *poChannel = poFile->GetChannel(iBand + 1);
    1838         462 :             if (poChannel->GetBlockWidth() <= 0 ||
    1839         231 :                 poChannel->GetBlockHeight() <= 0)
    1840             :             {
    1841           0 :                 delete poDS;
    1842           0 :                 return nullptr;
    1843             :             }
    1844             : 
    1845         231 :             if (PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType()) ==
    1846             :                 GDT_Unknown)
    1847             :             {
    1848           0 :                 continue;
    1849             :             }
    1850             : 
    1851         231 :             poDS->SetBand(poDS->GetRasterCount() + 1,
    1852         231 :                           new PCIDSK2Band(poFile, poChannel));
    1853             :         }
    1854             : 
    1855             :         /* --------------------------------------------------------------------
    1856             :          */
    1857             :         /*      Create band objects for bitmap segments. */
    1858             :         /* --------------------------------------------------------------------
    1859             :          */
    1860         243 :         int nLastBitmapSegment = 0;
    1861         243 :         PCIDSKSegment *poBitSeg = nullptr;
    1862             : 
    1863         486 :         while (bValidRasterDimensions &&
    1864         486 :                (poBitSeg = poFile->GetSegment(SEG_BIT, "",
    1865         243 :                                               nLastBitmapSegment)) != nullptr)
    1866             :         {
    1867           0 :             PCIDSKChannel *poChannel = dynamic_cast<PCIDSKChannel *>(poBitSeg);
    1868           0 :             if (poChannel == nullptr || poChannel->GetBlockWidth() <= 0 ||
    1869           0 :                 poChannel->GetBlockHeight() <= 0)
    1870             :             {
    1871           0 :                 delete poDS;
    1872           0 :                 return nullptr;
    1873             :             }
    1874             : 
    1875           0 :             if (PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType()) ==
    1876             :                 GDT_Unknown)
    1877             :             {
    1878           0 :                 continue;
    1879             :             }
    1880             : 
    1881           0 :             poDS->SetBand(poDS->GetRasterCount() + 1,
    1882           0 :                           new PCIDSK2Band(poChannel));
    1883             : 
    1884           0 :             nLastBitmapSegment = poBitSeg->GetSegmentNumber();
    1885             :         }
    1886             : 
    1887             :         /* --------------------------------------------------------------------
    1888             :          */
    1889             :         /*      Create vector layers from vector segments. */
    1890             :         /* --------------------------------------------------------------------
    1891             :          */
    1892         243 :         PCIDSK::PCIDSKSegment *segobj = poFile->GetSegment(PCIDSK::SEG_VEC, "");
    1893         338 :         for (; segobj != nullptr;
    1894          95 :              segobj = poFile->GetSegment(PCIDSK::SEG_VEC, "",
    1895          95 :                                          segobj->GetSegmentNumber()))
    1896             :         {
    1897             :             PCIDSK::PCIDSKVectorSegment *poVecSeg =
    1898          95 :                 dynamic_cast<PCIDSK::PCIDSKVectorSegment *>(segobj);
    1899          95 :             if (poVecSeg)
    1900          95 :                 poDS->apoLayers.push_back(new OGRPCIDSKLayer(
    1901          95 :                     poDS, segobj, poVecSeg, eAccessIn == GA_Update));
    1902             :         }
    1903             : 
    1904             :         /* --------------------------------------------------------------------
    1905             :          */
    1906             :         /*      Process RPC segment, if there is one. */
    1907             :         /* --------------------------------------------------------------------
    1908             :          */
    1909         243 :         poDS->ProcessRPC();
    1910             : 
    1911             :         /* --------------------------------------------------------------------
    1912             :          */
    1913             :         /*      Initialize any PAM information. */
    1914             :         /* --------------------------------------------------------------------
    1915             :          */
    1916         243 :         poDS->SetDescription(pszFilename);
    1917         243 :         poDS->TryLoadXML(papszSiblingFiles);
    1918             : 
    1919             :         /* --------------------------------------------------------------------
    1920             :          */
    1921             :         /*      Open overviews. */
    1922             :         /* --------------------------------------------------------------------
    1923             :          */
    1924         243 :         poDS->oOvManager.Initialize(poDS, pszFilename, papszSiblingFiles);
    1925             : 
    1926         243 :         return poDS;
    1927             :     }
    1928             : 
    1929             :     /* -------------------------------------------------------------------- */
    1930             :     /*      Trap exceptions.                                                */
    1931             :     /* -------------------------------------------------------------------- */
    1932           0 :     catch (const PCIDSKException &ex)
    1933             :     {
    1934           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1935             :     }
    1936           0 :     catch (...)
    1937             :     {
    1938           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1939             :                  "PCIDSK SDK Failure in Open(), unexpected exception.");
    1940             :     }
    1941             : 
    1942             :     /* -------------------------------------------------------------------- */
    1943             :     /*      In case of exception, close dataset                             */
    1944             :     /* -------------------------------------------------------------------- */
    1945           0 :     delete poDS;
    1946             : 
    1947           0 :     return nullptr;
    1948             : }
    1949             : 
    1950             : /************************************************************************/
    1951             : /*                               Create()                               */
    1952             : /************************************************************************/
    1953             : 
    1954         123 : GDALDataset *PCIDSK2Dataset::Create(const char *pszFilename, int nXSize,
    1955             :                                     int nYSize, int nBandsIn,
    1956             :                                     GDALDataType eType, char **papszParamList)
    1957             : 
    1958             : {
    1959             :     /* -------------------------------------------------------------------- */
    1960             :     /*      Prepare channel type list.                                      */
    1961             :     /* -------------------------------------------------------------------- */
    1962         246 :     std::vector<eChanType> aeChanTypes;
    1963             : 
    1964         123 :     if (eType == GDT_Float32)
    1965           3 :         aeChanTypes.resize(std::max(1, nBandsIn), CHN_32R);
    1966         120 :     else if (eType == GDT_Int16)
    1967           3 :         aeChanTypes.resize(std::max(1, nBandsIn), CHN_16S);
    1968         117 :     else if (eType == GDT_UInt16)
    1969          11 :         aeChanTypes.resize(std::max(1, nBandsIn), CHN_16U);
    1970         106 :     else if (eType == GDT_CInt16)
    1971           3 :         aeChanTypes.resize(std::max(1, nBandsIn), CHN_C16S);
    1972         103 :     else if (eType == GDT_CFloat32)
    1973           3 :         aeChanTypes.resize(std::max(1, nBandsIn), CHN_C32R);
    1974             :     else
    1975         100 :         aeChanTypes.resize(std::max(1, nBandsIn), CHN_8U);
    1976             : 
    1977             :     /* -------------------------------------------------------------------- */
    1978             :     /*      Reformat options.  Currently no support for jpeg compression    */
    1979             :     /*      quality.                                                        */
    1980             :     /* -------------------------------------------------------------------- */
    1981         246 :     CPLString osOptions;
    1982         123 :     const char *pszValue = CSLFetchNameValue(papszParamList, "INTERLEAVING");
    1983         123 :     if (pszValue == nullptr)
    1984         115 :         pszValue = "BAND";
    1985             : 
    1986         123 :     osOptions = pszValue;
    1987             : 
    1988         123 :     if (osOptions == "TILED")
    1989             :     {
    1990           7 :         pszValue = CSLFetchNameValue(papszParamList, "TILESIZE");
    1991           7 :         if (pszValue != nullptr)
    1992           6 :             osOptions += pszValue;
    1993             : 
    1994           7 :         pszValue = CSLFetchNameValue(papszParamList, "COMPRESSION");
    1995           7 :         if (pszValue != nullptr)
    1996             :         {
    1997           4 :             osOptions += " ";
    1998           4 :             osOptions += pszValue;
    1999             :         }
    2000             : 
    2001           7 :         pszValue = CSLFetchNameValue(papszParamList, "TILEVERSION");
    2002           7 :         if (pszValue != nullptr)
    2003             :         {
    2004           4 :             osOptions += " TILEV";
    2005           4 :             osOptions += pszValue;
    2006             :         }
    2007             :     }
    2008             : 
    2009             :     /* -------------------------------------------------------------------- */
    2010             :     /*      Try creation.                                                   */
    2011             :     /* -------------------------------------------------------------------- */
    2012             : 
    2013             :     try
    2014             :     {
    2015         123 :         if (nBandsIn == 0)
    2016             :         {
    2017          43 :             nXSize = 512;
    2018          43 :             nYSize = 512;
    2019             :         }
    2020         274 :         PCIDSKFile *poFile = PCIDSK::Create(pszFilename, nXSize, nYSize,
    2021         123 :                                             nBandsIn, &(aeChanTypes[0]),
    2022             :                                             osOptions, PCIDSK2GetInterfaces());
    2023             : 
    2024             :         /* --------------------------------------------------------------------
    2025             :          */
    2026             :         /*      Apply band descriptions, if provided as creation options. */
    2027             :         /* --------------------------------------------------------------------
    2028             :          */
    2029         131 :         for (size_t i = 0;
    2030         131 :              papszParamList != nullptr && papszParamList[i] != nullptr; i++)
    2031             :         {
    2032          22 :             if (STARTS_WITH_CI(papszParamList[i], "BANDDESC"))
    2033             :             {
    2034           0 :                 int nBand = atoi(papszParamList[i] + 8);
    2035           0 :                 const char *pszDescription = strstr(papszParamList[i], "=");
    2036           0 :                 if (pszDescription && nBand > 0 && nBand <= nBandsIn)
    2037             :                 {
    2038           0 :                     poFile->GetChannel(nBand)->SetDescription(pszDescription +
    2039           0 :                                                               1);
    2040             :                 }
    2041             :             }
    2042             :         }
    2043             : 
    2044         109 :         return LLOpen(pszFilename, poFile, GA_Update);
    2045             :     }
    2046             :     /* -------------------------------------------------------------------- */
    2047             :     /*      Trap exceptions.                                                */
    2048             :     /* -------------------------------------------------------------------- */
    2049          28 :     catch (const PCIDSKException &ex)
    2050             :     {
    2051          14 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    2052             :     }
    2053           0 :     catch (...)
    2054             :     {
    2055           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2056             :                  "PCIDSK::Create() failed, unexpected exception.");
    2057             :     }
    2058             : 
    2059          14 :     return nullptr;
    2060             : }
    2061             : 
    2062             : /************************************************************************/
    2063             : /*                           TestCapability()                           */
    2064             : /************************************************************************/
    2065             : 
    2066          79 : int PCIDSK2Dataset::TestCapability(const char *pszCap)
    2067             : 
    2068             : {
    2069          79 :     if (EQUAL(pszCap, ODsCCreateLayer))
    2070          37 :         return eAccess == GA_Update;
    2071          42 :     if (EQUAL(pszCap, ODsCRandomLayerWrite))
    2072           0 :         return eAccess == GA_Update;
    2073          42 :     if (EQUAL(pszCap, ODsCZGeometries))
    2074          12 :         return TRUE;
    2075             : 
    2076          30 :     return FALSE;
    2077             : }
    2078             : 
    2079             : /************************************************************************/
    2080             : /*                              GetLayer()                              */
    2081             : /************************************************************************/
    2082             : 
    2083        1655 : OGRLayer *PCIDSK2Dataset::GetLayer(int iLayer)
    2084             : 
    2085             : {
    2086        1655 :     if (iLayer < 0 || iLayer >= static_cast<int>(apoLayers.size()))
    2087           2 :         return nullptr;
    2088             : 
    2089        1653 :     return apoLayers[iLayer];
    2090             : }
    2091             : 
    2092             : /************************************************************************/
    2093             : /*                           ICreateLayer()                             */
    2094             : /************************************************************************/
    2095             : 
    2096        1089 : OGRLayer *PCIDSK2Dataset::ICreateLayer(const char *pszLayerName,
    2097             :                                        const OGRGeomFieldDefn *poGeomFieldDefn,
    2098             :                                        CSLConstList /*papszOptions*/)
    2099             : {
    2100             :     /* -------------------------------------------------------------------- */
    2101             :     /*      Verify we are in update mode.                                   */
    2102             :     /* -------------------------------------------------------------------- */
    2103        1089 :     if (eAccess != GA_Update)
    2104             :     {
    2105           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    2106             :                  "Data source %s opened read-only.\n"
    2107             :                  "New layer %s cannot be created.\n",
    2108           0 :                  GetDescription(), pszLayerName);
    2109           0 :         return nullptr;
    2110             :     }
    2111             : 
    2112        1089 :     const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
    2113             :     const auto poSRS =
    2114        1089 :         poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
    2115             : 
    2116             :     /* -------------------------------------------------------------------- */
    2117             :     /*      Figure out what type of layer we need.                          */
    2118             :     /* -------------------------------------------------------------------- */
    2119        2178 :     std::string osLayerType;
    2120             : 
    2121        1089 :     switch (wkbFlatten(eType))
    2122             :     {
    2123          10 :         case wkbPoint:
    2124          10 :             osLayerType = "POINTS";
    2125          10 :             break;
    2126             : 
    2127          10 :         case wkbLineString:
    2128          10 :             osLayerType = "ARCS";
    2129          10 :             break;
    2130             : 
    2131           6 :         case wkbPolygon:
    2132           6 :             osLayerType = "WHOLE_POLYGONS";
    2133           6 :             break;
    2134             : 
    2135           7 :         case wkbNone:
    2136           7 :             osLayerType = "TABLE";
    2137           7 :             break;
    2138             : 
    2139        1056 :         default:
    2140        1056 :             break;
    2141             :     }
    2142             : 
    2143             :     /* -------------------------------------------------------------------- */
    2144             :     /*      Create the segment.                                             */
    2145             :     /* -------------------------------------------------------------------- */
    2146             :     int nSegNum;
    2147             :     try
    2148             :     {
    2149        1093 :         nSegNum = poFile->CreateSegment(pszLayerName, "", PCIDSK::SEG_VEC, 0L);
    2150             :     }
    2151           1 :     catch (const PCIDSKException &ex)
    2152             :     {
    2153           1 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    2154           1 :         return nullptr;
    2155             :     }
    2156        1088 :     PCIDSK::PCIDSKSegment *poSeg = poFile->GetSegment(nSegNum);
    2157             :     PCIDSK::PCIDSKVectorSegment *poVecSeg =
    2158        1088 :         dynamic_cast<PCIDSK::PCIDSKVectorSegment *>(poSeg);
    2159        1088 :     if (poVecSeg == nullptr)
    2160           0 :         return nullptr;
    2161             : 
    2162        1088 :     if (osLayerType != "")
    2163          33 :         poSeg->SetMetadataValue("LAYER_TYPE", osLayerType);
    2164             : 
    2165             :     /* -------------------------------------------------------------------- */
    2166             :     /*      Do we need to apply a coordinate system?                        */
    2167             :     /* -------------------------------------------------------------------- */
    2168        1088 :     char *pszGeosys = nullptr;
    2169        1088 :     char *pszUnits = nullptr;
    2170        1088 :     double *padfPrjParams = nullptr;
    2171             : 
    2172        1088 :     if (poSRS != nullptr && poSRS->exportToPCI(&pszGeosys, &pszUnits,
    2173             :                                                &padfPrjParams) == OGRERR_NONE)
    2174             :     {
    2175             :         try
    2176             :         {
    2177           6 :             std::vector<double> adfPCIParameters;
    2178             : 
    2179         108 :             for (int i = 0; i < 17; i++)
    2180         102 :                 adfPCIParameters.push_back(padfPrjParams[i]);
    2181             : 
    2182           6 :             if (STARTS_WITH_CI(pszUnits, "FOOT"))
    2183           0 :                 adfPCIParameters.push_back(static_cast<double>(
    2184             :                     static_cast<int>(PCIDSK::UNIT_US_FOOT)));
    2185           6 :             else if (STARTS_WITH_CI(pszUnits, "INTL FOOT"))
    2186           0 :                 adfPCIParameters.push_back(static_cast<double>(
    2187             :                     static_cast<int>(PCIDSK::UNIT_INTL_FOOT)));
    2188           6 :             else if (STARTS_WITH_CI(pszUnits, "DEGREE"))
    2189           2 :                 adfPCIParameters.push_back(
    2190           2 :                     static_cast<double>(static_cast<int>(PCIDSK::UNIT_DEGREE)));
    2191             :             else
    2192           4 :                 adfPCIParameters.push_back(
    2193           4 :                     static_cast<double>(static_cast<int>(PCIDSK::UNIT_METER)));
    2194             : 
    2195           6 :             poVecSeg->SetProjection(pszGeosys, adfPCIParameters);
    2196             :         }
    2197           0 :         catch (const PCIDSKException &ex)
    2198             :         {
    2199           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    2200             :         }
    2201             : 
    2202           6 :         CPLFree(pszGeosys);
    2203           6 :         CPLFree(pszUnits);
    2204           6 :         CPLFree(padfPrjParams);
    2205             :     }
    2206             : 
    2207             :     /* -------------------------------------------------------------------- */
    2208             :     /*      Create the layer object.                                        */
    2209             :     /* -------------------------------------------------------------------- */
    2210             : 
    2211        1088 :     apoLayers.push_back(new OGRPCIDSKLayer(this, poSeg, poVecSeg, TRUE));
    2212             : 
    2213        1088 :     return apoLayers.back();
    2214             : }
    2215             : 
    2216             : /************************************************************************/
    2217             : /*                        GDALRegister_PCIDSK()                         */
    2218             : /************************************************************************/
    2219             : 
    2220          11 : void GDALRegister_PCIDSK()
    2221             : 
    2222             : {
    2223          11 :     if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
    2224           0 :         return;
    2225             : 
    2226          11 :     GDALDriver *poDriver = new GDALDriver();
    2227          11 :     PCIDSKDriverSetCommonMetadata(poDriver);
    2228             : 
    2229          11 :     poDriver->pfnOpen = PCIDSK2Dataset::Open;
    2230          11 :     poDriver->pfnCreate = PCIDSK2Dataset::Create;
    2231             : 
    2232          11 :     GetGDALDriverManager()->RegisterDriver(poDriver);
    2233             : }

Generated by: LCOV version 1.14