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

Generated by: LCOV version 1.14