LCOV - code coverage report
Current view: top level - frmts/pcidsk - pcidskdataset2.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 621 910 68.2 %
Date: 2026-03-26 23:25:44 Functions: 47 49 95.9 %

          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         235 : PCIDSK2Band::PCIDSK2Band(PCIDSKFile *poFileIn, PCIDSKChannel *poChannelIn)
      36             : 
      37             : {
      38         235 :     Initialize();
      39             : 
      40         235 :     poFile = poFileIn;
      41         235 :     poChannel = poChannelIn;
      42             : 
      43         235 :     nBlockXSize = static_cast<int>(poChannel->GetBlockWidth());
      44         235 :     nBlockYSize = static_cast<int>(poChannel->GetBlockHeight());
      45             : 
      46         235 :     eDataType = PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType());
      47             : 
      48         235 :     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         235 :     RefreshOverviewList();
      56         235 : }
      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         246 : void PCIDSK2Band::Initialize()
      98             : 
      99             : {
     100         246 :     papszLastMDListValue = nullptr;
     101             : 
     102         246 :     poChannel = nullptr;
     103         246 :     poFile = nullptr;
     104         246 :     poDS = nullptr;
     105             : 
     106         246 :     bCheckedForColorTable = false;
     107         246 :     poColorTable = nullptr;
     108         246 :     nPCTSegNumber = -1;
     109             : 
     110         246 :     papszCategoryNames = nullptr;
     111         246 : }
     112             : 
     113             : /************************************************************************/
     114             : /*                            ~PCIDSK2Band()                            */
     115             : /************************************************************************/
     116             : 
     117         738 : PCIDSK2Band::~PCIDSK2Band()
     118             : 
     119             : {
     120         257 :     while (!apoOverviews.empty())
     121             :     {
     122          11 :         delete apoOverviews.back();
     123          11 :         apoOverviews.pop_back();
     124             :     }
     125         246 :     CSLDestroy(papszLastMDListValue);
     126         246 :     CSLDestroy(papszCategoryNames);
     127             : 
     128         246 :     delete poColorTable;
     129         492 : }
     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          27 : bool PCIDSK2Band::CheckForColorTable()
     235             : 
     236             : {
     237          27 :     if (bCheckedForColorTable || poFile == nullptr)
     238          14 :         return true;
     239             : 
     240          13 :     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          39 :             poChannel->GetMetadataValue("DEFAULT_PCT_REF");
     251          13 :         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          25 :         if (osDefaultPCT.empty() && poDS != nullptr &&
     256          12 :             poDS->GetRasterCount() == 1)
     257             :         {
     258          12 :             poPCTSeg = poFile->GetSegment(SEG_PCT, "");
     259          12 :             if (poPCTSeg != nullptr &&
     260          12 :                 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          13 :         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          26 :         std::vector<std::string> aosMDKeys = poChannel->GetMetadataKeys();
     304             : 
     305          23 :         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          13 :     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          15 : GDALColorInterp PCIDSK2Band::GetColorInterpretation()
     479             : 
     480             : {
     481          15 :     CheckForColorTable();
     482             : 
     483          15 :     if (poColorTable != nullptr)
     484           1 :         return GCI_PaletteIndex;
     485             : 
     486          14 :     return GDALPamRasterBand::GetColorInterpretation();
     487             : }
     488             : 
     489             : /************************************************************************/
     490             : /*                        RefreshOverviewList()                         */
     491             : /************************************************************************/
     492             : 
     493         236 : void PCIDSK2Band::RefreshOverviewList()
     494             : 
     495             : {
     496             :     /* -------------------------------------------------------------------- */
     497             :     /*      Clear existing overviews.                                       */
     498             :     /* -------------------------------------------------------------------- */
     499         236 :     while (!apoOverviews.empty())
     500             :     {
     501           0 :         delete apoOverviews.back();
     502           0 :         apoOverviews.pop_back();
     503             :     }
     504             : 
     505             :     /* -------------------------------------------------------------------- */
     506             :     /*      Fetch overviews.                                                */
     507             :     /* -------------------------------------------------------------------- */
     508         247 :     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         236 : }
     515             : 
     516             : /************************************************************************/
     517             : /*                             IReadBlock()                             */
     518             : /************************************************************************/
     519             : 
     520         262 : CPLErr PCIDSK2Band::IReadBlock(int iBlockX, int iBlockY, void *pData)
     521             : 
     522             : {
     523             :     try
     524             :     {
     525         262 :         poChannel->ReadBlock(iBlockX + iBlockY * nBlocksPerRow, pData);
     526             : 
     527             :         // Do we need to upsample 1bit to 8bit?
     528         262 :         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         262 :         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         645 : CPLErr PCIDSK2Band::IWriteBlock(int iBlockX, int iBlockY, void *pData)
     555             : 
     556             : {
     557             :     try
     558             :     {
     559         645 :         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         645 :     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           2 : CPLErr PCIDSK2Band::SetMetadata(CSLConstList papszMD, const char *pszDomain)
     601             : 
     602             : {
     603             :     /* -------------------------------------------------------------------- */
     604             :     /*      PCIDSK only supports metadata in the default domain.            */
     605             :     /* -------------------------------------------------------------------- */
     606           2 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
     607           0 :         return GDALPamRasterBand::SetMetadata(papszMD, pszDomain);
     608             : 
     609             :     /* -------------------------------------------------------------------- */
     610             :     /*      Set each item individually.                                     */
     611             :     /* -------------------------------------------------------------------- */
     612           2 :     CSLDestroy(papszLastMDListValue);
     613           2 :     papszLastMDListValue = nullptr;
     614           2 :     m_oCacheMetadataItem.clear();
     615             : 
     616           2 :     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           5 :         for (int iItem = 0; papszMD && papszMD[iItem]; iItem++)
     626             :         {
     627           3 :             char *pszItemName = nullptr;
     628             : 
     629             :             const char *pszItemValue =
     630           3 :                 CPLParseNameValue(papszMD[iItem], &pszItemName);
     631           3 :             if (pszItemName != nullptr)
     632             :             {
     633           3 :                 poChannel->SetMetadataValue(pszItemName, pszItemValue);
     634           3 :                 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           2 :     return CE_None;
     645             : }
     646             : 
     647             : /************************************************************************/
     648             : /*                          SetMetadataItem()                           */
     649             : /************************************************************************/
     650             : 
     651           6 : 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           6 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
     659           1 :         return GDALPamRasterBand::SetMetadataItem(pszName, pszValue, pszDomain);
     660             : 
     661             :     /* -------------------------------------------------------------------- */
     662             :     /*      Set on the file.                                                */
     663             :     /* -------------------------------------------------------------------- */
     664           5 :     CSLDestroy(papszLastMDListValue);
     665           5 :     papszLastMDListValue = nullptr;
     666           5 :     m_oCacheMetadataItem.clear();
     667             : 
     668           5 :     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           5 :         if (!pszValue)
     678           0 :             pszValue = "";
     679           5 :         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           5 :     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             : /*                           GetNoDataValue()                           */
     702             : /************************************************************************/
     703             : 
     704          63 : double PCIDSK2Band::GetNoDataValue(int *pbSuccess)
     705             : {
     706          63 :     const char *pszNoData = GetMetadataItem("NO_DATA_VALUE", "");
     707          63 :     if (pszNoData != nullptr)
     708             :     {
     709           1 :         if (pbSuccess)
     710           1 :             *pbSuccess = TRUE;
     711           1 :         return CPLAtof(pszNoData);
     712             :     }
     713             : 
     714          62 :     PCIDSK2Dataset *poGDS = cpl::down_cast<PCIDSK2Dataset *>(poDS);
     715          62 :     pszNoData = poGDS->GetMetadataItem("NO_DATA_VALUE", "");
     716          62 :     if (pszNoData != nullptr)
     717             :     {
     718           1 :         if (pbSuccess)
     719           1 :             *pbSuccess = TRUE;
     720           1 :         return CPLAtof(pszNoData);
     721             :     }
     722             : 
     723          61 :     if (pbSuccess)
     724          61 :         *pbSuccess = FALSE;
     725          61 :     return 0.0;
     726             : }
     727             : 
     728             : /************************************************************************/
     729             : /*                           SetNoDataValue()                           */
     730             : /************************************************************************/
     731             : 
     732           1 : CPLErr PCIDSK2Band::SetNoDataValue(double dfNoData)
     733             : {
     734           1 :     return SetMetadataItem("NO_DATA_VALUE", CPLSPrintf("%.17g", dfNoData), "");
     735             : }
     736             : 
     737             : /************************************************************************/
     738             : /*                          GetMetadataItem()                           */
     739             : /************************************************************************/
     740             : 
     741          97 : const char *PCIDSK2Band::GetMetadataItem(const char *pszName,
     742             :                                          const char *pszDomain)
     743             : 
     744             : {
     745             :     /* -------------------------------------------------------------------- */
     746             :     /*      PCIDSK only supports metadata in the default domain.            */
     747             :     /* -------------------------------------------------------------------- */
     748          97 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
     749          23 :         return GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
     750             : 
     751             :     /* -------------------------------------------------------------------- */
     752             :     /*      Try and fetch (use cached value if available)                   */
     753             :     /* -------------------------------------------------------------------- */
     754          74 :     auto oIter = m_oCacheMetadataItem.find(pszName);
     755          74 :     if (oIter != m_oCacheMetadataItem.end())
     756             :     {
     757          37 :         return oIter->second.empty() ? nullptr : oIter->second.c_str();
     758             :     }
     759             : 
     760          74 :     CPLString osValue;
     761             :     try
     762             :     {
     763          37 :         osValue = poChannel->GetMetadataValue(pszName);
     764             :     }
     765           0 :     catch (const PCIDSKException &ex)
     766             :     {
     767           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     768           0 :         return nullptr;
     769             :     }
     770             : 
     771          37 :     oIter = m_oCacheMetadataItem
     772          37 :                 .insert(std::pair<std::string, std::string>(pszName, osValue))
     773             :                 .first;
     774          37 :     return oIter->second.empty() ? nullptr : oIter->second.c_str();
     775             : }
     776             : 
     777             : /************************************************************************/
     778             : /*                            GetMetadata()                             */
     779             : /************************************************************************/
     780             : 
     781           6 : CSLConstList PCIDSK2Band::GetMetadata(const char *pszDomain)
     782             : 
     783             : {
     784             :     /* -------------------------------------------------------------------- */
     785             :     /*      PCIDSK only supports metadata in the default domain.            */
     786             :     /* -------------------------------------------------------------------- */
     787           6 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
     788           1 :         return GDALPamRasterBand::GetMetadata(pszDomain);
     789             : 
     790             :     /* -------------------------------------------------------------------- */
     791             :     /*      If we have a cached result, just use that.                      */
     792             :     /* -------------------------------------------------------------------- */
     793           5 :     if (papszLastMDListValue != nullptr)
     794           0 :         return papszLastMDListValue;
     795             : 
     796             :     /* -------------------------------------------------------------------- */
     797             :     /*      Fetch and build the list.                                       */
     798             :     /* -------------------------------------------------------------------- */
     799             :     try
     800             :     {
     801          10 :         std::vector<std::string> aosKeys = poChannel->GetMetadataKeys();
     802             : 
     803          11 :         for (unsigned int i = 0; i < aosKeys.size(); i++)
     804             :         {
     805           6 :             if (aosKeys[i].c_str()[0] == '_')
     806           3 :                 continue;
     807             : 
     808           6 :             papszLastMDListValue = CSLSetNameValue(
     809           3 :                 papszLastMDListValue, aosKeys[i].c_str(),
     810           6 :                 poChannel->GetMetadataValue(aosKeys[i]).c_str());
     811             :         }
     812             :     }
     813           0 :     catch (const PCIDSKException &ex)
     814             :     {
     815           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     816           0 :         return nullptr;
     817             :     }
     818             : 
     819           5 :     return papszLastMDListValue;
     820             : }
     821             : 
     822             : /************************************************************************/
     823             : /* ==================================================================== */
     824             : /*                            PCIDSK2Dataset                            */
     825             : /* ==================================================================== */
     826             : /************************************************************************/
     827             : 
     828             : /************************************************************************/
     829             : /*                           PCIDSK2Dataset()                           */
     830             : /************************************************************************/
     831             : 
     832         245 : PCIDSK2Dataset::PCIDSK2Dataset()
     833         245 :     : papszLastMDListValue(nullptr), poFile(nullptr)
     834             : {
     835         245 : }
     836             : 
     837             : /************************************************************************/
     838             : /*                          ~PCIDSK2Dataset()                           */
     839             : /************************************************************************/
     840             : 
     841             : // FIXME? is an exception can really be thrown in the destructor, then it is
     842             : // very dangerous !
     843             : #ifdef _MSC_VER
     844             : #pragma warning(push)
     845             : #pragma warning(disable : 4702) /*  unreachable code */
     846             : #endif
     847         490 : PCIDSK2Dataset::~PCIDSK2Dataset()
     848             : {
     849         245 :     PCIDSK2Dataset::FlushCache(true);
     850             : 
     851        1428 :     while (!apoLayers.empty())
     852             :     {
     853        1183 :         delete apoLayers.back();
     854        1183 :         apoLayers.pop_back();
     855             :     }
     856             : 
     857         245 :     if (m_poSRS)
     858           7 :         m_poSRS->Release();
     859             : 
     860             :     try
     861             :     {
     862         245 :         if (poFile != nullptr)
     863         245 :             delete poFile;
     864             :     }
     865             : 
     866             :     /* -------------------------------------------------------------------- */
     867             :     /*      Trap exceptions.                                                */
     868             :     /* -------------------------------------------------------------------- */
     869             :     catch (const PCIDSKException &ex)
     870             :     {
     871             :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     872             :     }
     873             :     catch (...)
     874             :     {
     875             :         CPLError(CE_Failure, CPLE_AppDefined,
     876             :                  "PCIDSK SDK Failure in Close(), unexpected exception.");
     877             :     }
     878             : 
     879         245 :     CSLDestroy(papszLastMDListValue);
     880         490 : }
     881             : #ifdef _MSC_VER
     882             : #pragma warning(pop)
     883             : #endif
     884             : 
     885             : /************************************************************************/
     886             : /*                            GetFileList()                             */
     887             : /************************************************************************/
     888             : 
     889          55 : char **PCIDSK2Dataset::GetFileList()
     890             : 
     891             : {
     892          55 :     char **papszFileList = GDALPamDataset::GetFileList();
     893         110 :     CPLString osBaseDir = CPLGetPathSafe(GetDescription());
     894             : 
     895             :     try
     896             :     {
     897          75 :         for (int nChan = 1; nChan <= poFile->GetChannels(); nChan++)
     898             :         {
     899          20 :             PCIDSKChannel *poChannel = poFile->GetChannel(nChan);
     900          40 :             CPLString osChanFilename;
     901             :             uint64 image_offset, pixel_offset, line_offset;
     902             :             bool little_endian;
     903             : 
     904          20 :             poChannel->GetChanInfo(osChanFilename, image_offset, pixel_offset,
     905          20 :                                    line_offset, little_endian);
     906             : 
     907          20 :             if (osChanFilename != "")
     908             :             {
     909           1 :                 papszFileList = CSLAddString(
     910             :                     papszFileList,
     911           2 :                     CPLProjectRelativeFilenameSafe(osBaseDir, osChanFilename)
     912             :                         .c_str());
     913             :             }
     914             :         }
     915             : 
     916          55 :         return papszFileList;
     917             :     }
     918           0 :     catch (const PCIDSKException &ex)
     919             :     {
     920           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
     921           0 :         return papszFileList;
     922             :     }
     923             : }
     924             : 
     925             : /************************************************************************/
     926             : /*                             ProcessRPC()                             */
     927             : /************************************************************************/
     928             : 
     929         245 : void PCIDSK2Dataset::ProcessRPC()
     930             : 
     931             : {
     932             :     /* -------------------------------------------------------------------- */
     933             :     /*      Search all BIN segments looking for an RPC segment.             */
     934             :     /* -------------------------------------------------------------------- */
     935         245 :     PCIDSKSegment *poSeg = poFile->GetSegment(SEG_BIN, "");
     936         245 :     PCIDSKRPCSegment *poRPCSeg = nullptr;
     937             : 
     938         245 :     while (poSeg != nullptr &&
     939           0 :            (poRPCSeg = dynamic_cast<PCIDSKRPCSegment *>(poSeg)) == nullptr)
     940             : 
     941             :     {
     942           0 :         poSeg = poFile->GetSegment(SEG_BIN, "", poSeg->GetSegmentNumber());
     943             :     }
     944             : 
     945         245 :     if (poRPCSeg == nullptr)
     946         245 :         return;
     947             : 
     948             :     /* -------------------------------------------------------------------- */
     949             :     /*      Turn RPC segment into GDAL RFC 22 style metadata.               */
     950             :     /* -------------------------------------------------------------------- */
     951             :     try
     952             :     {
     953           0 :         CPLString osValue;
     954             :         double dfLineOffset, dfLineScale, dfSampOffset, dfSampScale;
     955             :         double dfLatOffset, dfLatScale, dfLongOffset, dfLongScale,
     956             :             dfHeightOffset, dfHeightScale;
     957             : 
     958           0 :         poRPCSeg->GetRPCTranslationCoeffs(
     959             :             dfLongOffset, dfLongScale, dfLatOffset, dfLatScale, dfHeightOffset,
     960             :             dfHeightScale, dfSampOffset, dfSampScale, dfLineOffset,
     961           0 :             dfLineScale);
     962             : 
     963           0 :         osValue.Printf("%.16g", dfLineOffset);
     964           0 :         GDALPamDataset::SetMetadataItem("LINE_OFF", osValue, "RPC");
     965             : 
     966           0 :         osValue.Printf("%.16g", dfLineScale);
     967           0 :         GDALPamDataset::SetMetadataItem("LINE_SCALE", osValue, "RPC");
     968             : 
     969           0 :         osValue.Printf("%.16g", dfSampOffset);
     970           0 :         GDALPamDataset::SetMetadataItem("SAMP_OFF", osValue, "RPC");
     971             : 
     972           0 :         osValue.Printf("%.16g", dfSampScale);
     973           0 :         GDALPamDataset::SetMetadataItem("SAMP_SCALE", osValue, "RPC");
     974             : 
     975           0 :         osValue.Printf("%.16g", dfLongOffset);
     976           0 :         GDALPamDataset::SetMetadataItem("LONG_OFF", osValue, "RPC");
     977             : 
     978           0 :         osValue.Printf("%.16g", dfLongScale);
     979           0 :         GDALPamDataset::SetMetadataItem("LONG_SCALE", osValue, "RPC");
     980             : 
     981           0 :         osValue.Printf("%.16g", dfLatOffset);
     982           0 :         GDALPamDataset::SetMetadataItem("LAT_OFF", osValue, "RPC");
     983             : 
     984           0 :         osValue.Printf("%.16g", dfLatScale);
     985           0 :         GDALPamDataset::SetMetadataItem("LAT_SCALE", osValue, "RPC");
     986             : 
     987           0 :         osValue.Printf("%.16g", dfHeightOffset);
     988           0 :         GDALPamDataset::SetMetadataItem("HEIGHT_OFF", osValue, "RPC");
     989             : 
     990           0 :         osValue.Printf("%.16g", dfHeightScale);
     991           0 :         GDALPamDataset::SetMetadataItem("HEIGHT_SCALE", osValue, "RPC");
     992             : 
     993           0 :         if (poRPCSeg->GetXNumerator().size() != 20 ||
     994           0 :             poRPCSeg->GetXDenominator().size() != 20 ||
     995           0 :             poRPCSeg->GetYNumerator().size() != 20 ||
     996           0 :             poRPCSeg->GetYDenominator().size() != 20)
     997             :         {
     998           0 :             GDALPamDataset::SetMetadata(nullptr, "RPC");
     999           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1000             :                      "Did not get 20 values in the RPC coefficients lists.");
    1001           0 :             return;
    1002             :         }
    1003             : 
    1004           0 :         std::vector<double> adfCoef = poRPCSeg->GetYNumerator();
    1005           0 :         CPLString osCoefList = "";
    1006           0 :         for (int i = 0; i < 20; i++)
    1007             :         {
    1008           0 :             osValue.Printf("%.16g ", adfCoef[i]);
    1009           0 :             osCoefList += osValue;
    1010             :         }
    1011           0 :         GDALPamDataset::SetMetadataItem("LINE_NUM_COEFF", osCoefList, "RPC");
    1012             : 
    1013           0 :         adfCoef = poRPCSeg->GetYDenominator();
    1014           0 :         osCoefList = "";
    1015           0 :         for (int i = 0; i < 20; i++)
    1016             :         {
    1017           0 :             osValue.Printf("%.16g ", adfCoef[i]);
    1018           0 :             osCoefList += osValue;
    1019             :         }
    1020           0 :         GDALPamDataset::SetMetadataItem("LINE_DEN_COEFF", osCoefList, "RPC");
    1021             : 
    1022           0 :         adfCoef = poRPCSeg->GetXNumerator();
    1023           0 :         osCoefList = "";
    1024           0 :         for (int i = 0; i < 20; i++)
    1025             :         {
    1026           0 :             osValue.Printf("%.16g ", adfCoef[i]);
    1027           0 :             osCoefList += osValue;
    1028             :         }
    1029           0 :         GDALPamDataset::SetMetadataItem("SAMP_NUM_COEFF", osCoefList, "RPC");
    1030             : 
    1031           0 :         adfCoef = poRPCSeg->GetXDenominator();
    1032           0 :         osCoefList = "";
    1033           0 :         for (int i = 0; i < 20; i++)
    1034             :         {
    1035           0 :             osValue.Printf("%.16g ", adfCoef[i]);
    1036           0 :             osCoefList += osValue;
    1037             :         }
    1038           0 :         GDALPamDataset::SetMetadataItem("SAMP_DEN_COEFF", osCoefList, "RPC");
    1039             :     }
    1040           0 :     catch (const PCIDSKException &ex)
    1041             :     {
    1042           0 :         GDALPamDataset::SetMetadata(nullptr, "RPC");
    1043           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1044             :     }
    1045             : }
    1046             : 
    1047             : /************************************************************************/
    1048             : /*                             FlushCache()                             */
    1049             : /************************************************************************/
    1050             : 
    1051         257 : CPLErr PCIDSK2Dataset::FlushCache(bool bAtClosing)
    1052             : 
    1053             : {
    1054         257 :     CPLErr eErr = GDALPamDataset::FlushCache(bAtClosing);
    1055             : 
    1056         257 :     if (poFile)
    1057             :     {
    1058             :         try
    1059             :         {
    1060         257 :             poFile->Synchronize();
    1061             :         }
    1062           0 :         catch (const PCIDSKException &ex)
    1063             :         {
    1064           0 :             eErr = CE_Failure;
    1065           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1066             :         }
    1067             :     }
    1068         257 :     return eErr;
    1069             : }
    1070             : 
    1071             : /************************************************************************/
    1072             : /*                            SetMetadata()                             */
    1073             : /************************************************************************/
    1074             : 
    1075          26 : CPLErr PCIDSK2Dataset::SetMetadata(CSLConstList papszMD, const char *pszDomain)
    1076             : 
    1077             : {
    1078             :     /* -------------------------------------------------------------------- */
    1079             :     /*      PCIDSK only supports metadata in the default domain.            */
    1080             :     /* -------------------------------------------------------------------- */
    1081          26 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
    1082           0 :         return GDALPamDataset::SetMetadata(papszMD, pszDomain);
    1083             : 
    1084             :     /* -------------------------------------------------------------------- */
    1085             :     /*      Set each item individually.                                     */
    1086             :     /* -------------------------------------------------------------------- */
    1087          26 :     CSLDestroy(papszLastMDListValue);
    1088          26 :     papszLastMDListValue = nullptr;
    1089          26 :     m_oCacheMetadataItem.clear();
    1090             : 
    1091          26 :     if (GetAccess() == GA_ReadOnly)
    1092             :     {
    1093           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    1094             :                  "Unable to set metadata on read-only file.");
    1095           0 :         return CE_Failure;
    1096             :     }
    1097             : 
    1098             :     try
    1099             :     {
    1100          59 :         for (int iItem = 0; papszMD && papszMD[iItem]; iItem++)
    1101             :         {
    1102          33 :             char *pszItemName = nullptr;
    1103             :             const char *pszItemValue =
    1104          33 :                 CPLParseNameValue(papszMD[iItem], &pszItemName);
    1105          33 :             if (pszItemName != nullptr)
    1106             :             {
    1107          17 :                 poFile->SetMetadataValue(pszItemName, pszItemValue);
    1108          17 :                 CPLFree(pszItemName);
    1109             :             }
    1110             :         }
    1111             :     }
    1112           0 :     catch (const PCIDSKException &ex)
    1113             :     {
    1114           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1115           0 :         return CE_Failure;
    1116             :     }
    1117             : 
    1118          26 :     return CE_None;
    1119             : }
    1120             : 
    1121             : /************************************************************************/
    1122             : /*                          SetMetadataItem()                           */
    1123             : /************************************************************************/
    1124             : 
    1125         223 : CPLErr PCIDSK2Dataset::SetMetadataItem(const char *pszName,
    1126             :                                        const char *pszValue,
    1127             :                                        const char *pszDomain)
    1128             : 
    1129             : {
    1130             :     /* -------------------------------------------------------------------- */
    1131             :     /*      PCIDSK only supports metadata in the default domain.            */
    1132             :     /* -------------------------------------------------------------------- */
    1133         223 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
    1134         218 :         return GDALPamDataset::SetMetadataItem(pszName, pszValue, pszDomain);
    1135             : 
    1136             :     /* -------------------------------------------------------------------- */
    1137             :     /*      Set on the file.                                                */
    1138             :     /* -------------------------------------------------------------------- */
    1139           5 :     CSLDestroy(papszLastMDListValue);
    1140           5 :     papszLastMDListValue = nullptr;
    1141           5 :     m_oCacheMetadataItem.clear();
    1142             : 
    1143           5 :     if (GetAccess() == GA_ReadOnly)
    1144             :     {
    1145           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    1146             :                  "Unable to set metadata on read-only file.");
    1147           0 :         return CE_Failure;
    1148             :     }
    1149             : 
    1150             :     try
    1151             :     {
    1152           5 :         poFile->SetMetadataValue(pszName, pszValue);
    1153             :     }
    1154           0 :     catch (const PCIDSKException &ex)
    1155             :     {
    1156           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1157           0 :         return CE_Failure;
    1158             :     }
    1159             : 
    1160           5 :     return CE_None;
    1161             : }
    1162             : 
    1163             : /************************************************************************/
    1164             : /*                       GetMetadataDomainList()                        */
    1165             : /************************************************************************/
    1166             : 
    1167           0 : char **PCIDSK2Dataset::GetMetadataDomainList()
    1168             : {
    1169           0 :     return BuildMetadataDomainList(GDALPamDataset::GetMetadataDomainList(),
    1170           0 :                                    TRUE, "", nullptr);
    1171             : }
    1172             : 
    1173             : /************************************************************************/
    1174             : /*                          GetMetadataItem()                           */
    1175             : /************************************************************************/
    1176             : 
    1177        1300 : const char *PCIDSK2Dataset::GetMetadataItem(const char *pszName,
    1178             :                                             const char *pszDomain)
    1179             : 
    1180             : {
    1181             :     /* -------------------------------------------------------------------- */
    1182             :     /*      PCIDSK only supports metadata in the default domain.            */
    1183             :     /* -------------------------------------------------------------------- */
    1184        1300 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
    1185          95 :         return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
    1186             : 
    1187             :     /* -------------------------------------------------------------------- */
    1188             :     /*      Try and fetch (use cached value if available)                   */
    1189             :     /* -------------------------------------------------------------------- */
    1190        1205 :     auto oIter = m_oCacheMetadataItem.find(pszName);
    1191        1205 :     if (oIter != m_oCacheMetadataItem.end())
    1192             :     {
    1193        1086 :         return oIter->second.empty() ? nullptr : oIter->second.c_str();
    1194             :     }
    1195             : 
    1196         238 :     CPLString osValue;
    1197             :     try
    1198             :     {
    1199         119 :         osValue = poFile->GetMetadataValue(pszName);
    1200             :     }
    1201           0 :     catch (const PCIDSKException &ex)
    1202             :     {
    1203           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1204           0 :         return nullptr;
    1205             :     }
    1206             : 
    1207         119 :     oIter = m_oCacheMetadataItem
    1208         119 :                 .insert(std::pair<std::string, std::string>(pszName, osValue))
    1209             :                 .first;
    1210         119 :     return oIter->second.empty() ? nullptr : oIter->second.c_str();
    1211             : }
    1212             : 
    1213             : /************************************************************************/
    1214             : /*                            GetMetadata()                             */
    1215             : /************************************************************************/
    1216             : 
    1217          52 : CSLConstList PCIDSK2Dataset::GetMetadata(const char *pszDomain)
    1218             : 
    1219             : {
    1220             :     /* -------------------------------------------------------------------- */
    1221             :     /*      PCIDSK only supports metadata in the default domain.            */
    1222             :     /* -------------------------------------------------------------------- */
    1223          52 :     if (pszDomain != nullptr && strlen(pszDomain) > 0)
    1224          25 :         return GDALPamDataset::GetMetadata(pszDomain);
    1225             : 
    1226             :     /* -------------------------------------------------------------------- */
    1227             :     /*      If we have a cached result, just use that.                      */
    1228             :     /* -------------------------------------------------------------------- */
    1229          27 :     if (papszLastMDListValue != nullptr)
    1230           3 :         return papszLastMDListValue;
    1231             : 
    1232             :     /* -------------------------------------------------------------------- */
    1233             :     /*      Fetch and build the list.                                       */
    1234             :     /* -------------------------------------------------------------------- */
    1235             :     try
    1236             :     {
    1237          48 :         std::vector<std::string> aosKeys = poFile->GetMetadataKeys();
    1238             : 
    1239          38 :         for (unsigned int i = 0; i < aosKeys.size(); i++)
    1240             :         {
    1241          14 :             if (aosKeys[i].c_str()[0] == '_')
    1242           2 :                 continue;
    1243             : 
    1244          12 :             papszLastMDListValue =
    1245          12 :                 CSLSetNameValue(papszLastMDListValue, aosKeys[i].c_str(),
    1246          24 :                                 poFile->GetMetadataValue(aosKeys[i]).c_str());
    1247             :         }
    1248             :     }
    1249           0 :     catch (const PCIDSKException &ex)
    1250             :     {
    1251           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1252           0 :         return nullptr;
    1253             :     }
    1254             : 
    1255          24 :     return papszLastMDListValue;
    1256             : }
    1257             : 
    1258             : /************************************************************************/
    1259             : /*                          SetGeoTransform()                           */
    1260             : /************************************************************************/
    1261             : 
    1262          58 : CPLErr PCIDSK2Dataset::SetGeoTransform(const GDALGeoTransform &gt)
    1263             : {
    1264          58 :     PCIDSKGeoref *poGeoref = nullptr;
    1265             :     try
    1266             :     {
    1267          58 :         PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
    1268          58 :         poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
    1269             :     }
    1270           0 :     catch (const PCIDSKException &)
    1271             :     {
    1272             :         // I should really check whether this is an expected issue.
    1273             :     }
    1274             : 
    1275          58 :     if (poGeoref == nullptr)
    1276           0 :         return GDALPamDataset::SetGeoTransform(gt);
    1277             : 
    1278          58 :     if (GetAccess() == GA_ReadOnly)
    1279             :     {
    1280           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    1281             :                  "Unable to set GeoTransform on read-only file.");
    1282           0 :         return CE_Failure;
    1283             :     }
    1284             : 
    1285             :     try
    1286             :     {
    1287          58 :         poGeoref->WriteSimple(poGeoref->GetGeosys(), gt.xorig, gt.xscale,
    1288          58 :                               gt.xrot, gt.yorig, gt.yrot, gt.yscale);
    1289             :     }
    1290           0 :     catch (const PCIDSKException &ex)
    1291             :     {
    1292           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1293           0 :         return CE_Failure;
    1294             :     }
    1295             : 
    1296          58 :     return CE_None;
    1297             : }
    1298             : 
    1299             : /************************************************************************/
    1300             : /*                          GetGeoTransform()                           */
    1301             : /************************************************************************/
    1302             : 
    1303          44 : CPLErr PCIDSK2Dataset::GetGeoTransform(GDALGeoTransform &gt) const
    1304             : {
    1305          44 :     PCIDSKGeoref *poGeoref = nullptr;
    1306             :     try
    1307             :     {
    1308          44 :         PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
    1309          44 :         poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
    1310             :     }
    1311           0 :     catch (const PCIDSKException &)
    1312             :     {
    1313             :         // I should really check whether this is an expected issue.
    1314             :     }
    1315             : 
    1316          44 :     if (poGeoref != nullptr)
    1317             :     {
    1318             :         try
    1319             :         {
    1320          44 :             poGeoref->GetTransform(gt.xorig, gt.xscale, gt.xrot, gt.yorig,
    1321          44 :                                    gt.yrot, gt.yscale);
    1322             :         }
    1323           0 :         catch (const PCIDSKException &ex)
    1324             :         {
    1325           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1326           0 :             return CE_Failure;
    1327             :         }
    1328             : 
    1329             :         // If we got anything non-default return it.
    1330          44 :         if (gt != GDALGeoTransform())
    1331          41 :             return CE_None;
    1332             :     }
    1333             : 
    1334             :     /* -------------------------------------------------------------------- */
    1335             :     /*      Check for worldfile if we have no other georeferencing.         */
    1336             :     /* -------------------------------------------------------------------- */
    1337           3 :     if (GDALReadWorldFile(GetDescription(), "pxw", gt.data()))
    1338           0 :         return CE_None;
    1339             : 
    1340           3 :     return GDALPamDataset::GetGeoTransform(gt);
    1341             : }
    1342             : 
    1343             : /************************************************************************/
    1344             : /*                           SetSpatialRef()                            */
    1345             : /************************************************************************/
    1346             : 
    1347          58 : CPLErr PCIDSK2Dataset::SetSpatialRef(const OGRSpatialReference *poSRS)
    1348             : 
    1349             : {
    1350          58 :     PCIDSKGeoref *poGeoref = nullptr;
    1351             : 
    1352             :     try
    1353             :     {
    1354          58 :         PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
    1355          58 :         poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
    1356             :     }
    1357           0 :     catch (const PCIDSKException &)
    1358             :     {
    1359             :         // I should really check whether this is an expected issue.
    1360             :     }
    1361             : 
    1362          58 :     if (poGeoref == nullptr)
    1363             :     {
    1364           0 :         return GDALPamDataset::SetSpatialRef(poSRS);
    1365             :     }
    1366             : 
    1367          58 :     char *pszGeosys = nullptr;
    1368          58 :     char *pszUnits = nullptr;
    1369          58 :     double *padfPrjParams = nullptr;
    1370             : 
    1371          58 :     if (poSRS == nullptr || poSRS->exportToPCI(&pszGeosys, &pszUnits,
    1372             :                                                &padfPrjParams) != OGRERR_NONE)
    1373             :     {
    1374           0 :         return GDALPamDataset::SetSpatialRef(poSRS);
    1375             :     }
    1376             : 
    1377          58 :     if (GetAccess() == GA_ReadOnly)
    1378             :     {
    1379           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    1380             :                  "Unable to set projection on read-only file.");
    1381           0 :         CPLFree(pszGeosys);
    1382           0 :         CPLFree(pszUnits);
    1383           0 :         CPLFree(padfPrjParams);
    1384           0 :         return CE_Failure;
    1385             :     }
    1386             : 
    1387             :     try
    1388             :     {
    1389          58 :         GDALGeoTransform gt;
    1390          58 :         poGeoref->GetTransform(gt.xorig, gt.xscale, gt.xrot, gt.yorig, gt.yrot,
    1391          58 :                                gt.yscale);
    1392             : 
    1393          58 :         poGeoref->WriteSimple(pszGeosys, gt.xorig, gt.xscale, gt.xrot, gt.yorig,
    1394          58 :                               gt.yrot, gt.yscale);
    1395             : 
    1396         116 :         std::vector<double> adfPCIParameters;
    1397        1044 :         for (unsigned int i = 0; i < 17; i++)
    1398         986 :             adfPCIParameters.push_back(padfPrjParams[i]);
    1399             : 
    1400          58 :         if (STARTS_WITH_CI(pszUnits, "FOOT"))
    1401           0 :             adfPCIParameters.push_back(
    1402           0 :                 static_cast<double>(static_cast<int>(PCIDSK::UNIT_US_FOOT)));
    1403          58 :         else if (EQUALN(pszUnits, "INTL FOOT", 9))
    1404           0 :             adfPCIParameters.push_back(
    1405           0 :                 static_cast<double>(static_cast<int>(PCIDSK::UNIT_INTL_FOOT)));
    1406          58 :         else if (EQUALN(pszUnits, "DEGREE", 6))
    1407          50 :             adfPCIParameters.push_back(
    1408          50 :                 static_cast<double>(static_cast<int>(PCIDSK::UNIT_DEGREE)));
    1409             :         else
    1410           8 :             adfPCIParameters.push_back(
    1411           8 :                 static_cast<double>(static_cast<int>(PCIDSK::UNIT_METER)));
    1412             : 
    1413          58 :         poGeoref->WriteParameters(adfPCIParameters);
    1414             :     }
    1415           0 :     catch (const PCIDSKException &ex)
    1416             :     {
    1417           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1418           0 :         return CE_Failure;
    1419             :     }
    1420             : 
    1421          58 :     CPLFree(pszGeosys);
    1422          58 :     CPLFree(pszUnits);
    1423          58 :     CPLFree(padfPrjParams);
    1424             : 
    1425          58 :     return CE_None;
    1426             : }
    1427             : 
    1428             : /************************************************************************/
    1429             : /*                           GetSpatialRef()                            */
    1430             : /************************************************************************/
    1431             : 
    1432          10 : const OGRSpatialReference *PCIDSK2Dataset::GetSpatialRef() const
    1433             : {
    1434          10 :     return GetSpatialRef(false);
    1435             : }
    1436             : 
    1437           6 : const OGRSpatialReference *PCIDSK2Dataset::GetSpatialRefRasterOnly() const
    1438             : {
    1439           6 :     return GetSpatialRef(true);
    1440             : }
    1441             : 
    1442             : static thread_local int tlsEnableLayersInGetSpatialRefCounter = 0;
    1443             : 
    1444          16 : const OGRSpatialReference *PCIDSK2Dataset::GetSpatialRef(bool bRasterOnly) const
    1445             : {
    1446          16 :     if (tlsEnableLayersInGetSpatialRefCounter)
    1447           3 :         return nullptr;
    1448             : 
    1449          13 :     if (m_poSRS)
    1450           3 :         return m_poSRS;
    1451             : 
    1452          10 :     PCIDSKGeoref *poGeoref = nullptr;
    1453             : 
    1454             :     try
    1455             :     {
    1456          10 :         PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
    1457          10 :         poGeoref = dynamic_cast<PCIDSKGeoref *>(poGeoSeg);
    1458             :     }
    1459           0 :     catch (const PCIDSKException &)
    1460             :     {
    1461             :         // I should really check whether this is an expected issue.
    1462             :     }
    1463             : 
    1464          10 :     if (poGeoref == nullptr)
    1465             :     {
    1466           0 :         ++tlsEnableLayersInGetSpatialRefCounter;
    1467             :         const OGRSpatialReference *poRet =
    1468           0 :             (bRasterOnly) ? GDALPamDataset::GetSpatialRefRasterOnly()
    1469           0 :                           : GDALPamDataset::GetSpatialRef();
    1470           0 :         --tlsEnableLayersInGetSpatialRefCounter;
    1471           0 :         return poRet;
    1472             :     }
    1473             : 
    1474          20 :     CPLString osGeosys;
    1475          10 :     const char *pszUnits = nullptr;
    1476             : 
    1477          20 :     std::vector<double> adfParameters;
    1478          10 :     adfParameters.resize(18);
    1479             : 
    1480             :     try
    1481             :     {
    1482          10 :         osGeosys = poGeoref->GetGeosys();
    1483          10 :         adfParameters = poGeoref->GetParameters();
    1484             :         const UnitCode code =
    1485          10 :             static_cast<UnitCode>(static_cast<int>(adfParameters[16]));
    1486             : 
    1487          10 :         if (code == PCIDSK::UNIT_DEGREE)
    1488           0 :             pszUnits = "DEGREE";
    1489          10 :         else if (code == PCIDSK::UNIT_METER)
    1490           0 :             pszUnits = "METER";
    1491          10 :         else if (code == PCIDSK::UNIT_US_FOOT)
    1492           0 :             pszUnits = "FOOT";
    1493          10 :         else if (code == PCIDSK::UNIT_INTL_FOOT)
    1494           0 :             pszUnits = "INTL FOOT";
    1495             :     }
    1496           0 :     catch (const PCIDSKException &ex)
    1497             :     {
    1498           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1499             :     }
    1500             : 
    1501          20 :     OGRSpatialReference oSRS;
    1502          10 :     oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    1503          10 :     if (oSRS.importFromPCI(osGeosys, pszUnits, &(adfParameters[0])) ==
    1504             :         OGRERR_NONE)
    1505             :     {
    1506           7 :         m_poSRS = oSRS.Clone();
    1507           7 :         return m_poSRS;
    1508             :     }
    1509             :     else
    1510             :     {
    1511           3 :         ++tlsEnableLayersInGetSpatialRefCounter;
    1512             :         const OGRSpatialReference *poRet =
    1513           3 :             (bRasterOnly) ? GDALPamDataset::GetSpatialRefRasterOnly()
    1514           0 :                           : GDALPamDataset::GetSpatialRef();
    1515           3 :         --tlsEnableLayersInGetSpatialRefCounter;
    1516           3 :         return poRet;
    1517             :     }
    1518             : }
    1519             : 
    1520             : /************************************************************************/
    1521             : /*                          IBuildOverviews()                           */
    1522             : /************************************************************************/
    1523             : 
    1524           3 : CPLErr PCIDSK2Dataset::IBuildOverviews(
    1525             :     const char *pszResampling, int nOverviews, const int *panOverviewList,
    1526             :     int nListBands, const int *panBandList, GDALProgressFunc pfnProgress,
    1527             :     void *pProgressData, CSLConstList papszOptions)
    1528             : 
    1529             : {
    1530             :     PCIDSK2Band *poBand =
    1531           3 :         reinterpret_cast<PCIDSK2Band *>(GetRasterBand(panBandList[0]));
    1532             : 
    1533             :     /* -------------------------------------------------------------------- */
    1534             :     /*      If RRD overviews requested, then invoke generic handling.       */
    1535             :     /* -------------------------------------------------------------------- */
    1536           3 :     bool bUseGenericHandling = false;
    1537             : 
    1538           3 :     if (CPLTestBool(CPLGetConfigOption("USE_RRD", "NO")))
    1539             :     {
    1540           1 :         bUseGenericHandling = true;
    1541             :     }
    1542             : 
    1543             :     /* -------------------------------------------------------------------- */
    1544             :     /*      If we don't have read access, then create the overviews         */
    1545             :     /*      externally.                                                     */
    1546             :     /* -------------------------------------------------------------------- */
    1547           3 :     if (GetAccess() != GA_Update)
    1548             :     {
    1549           1 :         CPLDebug("PCIDSK", "File open for read-only accessing, "
    1550             :                            "creating overviews externally.");
    1551             : 
    1552           1 :         bUseGenericHandling = true;
    1553             :     }
    1554             : 
    1555           3 :     if (bUseGenericHandling)
    1556             :     {
    1557           2 :         if (poBand->GetOverviewCount() != 0)
    1558             :         {
    1559           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    1560             :                      "Cannot add external overviews when there are already "
    1561             :                      "internal overviews");
    1562           0 :             return CE_Failure;
    1563             :         }
    1564             : 
    1565           2 :         return GDALDataset::IBuildOverviews(
    1566             :             pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
    1567           2 :             pfnProgress, pProgressData, papszOptions);
    1568             :     }
    1569             : 
    1570           1 :     if (nListBands == 0)
    1571           0 :         return CE_None;
    1572             : 
    1573             :     /* -------------------------------------------------------------------- */
    1574             :     /*      Currently no support for clearing overviews.                    */
    1575             :     /* -------------------------------------------------------------------- */
    1576           1 :     if (nOverviews == 0)
    1577             :     {
    1578           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1579             :                  "PCIDSK2 driver does not currently support clearing existing "
    1580             :                  "overviews. ");
    1581           0 :         return CE_Failure;
    1582             :     }
    1583             : 
    1584             :     /* -------------------------------------------------------------------- */
    1585             :     /*      Establish which of the overview levels we already have, and     */
    1586             :     /*      which are new.  We assume that band 1 of the file is            */
    1587             :     /*      representative.                                                 */
    1588             :     /* -------------------------------------------------------------------- */
    1589             : 
    1590           1 :     int nNewOverviews = 0;
    1591             :     int *panNewOverviewList =
    1592           1 :         static_cast<int *>(CPLCalloc(sizeof(int), nOverviews));
    1593           2 :     std::vector<bool> abFoundOverviewFactor(nOverviews);
    1594           2 :     for (int i = 0; i < nOverviews && poBand != nullptr; i++)
    1595             :     {
    1596           1 :         for (int j = 0; j < poBand->GetOverviewCount(); j++)
    1597             :         {
    1598           0 :             GDALRasterBand *poOverview = poBand->GetOverview(j);
    1599             : 
    1600             :             int nOvFactor =
    1601           0 :                 GDALComputeOvFactor(poOverview->GetXSize(), poBand->GetXSize(),
    1602             :                                     poOverview->GetYSize(), poBand->GetYSize());
    1603             : 
    1604           0 :             if (nOvFactor == panOverviewList[i] ||
    1605           0 :                 nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
    1606             :                                                 poBand->GetXSize(),
    1607             :                                                 poBand->GetYSize()))
    1608           0 :                 abFoundOverviewFactor[i] = true;
    1609             :         }
    1610             : 
    1611           1 :         if (!abFoundOverviewFactor[i])
    1612           1 :             panNewOverviewList[nNewOverviews++] = panOverviewList[i];
    1613             :     }
    1614             : 
    1615             :     /* -------------------------------------------------------------------- */
    1616             :     /*      Create the overviews that are missing.                          */
    1617             :     /* -------------------------------------------------------------------- */
    1618           2 :     for (int i = 0; i < nNewOverviews; i++)
    1619             :     {
    1620             :         try
    1621             :         {
    1622             :             // conveniently our resampling values mostly match PCIDSK.
    1623           2 :             poFile->CreateOverviews(nListBands, panBandList,
    1624           2 :                                     panNewOverviewList[i], pszResampling);
    1625             :         }
    1626           0 :         catch (const PCIDSKException &ex)
    1627             :         {
    1628           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1629           0 :             CPLFree(panNewOverviewList);
    1630           0 :             return CE_Failure;
    1631             :         }
    1632             :     }
    1633             : 
    1634           1 :     CPLFree(panNewOverviewList);
    1635           1 :     panNewOverviewList = nullptr;
    1636             : 
    1637           2 :     for (int iBand = 0; iBand < nListBands; iBand++)
    1638             :     {
    1639             :         poBand =
    1640           1 :             reinterpret_cast<PCIDSK2Band *>(GetRasterBand(panBandList[iBand]));
    1641           1 :         reinterpret_cast<PCIDSK2Band *>(poBand)->RefreshOverviewList();
    1642             :     }
    1643             : 
    1644             :     /* -------------------------------------------------------------------- */
    1645             :     /*      Actually generate the overview imagery.                         */
    1646             :     /* -------------------------------------------------------------------- */
    1647           1 :     CPLErr eErr = CE_None;
    1648           1 :     std::vector<int> anRegenLevels;
    1649             : 
    1650             :     GDALRasterBand **papoOverviewBands = reinterpret_cast<GDALRasterBand **>(
    1651           1 :         CPLCalloc(sizeof(void *), nOverviews));
    1652             : 
    1653           2 :     for (int iBand = 0; iBand < nListBands && eErr == CE_None; iBand++)
    1654             :     {
    1655           1 :         nNewOverviews = 0;
    1656             : 
    1657             :         poBand =
    1658           1 :             reinterpret_cast<PCIDSK2Band *>(GetRasterBand(panBandList[iBand]));
    1659             : 
    1660           2 :         for (int i = 0; i < nOverviews && poBand != nullptr; i++)
    1661             :         {
    1662           1 :             for (int j = 0; j < poBand->GetOverviewCount(); j++)
    1663             :             {
    1664           1 :                 GDALRasterBand *poOverview = poBand->GetOverview(j);
    1665             : 
    1666           1 :                 int nOvFactor = GDALComputeOvFactor(
    1667             :                     poOverview->GetXSize(), poBand->GetXSize(),
    1668             :                     poOverview->GetYSize(), poBand->GetYSize());
    1669             : 
    1670           1 :                 if (nOvFactor == panOverviewList[i] ||
    1671           0 :                     nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
    1672             :                                                     poBand->GetXSize(),
    1673             :                                                     poBand->GetYSize()))
    1674             :                 {
    1675           1 :                     papoOverviewBands[nNewOverviews++] = poOverview;
    1676           1 :                     anRegenLevels.push_back(j);
    1677           1 :                     break;
    1678             :                 }
    1679             :             }
    1680             :         }
    1681             : 
    1682           1 :         if (nNewOverviews > 0)
    1683             :         {
    1684           1 :             eErr = GDALRegenerateOverviewsEx(
    1685             :                 (GDALRasterBandH)poBand, nNewOverviews,
    1686             :                 reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
    1687             :                 pszResampling, pfnProgress, pProgressData, papszOptions);
    1688             : 
    1689             :             // Mark the regenerated overviews as valid.
    1690           2 :             for (int i = 0; i < static_cast<int>(anRegenLevels.size()); i++)
    1691           1 :                 poBand->poChannel->SetOverviewValidity(anRegenLevels[i], true);
    1692             :         }
    1693             :     }
    1694             : 
    1695           1 :     CPLFree(papoOverviewBands);
    1696             : 
    1697           1 :     return eErr;
    1698             : }
    1699             : 
    1700             : /************************************************************************/
    1701             : /*                          PCIDSKTypeToGDAL()                          */
    1702             : /************************************************************************/
    1703             : 
    1704         481 : GDALDataType PCIDSK2Dataset::PCIDSKTypeToGDAL(eChanType eType)
    1705             : {
    1706         481 :     switch (eType)
    1707             :     {
    1708         343 :         case CHN_8U:
    1709         343 :             return GDT_UInt8;
    1710             : 
    1711          66 :         case CHN_16U:
    1712          66 :             return GDT_UInt16;
    1713             : 
    1714          18 :         case CHN_16S:
    1715          18 :             return GDT_Int16;
    1716             : 
    1717          18 :         case CHN_32R:
    1718          18 :             return GDT_Float32;
    1719             : 
    1720           0 :         case CHN_BIT:
    1721           0 :             return GDT_UInt8;
    1722             : 
    1723           0 :         case CHN_C16U:
    1724           0 :             return GDT_CInt16;
    1725             : 
    1726          18 :         case CHN_C16S:
    1727          18 :             return GDT_CInt16;
    1728             : 
    1729          18 :         case CHN_C32R:
    1730          18 :             return GDT_CFloat32;
    1731             : 
    1732           0 :         default:
    1733           0 :             return GDT_Unknown;
    1734             :     }
    1735             : }
    1736             : 
    1737             : /************************************************************************/
    1738             : /*                                Open()                                */
    1739             : /************************************************************************/
    1740             : 
    1741         137 : GDALDataset *PCIDSK2Dataset::Open(GDALOpenInfo *poOpenInfo)
    1742             : {
    1743         137 :     if (!PCIDSKDriverIdentify(poOpenInfo))
    1744           0 :         return nullptr;
    1745             : 
    1746             :     /* -------------------------------------------------------------------- */
    1747             :     /*      Try opening the file.                                           */
    1748             :     /* -------------------------------------------------------------------- */
    1749         137 :     PCIDSKFile *poFile = nullptr;
    1750             :     const int nMaxBandCount =
    1751         137 :         atoi(CPLGetConfigOption("GDAL_MAX_BAND_COUNT", "65536"));
    1752             :     try
    1753             :     {
    1754         278 :         poFile = PCIDSK::Open(poOpenInfo->pszFilename,
    1755         137 :                               poOpenInfo->eAccess == GA_ReadOnly ? "r" : "r+",
    1756             :                               PCIDSK2GetInterfaces(), nMaxBandCount);
    1757         136 :         if (poFile == nullptr)
    1758             :         {
    1759           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
    1760             :                      "Failed to re-open %s within PCIDSK driver.\n",
    1761             :                      poOpenInfo->pszFilename);
    1762           0 :             return nullptr;
    1763             :         }
    1764             : 
    1765             :         const bool bValidRasterDimensions =
    1766         136 :             poFile->GetWidth() && poFile->GetHeight();
    1767         136 :         if (!bValidRasterDimensions &&
    1768           0 :             (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
    1769           0 :             (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) == 0)
    1770             :         {
    1771           0 :             delete poFile;
    1772           0 :             return nullptr;
    1773             :         }
    1774             : 
    1775             :         /* Check if this is a vector-only PCIDSK file and that we are */
    1776             :         /* opened in raster-only mode */
    1777         400 :         if (poOpenInfo->eAccess == GA_ReadOnly &&
    1778         128 :             (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
    1779         118 :             (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) == 0 &&
    1780         267 :             poFile->GetChannels() == 0 &&
    1781         139 :             poFile->GetSegment(PCIDSK::SEG_VEC, "") != nullptr)
    1782             :         {
    1783           2 :             CPLDebug("PCIDSK",
    1784             :                      "This is a vector-only PCIDSK dataset, "
    1785             :                      "but it has been opened in read-only in raster-only mode");
    1786           2 :             delete poFile;
    1787           2 :             return nullptr;
    1788             :         }
    1789             :         /* Reverse test */
    1790         394 :         if (poOpenInfo->eAccess == GA_ReadOnly &&
    1791         126 :             (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
    1792          10 :             (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0 &&
    1793         260 :             poFile->GetChannels() != 0 &&
    1794         134 :             poFile->GetSegment(PCIDSK::SEG_VEC, "") == nullptr)
    1795             :         {
    1796           0 :             CPLDebug("PCIDSK",
    1797             :                      "This is a raster-only PCIDSK dataset, "
    1798             :                      "but it has been opened in read-only in vector-only mode");
    1799           0 :             delete poFile;
    1800           0 :             return nullptr;
    1801             :         }
    1802             : 
    1803         134 :         return LLOpen(poOpenInfo->pszFilename, poFile, poOpenInfo->eAccess,
    1804         134 :                       poOpenInfo->GetSiblingFiles());
    1805             :     }
    1806             :     /* -------------------------------------------------------------------- */
    1807             :     /*      Trap exceptions.                                                */
    1808             :     /* -------------------------------------------------------------------- */
    1809           1 :     catch (const PCIDSKException &ex)
    1810             :     {
    1811           1 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1812           1 :         delete poFile;
    1813           1 :         return nullptr;
    1814             :     }
    1815           0 :     catch (...)
    1816             :     {
    1817           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1818             :                  "PCIDSK::Create() failed, unexpected exception.");
    1819           0 :         delete poFile;
    1820           0 :         return nullptr;
    1821             :     }
    1822             : }
    1823             : 
    1824             : /************************************************************************/
    1825             : /*                               LLOpen()                               */
    1826             : /*                                                                      */
    1827             : /*      Low level variant of open that takes the preexisting            */
    1828             : /*      PCIDSKFile.                                                     */
    1829             : /************************************************************************/
    1830             : 
    1831         245 : GDALDataset *PCIDSK2Dataset::LLOpen(const char *pszFilename,
    1832             :                                     PCIDSK::PCIDSKFile *poFile,
    1833             :                                     GDALAccess eAccessIn,
    1834             :                                     char **papszSiblingFiles)
    1835             : 
    1836             : {
    1837         245 :     PCIDSK2Dataset *poDS = new PCIDSK2Dataset();
    1838             :     /* -------------------------------------------------------------------- */
    1839             :     /*      Create a corresponding GDALDataset.                             */
    1840             :     /* -------------------------------------------------------------------- */
    1841         245 :     poDS->poFile = poFile;
    1842         245 :     poDS->eAccess = eAccessIn;
    1843         245 :     poDS->nRasterXSize = poFile->GetWidth();
    1844         245 :     poDS->nRasterYSize = poFile->GetHeight();
    1845             : 
    1846             :     const bool bValidRasterDimensions =
    1847         245 :         poFile->GetWidth() && poFile->GetHeight();
    1848         245 :     if (!bValidRasterDimensions)
    1849             :     {
    1850           0 :         poDS->nRasterXSize = 512;
    1851           0 :         poDS->nRasterYSize = 512;
    1852             :     }
    1853             : 
    1854             :     try
    1855             :     {
    1856             : 
    1857             :         /* --------------------------------------------------------------------
    1858             :          */
    1859             :         /*      Are we specifically PIXEL or BAND interleaving? */
    1860             :         /*                                                                      */
    1861             :         /*      We don't set anything for FILE since it is harder to know if */
    1862             :         /*      this is tiled or what the on disk interleaving is. */
    1863             :         /* --------------------------------------------------------------------
    1864             :          */
    1865         245 :         if (EQUAL(poFile->GetInterleaving().c_str(), "PIXEL"))
    1866           0 :             poDS->SetMetadataItem("IMAGE_STRUCTURE", "PIXEL",
    1867             :                                   "IMAGE_STRUCTURE");
    1868         245 :         else if (EQUAL(poFile->GetInterleaving().c_str(), "BAND"))
    1869         217 :             poDS->SetMetadataItem("IMAGE_STRUCTURE", "BAND", "IMAGE_STRUCTURE");
    1870             : 
    1871             :         /* --------------------------------------------------------------------
    1872             :          */
    1873             :         /*      Create band objects. */
    1874             :         /* --------------------------------------------------------------------
    1875             :          */
    1876         480 :         for (int iBand = 0;
    1877         480 :              bValidRasterDimensions && iBand < poFile->GetChannels(); iBand++)
    1878             :         {
    1879         235 :             PCIDSKChannel *poChannel = poFile->GetChannel(iBand + 1);
    1880         470 :             if (poChannel->GetBlockWidth() <= 0 ||
    1881         235 :                 poChannel->GetBlockHeight() <= 0)
    1882             :             {
    1883           0 :                 delete poDS;
    1884           0 :                 return nullptr;
    1885             :             }
    1886             : 
    1887         235 :             if (PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType()) ==
    1888             :                 GDT_Unknown)
    1889             :             {
    1890           0 :                 continue;
    1891             :             }
    1892             : 
    1893         235 :             poDS->SetBand(poDS->GetRasterCount() + 1,
    1894         235 :                           new PCIDSK2Band(poFile, poChannel));
    1895             :         }
    1896             : 
    1897             :         /* --------------------------------------------------------------------
    1898             :          */
    1899             :         /*      Create band objects for bitmap segments. */
    1900             :         /* --------------------------------------------------------------------
    1901             :          */
    1902         245 :         int nLastBitmapSegment = 0;
    1903         245 :         PCIDSKSegment *poBitSeg = nullptr;
    1904             : 
    1905         490 :         while (bValidRasterDimensions &&
    1906         490 :                (poBitSeg = poFile->GetSegment(SEG_BIT, "",
    1907         245 :                                               nLastBitmapSegment)) != nullptr)
    1908             :         {
    1909           0 :             PCIDSKChannel *poChannel = dynamic_cast<PCIDSKChannel *>(poBitSeg);
    1910           0 :             if (poChannel == nullptr || poChannel->GetBlockWidth() <= 0 ||
    1911           0 :                 poChannel->GetBlockHeight() <= 0)
    1912             :             {
    1913           0 :                 delete poDS;
    1914           0 :                 return nullptr;
    1915             :             }
    1916             : 
    1917           0 :             if (PCIDSK2Dataset::PCIDSKTypeToGDAL(poChannel->GetType()) ==
    1918             :                 GDT_Unknown)
    1919             :             {
    1920           0 :                 continue;
    1921             :             }
    1922             : 
    1923           0 :             poDS->SetBand(poDS->GetRasterCount() + 1,
    1924           0 :                           new PCIDSK2Band(poChannel));
    1925             : 
    1926           0 :             nLastBitmapSegment = poBitSeg->GetSegmentNumber();
    1927             :         }
    1928             : 
    1929             :         /* --------------------------------------------------------------------
    1930             :          */
    1931             :         /*      Create vector layers from vector segments. */
    1932             :         /* --------------------------------------------------------------------
    1933             :          */
    1934         245 :         PCIDSK::PCIDSKSegment *segobj = poFile->GetSegment(PCIDSK::SEG_VEC, "");
    1935         340 :         for (; segobj != nullptr;
    1936          95 :              segobj = poFile->GetSegment(PCIDSK::SEG_VEC, "",
    1937          95 :                                          segobj->GetSegmentNumber()))
    1938             :         {
    1939             :             PCIDSK::PCIDSKVectorSegment *poVecSeg =
    1940          95 :                 dynamic_cast<PCIDSK::PCIDSKVectorSegment *>(segobj);
    1941          95 :             if (poVecSeg)
    1942          95 :                 poDS->apoLayers.push_back(new OGRPCIDSKLayer(
    1943          95 :                     poDS, segobj, poVecSeg, eAccessIn == GA_Update));
    1944             :         }
    1945             : 
    1946             :         /* --------------------------------------------------------------------
    1947             :          */
    1948             :         /*      Process RPC segment, if there is one. */
    1949             :         /* --------------------------------------------------------------------
    1950             :          */
    1951         245 :         poDS->ProcessRPC();
    1952             : 
    1953             :         /* --------------------------------------------------------------------
    1954             :          */
    1955             :         /*      Initialize any PAM information. */
    1956             :         /* --------------------------------------------------------------------
    1957             :          */
    1958         245 :         poDS->SetDescription(pszFilename);
    1959         245 :         poDS->TryLoadXML(papszSiblingFiles);
    1960             : 
    1961             :         /* --------------------------------------------------------------------
    1962             :          */
    1963             :         /*      Open overviews. */
    1964             :         /* --------------------------------------------------------------------
    1965             :          */
    1966         245 :         poDS->oOvManager.Initialize(poDS, pszFilename, papszSiblingFiles);
    1967             : 
    1968         245 :         return poDS;
    1969             :     }
    1970             : 
    1971             :     /* -------------------------------------------------------------------- */
    1972             :     /*      Trap exceptions.                                                */
    1973             :     /* -------------------------------------------------------------------- */
    1974           0 :     catch (const PCIDSKException &ex)
    1975             :     {
    1976           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    1977             :     }
    1978           0 :     catch (...)
    1979             :     {
    1980           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1981             :                  "PCIDSK SDK Failure in Open(), unexpected exception.");
    1982             :     }
    1983             : 
    1984             :     /* -------------------------------------------------------------------- */
    1985             :     /*      In case of exception, close dataset                             */
    1986             :     /* -------------------------------------------------------------------- */
    1987           0 :     delete poDS;
    1988             : 
    1989           0 :     return nullptr;
    1990             : }
    1991             : 
    1992             : /************************************************************************/
    1993             : /*                               Create()                               */
    1994             : /************************************************************************/
    1995             : 
    1996         125 : GDALDataset *PCIDSK2Dataset::Create(const char *pszFilename, int nXSize,
    1997             :                                     int nYSize, int nBandsIn,
    1998             :                                     GDALDataType eType,
    1999             :                                     CSLConstList papszParamList)
    2000             : 
    2001             : {
    2002             :     /* -------------------------------------------------------------------- */
    2003             :     /*      Prepare channel type list.                                      */
    2004             :     /* -------------------------------------------------------------------- */
    2005         250 :     std::vector<eChanType> aeChanTypes;
    2006             : 
    2007         125 :     if (eType == GDT_Float32)
    2008           3 :         aeChanTypes.resize(std::max(1, nBandsIn), CHN_32R);
    2009         122 :     else if (eType == GDT_Int16)
    2010           3 :         aeChanTypes.resize(std::max(1, nBandsIn), CHN_16S);
    2011         119 :     else if (eType == GDT_UInt16)
    2012          11 :         aeChanTypes.resize(std::max(1, nBandsIn), CHN_16U);
    2013         108 :     else if (eType == GDT_CInt16)
    2014           3 :         aeChanTypes.resize(std::max(1, nBandsIn), CHN_C16S);
    2015         105 :     else if (eType == GDT_CFloat32)
    2016           3 :         aeChanTypes.resize(std::max(1, nBandsIn), CHN_C32R);
    2017             :     else
    2018         102 :         aeChanTypes.resize(std::max(1, nBandsIn), CHN_8U);
    2019             : 
    2020             :     /* -------------------------------------------------------------------- */
    2021             :     /*      Reformat options.  Currently no support for jpeg compression    */
    2022             :     /*      quality.                                                        */
    2023             :     /* -------------------------------------------------------------------- */
    2024         250 :     CPLString osOptions;
    2025         125 :     const char *pszValue = CSLFetchNameValue(papszParamList, "INTERLEAVING");
    2026         125 :     if (pszValue == nullptr)
    2027         117 :         pszValue = "BAND";
    2028             : 
    2029         125 :     osOptions = pszValue;
    2030             : 
    2031         125 :     if (osOptions == "TILED")
    2032             :     {
    2033           7 :         pszValue = CSLFetchNameValue(papszParamList, "TILESIZE");
    2034           7 :         if (pszValue != nullptr)
    2035           6 :             osOptions += pszValue;
    2036             : 
    2037           7 :         pszValue = CSLFetchNameValue(papszParamList, "COMPRESSION");
    2038           7 :         if (pszValue != nullptr)
    2039             :         {
    2040           4 :             osOptions += " ";
    2041           4 :             osOptions += pszValue;
    2042             :         }
    2043             : 
    2044           7 :         pszValue = CSLFetchNameValue(papszParamList, "TILEVERSION");
    2045           7 :         if (pszValue != nullptr)
    2046             :         {
    2047           4 :             osOptions += " TILEV";
    2048           4 :             osOptions += pszValue;
    2049             :         }
    2050             :     }
    2051             : 
    2052             :     /* -------------------------------------------------------------------- */
    2053             :     /*      Try creation.                                                   */
    2054             :     /* -------------------------------------------------------------------- */
    2055             : 
    2056             :     try
    2057             :     {
    2058         125 :         if (nBandsIn == 0)
    2059             :         {
    2060          43 :             nXSize = 512;
    2061          43 :             nYSize = 512;
    2062             :         }
    2063         278 :         PCIDSKFile *poFile = PCIDSK::Create(pszFilename, nXSize, nYSize,
    2064         125 :                                             nBandsIn, &(aeChanTypes[0]),
    2065             :                                             osOptions, PCIDSK2GetInterfaces());
    2066             : 
    2067             :         /* --------------------------------------------------------------------
    2068             :          */
    2069             :         /*      Apply band descriptions, if provided as creation options. */
    2070             :         /* --------------------------------------------------------------------
    2071             :          */
    2072         133 :         for (size_t i = 0;
    2073         133 :              papszParamList != nullptr && papszParamList[i] != nullptr; i++)
    2074             :         {
    2075          22 :             if (STARTS_WITH_CI(papszParamList[i], "BANDDESC"))
    2076             :             {
    2077           0 :                 int nBand = atoi(papszParamList[i] + 8);
    2078           0 :                 const char *pszDescription = strstr(papszParamList[i], "=");
    2079           0 :                 if (pszDescription && nBand > 0 && nBand <= nBandsIn)
    2080             :                 {
    2081           0 :                     poFile->GetChannel(nBand)->SetDescription(pszDescription +
    2082           0 :                                                               1);
    2083             :                 }
    2084             :             }
    2085             :         }
    2086             : 
    2087         111 :         return LLOpen(pszFilename, poFile, GA_Update);
    2088             :     }
    2089             :     /* -------------------------------------------------------------------- */
    2090             :     /*      Trap exceptions.                                                */
    2091             :     /* -------------------------------------------------------------------- */
    2092          28 :     catch (const PCIDSKException &ex)
    2093             :     {
    2094          14 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    2095             :     }
    2096           0 :     catch (...)
    2097             :     {
    2098           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2099             :                  "PCIDSK::Create() failed, unexpected exception.");
    2100             :     }
    2101             : 
    2102          14 :     return nullptr;
    2103             : }
    2104             : 
    2105             : /************************************************************************/
    2106             : /*                           TestCapability()                           */
    2107             : /************************************************************************/
    2108             : 
    2109          79 : int PCIDSK2Dataset::TestCapability(const char *pszCap) const
    2110             : 
    2111             : {
    2112          79 :     if (EQUAL(pszCap, ODsCCreateLayer))
    2113          37 :         return eAccess == GA_Update;
    2114          42 :     if (EQUAL(pszCap, ODsCRandomLayerWrite))
    2115           0 :         return eAccess == GA_Update;
    2116          42 :     if (EQUAL(pszCap, ODsCZGeometries))
    2117          12 :         return TRUE;
    2118             : 
    2119          30 :     return FALSE;
    2120             : }
    2121             : 
    2122             : /************************************************************************/
    2123             : /*                              GetLayer()                              */
    2124             : /************************************************************************/
    2125             : 
    2126        1655 : const OGRLayer *PCIDSK2Dataset::GetLayer(int iLayer) const
    2127             : 
    2128             : {
    2129        1655 :     if (iLayer < 0 || iLayer >= static_cast<int>(apoLayers.size()))
    2130           2 :         return nullptr;
    2131             : 
    2132        1653 :     return apoLayers[iLayer];
    2133             : }
    2134             : 
    2135             : /************************************************************************/
    2136             : /*                            ICreateLayer()                            */
    2137             : /************************************************************************/
    2138             : 
    2139        1089 : OGRLayer *PCIDSK2Dataset::ICreateLayer(const char *pszLayerName,
    2140             :                                        const OGRGeomFieldDefn *poGeomFieldDefn,
    2141             :                                        CSLConstList /*papszOptions*/)
    2142             : {
    2143             :     /* -------------------------------------------------------------------- */
    2144             :     /*      Verify we are in update mode.                                   */
    2145             :     /* -------------------------------------------------------------------- */
    2146        1089 :     if (eAccess != GA_Update)
    2147             :     {
    2148           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    2149             :                  "Data source %s opened read-only.\n"
    2150             :                  "New layer %s cannot be created.\n",
    2151           0 :                  GetDescription(), pszLayerName);
    2152           0 :         return nullptr;
    2153             :     }
    2154             : 
    2155        1089 :     const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
    2156             :     const auto poSRS =
    2157        1089 :         poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
    2158             : 
    2159             :     /* -------------------------------------------------------------------- */
    2160             :     /*      Figure out what type of layer we need.                          */
    2161             :     /* -------------------------------------------------------------------- */
    2162        2178 :     std::string osLayerType;
    2163             : 
    2164        1089 :     switch (wkbFlatten(eType))
    2165             :     {
    2166          10 :         case wkbPoint:
    2167          10 :             osLayerType = "POINTS";
    2168          10 :             break;
    2169             : 
    2170          10 :         case wkbLineString:
    2171          10 :             osLayerType = "ARCS";
    2172          10 :             break;
    2173             : 
    2174           6 :         case wkbPolygon:
    2175           6 :             osLayerType = "WHOLE_POLYGONS";
    2176           6 :             break;
    2177             : 
    2178           7 :         case wkbNone:
    2179           7 :             osLayerType = "TABLE";
    2180           7 :             break;
    2181             : 
    2182        1056 :         default:
    2183        1056 :             break;
    2184             :     }
    2185             : 
    2186             :     /* -------------------------------------------------------------------- */
    2187             :     /*      Create the segment.                                             */
    2188             :     /* -------------------------------------------------------------------- */
    2189             :     int nSegNum;
    2190             :     try
    2191             :     {
    2192        1093 :         nSegNum = poFile->CreateSegment(pszLayerName, "", PCIDSK::SEG_VEC, 0L);
    2193             :     }
    2194           1 :     catch (const PCIDSKException &ex)
    2195             :     {
    2196           1 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    2197           1 :         return nullptr;
    2198             :     }
    2199        1088 :     PCIDSK::PCIDSKSegment *poSeg = poFile->GetSegment(nSegNum);
    2200             :     PCIDSK::PCIDSKVectorSegment *poVecSeg =
    2201        1088 :         dynamic_cast<PCIDSK::PCIDSKVectorSegment *>(poSeg);
    2202        1088 :     if (poVecSeg == nullptr)
    2203           0 :         return nullptr;
    2204             : 
    2205        1088 :     if (osLayerType != "")
    2206          33 :         poSeg->SetMetadataValue("LAYER_TYPE", osLayerType);
    2207             : 
    2208             :     /* -------------------------------------------------------------------- */
    2209             :     /*      Do we need to apply a coordinate system?                        */
    2210             :     /* -------------------------------------------------------------------- */
    2211        1088 :     char *pszGeosys = nullptr;
    2212        1088 :     char *pszUnits = nullptr;
    2213        1088 :     double *padfPrjParams = nullptr;
    2214             : 
    2215        1088 :     if (poSRS != nullptr && poSRS->exportToPCI(&pszGeosys, &pszUnits,
    2216             :                                                &padfPrjParams) == OGRERR_NONE)
    2217             :     {
    2218             :         try
    2219             :         {
    2220           6 :             std::vector<double> adfPCIParameters;
    2221             : 
    2222         108 :             for (int i = 0; i < 17; i++)
    2223         102 :                 adfPCIParameters.push_back(padfPrjParams[i]);
    2224             : 
    2225           6 :             if (STARTS_WITH_CI(pszUnits, "FOOT"))
    2226           0 :                 adfPCIParameters.push_back(static_cast<double>(
    2227             :                     static_cast<int>(PCIDSK::UNIT_US_FOOT)));
    2228           6 :             else if (STARTS_WITH_CI(pszUnits, "INTL FOOT"))
    2229           0 :                 adfPCIParameters.push_back(static_cast<double>(
    2230             :                     static_cast<int>(PCIDSK::UNIT_INTL_FOOT)));
    2231           6 :             else if (STARTS_WITH_CI(pszUnits, "DEGREE"))
    2232           2 :                 adfPCIParameters.push_back(
    2233           2 :                     static_cast<double>(static_cast<int>(PCIDSK::UNIT_DEGREE)));
    2234             :             else
    2235           4 :                 adfPCIParameters.push_back(
    2236           4 :                     static_cast<double>(static_cast<int>(PCIDSK::UNIT_METER)));
    2237             : 
    2238           6 :             poVecSeg->SetProjection(pszGeosys, adfPCIParameters);
    2239             :         }
    2240           0 :         catch (const PCIDSKException &ex)
    2241             :         {
    2242           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
    2243             :         }
    2244             : 
    2245           6 :         CPLFree(pszGeosys);
    2246           6 :         CPLFree(pszUnits);
    2247           6 :         CPLFree(padfPrjParams);
    2248             :     }
    2249             : 
    2250             :     /* -------------------------------------------------------------------- */
    2251             :     /*      Create the layer object.                                        */
    2252             :     /* -------------------------------------------------------------------- */
    2253             : 
    2254        1088 :     apoLayers.push_back(new OGRPCIDSKLayer(this, poSeg, poVecSeg, TRUE));
    2255             : 
    2256        1088 :     return apoLayers.back();
    2257             : }
    2258             : 
    2259             : /************************************************************************/
    2260             : /*                        GDALRegister_PCIDSK()                         */
    2261             : /************************************************************************/
    2262             : 
    2263          14 : void GDALRegister_PCIDSK()
    2264             : 
    2265             : {
    2266          14 :     if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
    2267           0 :         return;
    2268             : 
    2269          14 :     GDALDriver *poDriver = new GDALDriver();
    2270          14 :     PCIDSKDriverSetCommonMetadata(poDriver);
    2271             : 
    2272          14 :     poDriver->pfnOpen = PCIDSK2Dataset::Open;
    2273          14 :     poDriver->pfnCreate = PCIDSK2Dataset::Create;
    2274             : 
    2275          14 :     GetGDALDriverManager()->RegisterDriver(poDriver);
    2276             : }

Generated by: LCOV version 1.14