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

Generated by: LCOV version 1.14