LCOV - code coverage report
Current view: top level - frmts/raw - pauxdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 301 408 73.8 %
Date: 2024-11-21 22:18:42 Functions: 18 25 72.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  PCI .aux Driver
       4             :  * Purpose:  Implementation of PAuxDataset
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, Frank Warmerdam
       9             :  * Copyright (c) 2008-2010, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_string.h"
      15             : #include "gdal_frmts.h"
      16             : #include "ogr_spatialref.h"
      17             : #include "rawdataset.h"
      18             : 
      19             : #include <cmath>
      20             : 
      21             : /************************************************************************/
      22             : /* ==================================================================== */
      23             : /*                              PAuxDataset                             */
      24             : /* ==================================================================== */
      25             : /************************************************************************/
      26             : 
      27             : class PAuxRasterBand;
      28             : 
      29             : class PAuxDataset final : public RawDataset
      30             : {
      31             :     friend class PAuxRasterBand;
      32             : 
      33             :     VSILFILE *fpImage;  // Image data file.
      34             : 
      35             :     int nGCPCount;
      36             :     GDAL_GCP *pasGCPList;
      37             :     OGRSpatialReference m_oGCPSRS{};
      38             : 
      39             :     void ScanForGCPs();
      40             :     static OGRSpatialReference PCI2SRS(const char *pszGeosys,
      41             :                                        const char *pszProjParams);
      42             : 
      43             :     OGRSpatialReference m_oSRS{};
      44             : 
      45             :     CPL_DISALLOW_COPY_ASSIGN(PAuxDataset)
      46             : 
      47             :     CPLErr Close() override;
      48             : 
      49             :   public:
      50             :     PAuxDataset();
      51             :     ~PAuxDataset() override;
      52             : 
      53             :     // TODO(schwehr): Why are these public?
      54             :     char *pszAuxFilename;
      55             :     char **papszAuxLines;
      56             :     int bAuxUpdated;
      57             : 
      58           0 :     const OGRSpatialReference *GetSpatialRef() const override
      59             :     {
      60           0 :         return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
      61             :     }
      62             : 
      63             :     CPLErr GetGeoTransform(double *) override;
      64             :     CPLErr SetGeoTransform(double *) override;
      65             : 
      66             :     int GetGCPCount() override;
      67             : 
      68           0 :     const OGRSpatialReference *GetGCPSpatialRef() const override
      69             :     {
      70           0 :         return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
      71             :     }
      72             : 
      73             :     const GDAL_GCP *GetGCPs() override;
      74             : 
      75             :     char **GetFileList() override;
      76             : 
      77             :     static GDALDataset *Open(GDALOpenInfo *);
      78             :     static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
      79             :                                int nBandsIn, GDALDataType eType,
      80             :                                char **papszParamList);
      81             : };
      82             : 
      83             : /************************************************************************/
      84             : /* ==================================================================== */
      85             : /*                           PAuxRasterBand                             */
      86             : /* ==================================================================== */
      87             : /************************************************************************/
      88             : 
      89             : class PAuxRasterBand final : public RawRasterBand
      90             : {
      91             :     CPL_DISALLOW_COPY_ASSIGN(PAuxRasterBand)
      92             : 
      93             :   public:
      94             :     PAuxRasterBand(GDALDataset *poDS, int nBand, VSILFILE *fpRaw,
      95             :                    vsi_l_offset nImgOffset, int nPixelOffset, int nLineOffset,
      96             :                    GDALDataType eDataType, int bNativeOrder);
      97             : 
      98             :     ~PAuxRasterBand() override;
      99             : 
     100             :     double GetNoDataValue(int *pbSuccess = nullptr) override;
     101             :     CPLErr SetNoDataValue(double) override;
     102             : 
     103             :     GDALColorTable *GetColorTable() override;
     104             :     GDALColorInterp GetColorInterpretation() override;
     105             : 
     106             :     void SetDescription(const char *pszNewDescription) override;
     107             : };
     108             : 
     109             : /************************************************************************/
     110             : /*                           PAuxRasterBand()                           */
     111             : /************************************************************************/
     112             : 
     113          84 : PAuxRasterBand::PAuxRasterBand(GDALDataset *poDSIn, int nBandIn,
     114             :                                VSILFILE *fpRawIn, vsi_l_offset nImgOffsetIn,
     115             :                                int nPixelOffsetIn, int nLineOffsetIn,
     116          84 :                                GDALDataType eDataTypeIn, int bNativeOrderIn)
     117             :     : RawRasterBand(poDSIn, nBandIn, fpRawIn, nImgOffsetIn, nPixelOffsetIn,
     118             :                     nLineOffsetIn, eDataTypeIn, bNativeOrderIn,
     119          84 :                     RawRasterBand::OwnFP::NO)
     120             : {
     121          84 :     PAuxDataset *poPDS = reinterpret_cast<PAuxDataset *>(poDS);
     122             : 
     123             :     /* -------------------------------------------------------------------- */
     124             :     /*      Does this channel have a description?                           */
     125             :     /* -------------------------------------------------------------------- */
     126          84 :     char szTarget[128] = {'\0'};
     127             : 
     128          84 :     snprintf(szTarget, sizeof(szTarget), "ChanDesc-%d", nBand);
     129          84 :     if (CSLFetchNameValue(poPDS->papszAuxLines, szTarget) != nullptr)
     130           0 :         GDALRasterBand::SetDescription(
     131           0 :             CSLFetchNameValue(poPDS->papszAuxLines, szTarget));
     132             : 
     133             :     /* -------------------------------------------------------------------- */
     134             :     /*      See if we have colors.  Currently we must have color zero,      */
     135             :     /*      but this should not really be a limitation.                     */
     136             :     /* -------------------------------------------------------------------- */
     137          84 :     snprintf(szTarget, sizeof(szTarget), "METADATA_IMG_%d_Class_%d_Color",
     138             :              nBand, 0);
     139          84 :     if (CSLFetchNameValue(poPDS->papszAuxLines, szTarget) != nullptr)
     140             :     {
     141           0 :         poCT = new GDALColorTable();
     142             : 
     143           0 :         for (int i = 0; i < 256; i++)
     144             :         {
     145           0 :             snprintf(szTarget, sizeof(szTarget),
     146             :                      "METADATA_IMG_%d_Class_%d_Color", nBand, i);
     147             :             const char *pszLine =
     148           0 :                 CSLFetchNameValue(poPDS->papszAuxLines, szTarget);
     149           0 :             while (pszLine && *pszLine == ' ')
     150           0 :                 pszLine++;
     151             : 
     152           0 :             int nRed = 0;
     153           0 :             int nGreen = 0;
     154           0 :             int nBlue = 0;
     155             :             // TODO(schwehr): Replace sscanf with something safe.
     156           0 :             if (pszLine != nullptr && STARTS_WITH_CI(pszLine, "(RGB:") &&
     157           0 :                 sscanf(pszLine + 5, "%d %d %d", &nRed, &nGreen, &nBlue) == 3)
     158             :             {
     159           0 :                 GDALColorEntry oColor = {static_cast<short>(nRed),
     160             :                                          static_cast<short>(nGreen),
     161           0 :                                          static_cast<short>(nBlue), 255};
     162             : 
     163           0 :                 poCT->SetColorEntry(i, &oColor);
     164             :             }
     165             :         }
     166             :     }
     167          84 : }
     168             : 
     169             : /************************************************************************/
     170             : /*                          ~PAuxRasterBand()                           */
     171             : /************************************************************************/
     172             : 
     173         168 : PAuxRasterBand::~PAuxRasterBand()
     174             : 
     175             : {
     176         168 : }
     177             : 
     178             : /************************************************************************/
     179             : /*                           GetNoDataValue()                           */
     180             : /************************************************************************/
     181             : 
     182           8 : double PAuxRasterBand::GetNoDataValue(int *pbSuccess)
     183             : 
     184             : {
     185           8 :     char szTarget[128] = {'\0'};
     186           8 :     snprintf(szTarget, sizeof(szTarget), "METADATA_IMG_%d_NO_DATA_VALUE",
     187             :              nBand);
     188             : 
     189           8 :     PAuxDataset *poPDS = reinterpret_cast<PAuxDataset *>(poDS);
     190           8 :     const char *pszLine = CSLFetchNameValue(poPDS->papszAuxLines, szTarget);
     191             : 
     192           8 :     if (pbSuccess != nullptr)
     193           8 :         *pbSuccess = (pszLine != nullptr);
     194             : 
     195           8 :     if (pszLine == nullptr)
     196           8 :         return -1.0e8;
     197             : 
     198           0 :     return CPLAtof(pszLine);
     199             : }
     200             : 
     201             : /************************************************************************/
     202             : /*                           SetNoDataValue()                           */
     203             : /************************************************************************/
     204             : 
     205           0 : CPLErr PAuxRasterBand::SetNoDataValue(double dfNewValue)
     206             : 
     207             : {
     208           0 :     if (GetAccess() == GA_ReadOnly)
     209             :     {
     210           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
     211             :                  "Can't update readonly dataset.");
     212           0 :         return CE_Failure;
     213             :     }
     214             : 
     215           0 :     char szTarget[128] = {'\0'};
     216           0 :     char szValue[128] = {'\0'};
     217           0 :     snprintf(szTarget, sizeof(szTarget), "METADATA_IMG_%d_NO_DATA_VALUE",
     218             :              nBand);
     219           0 :     CPLsnprintf(szValue, sizeof(szValue), "%24.12f", dfNewValue);
     220             : 
     221           0 :     PAuxDataset *poPDS = reinterpret_cast<PAuxDataset *>(poDS);
     222           0 :     poPDS->papszAuxLines =
     223           0 :         CSLSetNameValue(poPDS->papszAuxLines, szTarget, szValue);
     224             : 
     225           0 :     poPDS->bAuxUpdated = TRUE;
     226             : 
     227           0 :     return CE_None;
     228             : }
     229             : 
     230             : /************************************************************************/
     231             : /*                           SetDescription()                           */
     232             : /*                                                                      */
     233             : /*      We override the set description so we can mark the auxfile      */
     234             : /*      info as changed.                                                */
     235             : /************************************************************************/
     236             : 
     237           0 : void PAuxRasterBand::SetDescription(const char *pszNewDescription)
     238             : 
     239             : {
     240           0 :     if (GetAccess() == GA_Update)
     241             :     {
     242           0 :         char szTarget[128] = {'\0'};
     243           0 :         snprintf(szTarget, sizeof(szTarget), "ChanDesc-%d", nBand);
     244             : 
     245           0 :         PAuxDataset *poPDS = reinterpret_cast<PAuxDataset *>(poDS);
     246           0 :         poPDS->papszAuxLines =
     247           0 :             CSLSetNameValue(poPDS->papszAuxLines, szTarget, pszNewDescription);
     248             : 
     249           0 :         poPDS->bAuxUpdated = TRUE;
     250             :     }
     251             : 
     252           0 :     GDALRasterBand::SetDescription(pszNewDescription);
     253           0 : }
     254             : 
     255             : /************************************************************************/
     256             : /*                           GetColorTable()                            */
     257             : /************************************************************************/
     258             : 
     259           0 : GDALColorTable *PAuxRasterBand::GetColorTable()
     260             : 
     261             : {
     262           0 :     return poCT;
     263             : }
     264             : 
     265             : /************************************************************************/
     266             : /*                       GetColorInterpretation()                       */
     267             : /************************************************************************/
     268             : 
     269           2 : GDALColorInterp PAuxRasterBand::GetColorInterpretation()
     270             : 
     271             : {
     272           2 :     if (poCT == nullptr)
     273           2 :         return GCI_Undefined;
     274             : 
     275           0 :     return GCI_PaletteIndex;
     276             : }
     277             : 
     278             : /************************************************************************/
     279             : /* ==================================================================== */
     280             : /*                              PAuxDataset                             */
     281             : /* ==================================================================== */
     282             : /************************************************************************/
     283             : 
     284             : /************************************************************************/
     285             : /*                            PAuxDataset()                             */
     286             : /************************************************************************/
     287             : 
     288          46 : PAuxDataset::PAuxDataset()
     289             :     : fpImage(nullptr), nGCPCount(0), pasGCPList(nullptr),
     290          46 :       pszAuxFilename(nullptr), papszAuxLines(nullptr), bAuxUpdated(FALSE)
     291             : {
     292          46 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     293          46 :     m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     294          46 : }
     295             : 
     296             : /************************************************************************/
     297             : /*                            ~PAuxDataset()                            */
     298             : /************************************************************************/
     299             : 
     300          92 : PAuxDataset::~PAuxDataset()
     301             : 
     302             : {
     303          46 :     PAuxDataset::Close();
     304          92 : }
     305             : 
     306             : /************************************************************************/
     307             : /*                              Close()                                 */
     308             : /************************************************************************/
     309             : 
     310          84 : CPLErr PAuxDataset::Close()
     311             : {
     312          84 :     CPLErr eErr = CE_None;
     313          84 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
     314             :     {
     315          46 :         if (PAuxDataset::FlushCache(true) != CE_None)
     316           2 :             eErr = CE_Failure;
     317             : 
     318          46 :         if (fpImage != nullptr)
     319             :         {
     320          42 :             if (VSIFCloseL(fpImage) != 0)
     321             :             {
     322           0 :                 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     323           0 :                 eErr = CE_Failure;
     324             :             }
     325             :         }
     326             : 
     327          46 :         if (bAuxUpdated)
     328             :         {
     329          21 :             CSLSetNameValueSeparator(papszAuxLines, ": ");
     330          21 :             CSLSave(papszAuxLines, pszAuxFilename);
     331             :         }
     332             : 
     333          46 :         GDALDeinitGCPs(nGCPCount, pasGCPList);
     334          46 :         CPLFree(pasGCPList);
     335             : 
     336          46 :         CPLFree(pszAuxFilename);
     337          46 :         CSLDestroy(papszAuxLines);
     338             : 
     339          46 :         if (GDALPamDataset::Close() != CE_None)
     340           0 :             eErr = CE_Failure;
     341             :     }
     342          84 :     return eErr;
     343             : }
     344             : 
     345             : /************************************************************************/
     346             : /*                            GetFileList()                             */
     347             : /************************************************************************/
     348             : 
     349           1 : char **PAuxDataset::GetFileList()
     350             : 
     351             : {
     352           1 :     char **papszFileList = RawDataset::GetFileList();
     353           1 :     papszFileList = CSLAddString(papszFileList, pszAuxFilename);
     354           1 :     return papszFileList;
     355             : }
     356             : 
     357             : /************************************************************************/
     358             : /*                              PCI2SRS()                               */
     359             : /*                                                                      */
     360             : /*      Convert PCI coordinate system to WKT.  For now this is very     */
     361             : /*      incomplete, but can be filled out in the future.                */
     362             : /************************************************************************/
     363             : 
     364           8 : OGRSpatialReference PAuxDataset::PCI2SRS(const char *pszGeosys,
     365             :                                          const char *pszProjParams)
     366             : 
     367             : {
     368           8 :     while (*pszGeosys == ' ')
     369           4 :         pszGeosys++;
     370             : 
     371             :     /* -------------------------------------------------------------------- */
     372             :     /*      Parse projection parameters array.                              */
     373             :     /* -------------------------------------------------------------------- */
     374           4 :     double adfProjParams[16] = {0.0};
     375             : 
     376           4 :     if (pszProjParams != nullptr)
     377             :     {
     378           4 :         char **papszTokens = CSLTokenizeString(pszProjParams);
     379             : 
     380           4 :         for (int i = 0;
     381          68 :              i < 16 && papszTokens != nullptr && papszTokens[i] != nullptr; i++)
     382          64 :             adfProjParams[i] = CPLAtof(papszTokens[i]);
     383             : 
     384           4 :         CSLDestroy(papszTokens);
     385             :     }
     386             : 
     387             :     /* -------------------------------------------------------------------- */
     388             :     /*      Convert to SRS.                                                 */
     389             :     /* -------------------------------------------------------------------- */
     390           4 :     OGRSpatialReference oSRS;
     391           4 :     oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     392           4 :     if (oSRS.importFromPCI(pszGeosys, nullptr, adfProjParams) != OGRERR_NONE)
     393             :     {
     394           0 :         oSRS.Clear();
     395             :     }
     396             : 
     397           8 :     return oSRS;
     398             : }
     399             : 
     400             : /************************************************************************/
     401             : /*                            ScanForGCPs()                             */
     402             : /************************************************************************/
     403             : 
     404          42 : void PAuxDataset::ScanForGCPs()
     405             : 
     406             : {
     407          42 :     const int MAX_GCP = 256;
     408             : 
     409          42 :     nGCPCount = 0;
     410          42 :     CPLAssert(pasGCPList == nullptr);
     411          42 :     pasGCPList =
     412          42 :         reinterpret_cast<GDAL_GCP *>(CPLCalloc(sizeof(GDAL_GCP), MAX_GCP));
     413             : 
     414             :     /* -------------------------------------------------------------------- */
     415             :     /*      Get the GCP coordinate system.                                  */
     416             :     /* -------------------------------------------------------------------- */
     417             :     const char *pszMapUnits =
     418          42 :         CSLFetchNameValue(papszAuxLines, "GCP_1_MapUnits");
     419             :     const char *pszProjParams =
     420          42 :         CSLFetchNameValue(papszAuxLines, "GCP_1_ProjParms");
     421             : 
     422          42 :     if (pszMapUnits != nullptr)
     423           0 :         m_oGCPSRS = PCI2SRS(pszMapUnits, pszProjParams);
     424             : 
     425             :     /* -------------------------------------------------------------------- */
     426             :     /*      Collect standalone GCPs.  They look like:                       */
     427             :     /*                                                                      */
     428             :     /*      GCP_1_n = row, col, x, y [,z [,"id"[, "desc"]]]                 */
     429             :     /* -------------------------------------------------------------------- */
     430          42 :     for (int i = 0; nGCPCount < MAX_GCP; i++)
     431             :     {
     432          42 :         char szName[50] = {'\0'};
     433          42 :         snprintf(szName, sizeof(szName), "GCP_1_%d", i + 1);
     434          42 :         if (CSLFetchNameValue(papszAuxLines, szName) == nullptr)
     435          42 :             break;
     436             : 
     437           0 :         char **papszTokens = CSLTokenizeStringComplex(
     438           0 :             CSLFetchNameValue(papszAuxLines, szName), " ", TRUE, FALSE);
     439             : 
     440           0 :         if (CSLCount(papszTokens) >= 4)
     441             :         {
     442           0 :             GDALInitGCPs(1, pasGCPList + nGCPCount);
     443             : 
     444           0 :             pasGCPList[nGCPCount].dfGCPX = CPLAtof(papszTokens[2]);
     445           0 :             pasGCPList[nGCPCount].dfGCPY = CPLAtof(papszTokens[3]);
     446           0 :             pasGCPList[nGCPCount].dfGCPPixel = CPLAtof(papszTokens[0]);
     447           0 :             pasGCPList[nGCPCount].dfGCPLine = CPLAtof(papszTokens[1]);
     448             : 
     449           0 :             if (CSLCount(papszTokens) > 4)
     450           0 :                 pasGCPList[nGCPCount].dfGCPZ = CPLAtof(papszTokens[4]);
     451             : 
     452           0 :             CPLFree(pasGCPList[nGCPCount].pszId);
     453           0 :             if (CSLCount(papszTokens) > 5)
     454             :             {
     455           0 :                 pasGCPList[nGCPCount].pszId = CPLStrdup(papszTokens[5]);
     456             :             }
     457             :             else
     458             :             {
     459           0 :                 snprintf(szName, sizeof(szName), "GCP_%d", i + 1);
     460           0 :                 pasGCPList[nGCPCount].pszId = CPLStrdup(szName);
     461             :             }
     462             : 
     463           0 :             if (CSLCount(papszTokens) > 6)
     464             :             {
     465           0 :                 CPLFree(pasGCPList[nGCPCount].pszInfo);
     466           0 :                 pasGCPList[nGCPCount].pszInfo = CPLStrdup(papszTokens[6]);
     467             :             }
     468             : 
     469           0 :             nGCPCount++;
     470             :         }
     471             : 
     472           0 :         CSLDestroy(papszTokens);
     473             :     }
     474          42 : }
     475             : 
     476             : /************************************************************************/
     477             : /*                            GetGCPCount()                             */
     478             : /************************************************************************/
     479             : 
     480           0 : int PAuxDataset::GetGCPCount()
     481             : 
     482             : {
     483           0 :     return nGCPCount;
     484             : }
     485             : 
     486             : /************************************************************************/
     487             : /*                               GetGCP()                               */
     488             : /************************************************************************/
     489             : 
     490           0 : const GDAL_GCP *PAuxDataset::GetGCPs()
     491             : 
     492             : {
     493           0 :     return pasGCPList;
     494             : }
     495             : 
     496             : /************************************************************************/
     497             : /*                          GetGeoTransform()                           */
     498             : /************************************************************************/
     499             : 
     500          12 : CPLErr PAuxDataset::GetGeoTransform(double *padfGeoTransform)
     501             : 
     502             : {
     503          12 :     if (CSLFetchNameValue(papszAuxLines, "UpLeftX") == nullptr ||
     504          12 :         CSLFetchNameValue(papszAuxLines, "UpLeftY") == nullptr ||
     505          36 :         CSLFetchNameValue(papszAuxLines, "LoRightX") == nullptr ||
     506          12 :         CSLFetchNameValue(papszAuxLines, "LoRightY") == nullptr)
     507             :     {
     508           0 :         padfGeoTransform[0] = 0.0;
     509           0 :         padfGeoTransform[1] = 1.0;
     510           0 :         padfGeoTransform[2] = 0.0;
     511           0 :         padfGeoTransform[3] = 0.0;
     512           0 :         padfGeoTransform[4] = 0.0;
     513           0 :         padfGeoTransform[5] = 1.0;
     514             : 
     515           0 :         return CE_Failure;
     516             :     }
     517             : 
     518             :     const double dfUpLeftX =
     519          12 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "UpLeftX"));
     520             :     const double dfUpLeftY =
     521          12 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "UpLeftY"));
     522             :     const double dfLoRightX =
     523          12 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "LoRightX"));
     524             :     const double dfLoRightY =
     525          12 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "LoRightY"));
     526             : 
     527          12 :     padfGeoTransform[0] = dfUpLeftX;
     528          12 :     padfGeoTransform[1] = (dfLoRightX - dfUpLeftX) / GetRasterXSize();
     529          12 :     padfGeoTransform[2] = 0.0;
     530          12 :     padfGeoTransform[3] = dfUpLeftY;
     531          12 :     padfGeoTransform[4] = 0.0;
     532          12 :     padfGeoTransform[5] = (dfLoRightY - dfUpLeftY) / GetRasterYSize();
     533             : 
     534          12 :     return CE_None;
     535             : }
     536             : 
     537             : /************************************************************************/
     538             : /*                          SetGeoTransform()                           */
     539             : /************************************************************************/
     540             : 
     541          21 : CPLErr PAuxDataset::SetGeoTransform(double *padfGeoTransform)
     542             : 
     543             : {
     544          21 :     char szUpLeftX[128] = {'\0'};
     545          21 :     char szUpLeftY[128] = {'\0'};
     546          21 :     char szLoRightX[128] = {'\0'};
     547          21 :     char szLoRightY[128] = {'\0'};
     548             : 
     549          40 :     if (std::abs(padfGeoTransform[0]) < 181 &&
     550          19 :         std::abs(padfGeoTransform[1]) < 1)
     551             :     {
     552          19 :         CPLsnprintf(szUpLeftX, sizeof(szUpLeftX), "%.12f", padfGeoTransform[0]);
     553          19 :         CPLsnprintf(szUpLeftY, sizeof(szUpLeftY), "%.12f", padfGeoTransform[3]);
     554          19 :         CPLsnprintf(szLoRightX, sizeof(szLoRightX), "%.12f",
     555          19 :                     padfGeoTransform[0] +
     556          19 :                         padfGeoTransform[1] * GetRasterXSize());
     557          19 :         CPLsnprintf(szLoRightY, sizeof(szLoRightY), "%.12f",
     558          19 :                     padfGeoTransform[3] +
     559          19 :                         padfGeoTransform[5] * GetRasterYSize());
     560             :     }
     561             :     else
     562             :     {
     563           2 :         CPLsnprintf(szUpLeftX, sizeof(szUpLeftX), "%.3f", padfGeoTransform[0]);
     564           2 :         CPLsnprintf(szUpLeftY, sizeof(szUpLeftY), "%.3f", padfGeoTransform[3]);
     565           2 :         CPLsnprintf(szLoRightX, sizeof(szLoRightX), "%.3f",
     566           2 :                     padfGeoTransform[0] +
     567           2 :                         padfGeoTransform[1] * GetRasterXSize());
     568           2 :         CPLsnprintf(szLoRightY, sizeof(szLoRightY), "%.3f",
     569           2 :                     padfGeoTransform[3] +
     570           2 :                         padfGeoTransform[5] * GetRasterYSize());
     571             :     }
     572             : 
     573          21 :     papszAuxLines = CSLSetNameValue(papszAuxLines, "UpLeftX", szUpLeftX);
     574          21 :     papszAuxLines = CSLSetNameValue(papszAuxLines, "UpLeftY", szUpLeftY);
     575          21 :     papszAuxLines = CSLSetNameValue(papszAuxLines, "LoRightX", szLoRightX);
     576          21 :     papszAuxLines = CSLSetNameValue(papszAuxLines, "LoRightY", szLoRightY);
     577             : 
     578          21 :     bAuxUpdated = TRUE;
     579             : 
     580          21 :     return CE_None;
     581             : }
     582             : 
     583             : /************************************************************************/
     584             : /*                                Open()                                */
     585             : /************************************************************************/
     586             : 
     587       30781 : GDALDataset *PAuxDataset::Open(GDALOpenInfo *poOpenInfo)
     588             : 
     589             : {
     590       30781 :     if (poOpenInfo->nHeaderBytes < 1)
     591       27247 :         return nullptr;
     592             : 
     593             :     /* -------------------------------------------------------------------- */
     594             :     /*      If this is an .aux file, fetch out and form the name of the     */
     595             :     /*      file it references.                                             */
     596             :     /* -------------------------------------------------------------------- */
     597             : 
     598        7068 :     CPLString osTarget = poOpenInfo->pszFilename;
     599             : 
     600        3536 :     if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "aux") &&
     601           2 :         STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
     602             :                        "AuxilaryTarget: "))
     603             :     {
     604           2 :         const char *pszSrc =
     605           2 :             reinterpret_cast<const char *>(poOpenInfo->pabyHeader + 16);
     606             : 
     607           2 :         char szAuxTarget[1024] = {'\0'};
     608           2 :         for (int i = 0; i < static_cast<int>(sizeof(szAuxTarget)) - 1 &&
     609          24 :                         pszSrc[i] != 10 && pszSrc[i] != 13 && pszSrc[i] != '\0';
     610             :              i++)
     611             :         {
     612          22 :             szAuxTarget[i] = pszSrc[i];
     613             :         }
     614           2 :         szAuxTarget[sizeof(szAuxTarget) - 1] = '\0';
     615             : 
     616           2 :         const std::string osPath(CPLGetPath(poOpenInfo->pszFilename));
     617           2 :         osTarget = CPLFormFilename(osPath.c_str(), szAuxTarget, nullptr);
     618             :     }
     619             : 
     620             :     /* -------------------------------------------------------------------- */
     621             :     /*      Now we need to tear apart the filename to form a .aux           */
     622             :     /*      filename.                                                       */
     623             :     /* -------------------------------------------------------------------- */
     624        7068 :     CPLString osAuxFilename = CPLResetExtension(osTarget, "aux");
     625             : 
     626             :     /* -------------------------------------------------------------------- */
     627             :     /*      Do we have a .aux file?                                         */
     628             :     /* -------------------------------------------------------------------- */
     629        3534 :     char **papszSiblingFiles = poOpenInfo->GetSiblingFiles();
     630        7032 :     if (papszSiblingFiles != nullptr &&
     631        3498 :         CSLFindString(papszSiblingFiles, CPLGetFilename(osAuxFilename)) == -1)
     632             :     {
     633        3449 :         return nullptr;
     634             :     }
     635             : 
     636          85 :     VSILFILE *fp = VSIFOpenL(osAuxFilename, "r");
     637          85 :     if (fp == nullptr)
     638             :     {
     639          36 :         osAuxFilename = CPLResetExtension(osTarget, "AUX");
     640          36 :         fp = VSIFOpenL(osAuxFilename, "r");
     641             :     }
     642             : 
     643          85 :     if (fp == nullptr)
     644          36 :         return nullptr;
     645             : 
     646             :     /* -------------------------------------------------------------------- */
     647             :     /*      Is this file a PCI .aux file?  Check the first line for the     */
     648             :     /*      telltale AuxilaryTarget keyword.                                */
     649             :     /*                                                                      */
     650             :     /*      At this point we should be verifying that it refers to our      */
     651             :     /*      binary file, but that is a pretty involved test.                */
     652             :     /* -------------------------------------------------------------------- */
     653          49 :     CPLPushErrorHandler(CPLQuietErrorHandler);
     654          49 :     const char *pszLine = CPLReadLine2L(fp, 1024, nullptr);
     655          49 :     CPLPopErrorHandler();
     656             : 
     657          49 :     CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     658             : 
     659          49 :     if (pszLine == nullptr || (!STARTS_WITH_CI(pszLine, "AuxilaryTarget") &&
     660           1 :                                !STARTS_WITH_CI(pszLine, "AuxiliaryTarget")))
     661             :     {
     662           3 :         CPLErrorReset();
     663           3 :         return nullptr;
     664             :     }
     665             : 
     666             :     /* -------------------------------------------------------------------- */
     667             :     /*      Create a corresponding GDALDataset.                             */
     668             :     /* -------------------------------------------------------------------- */
     669          92 :     auto poDS = std::make_unique<PAuxDataset>();
     670             : 
     671             :     /* -------------------------------------------------------------------- */
     672             :     /*      Load the .aux file into a string list suitable to be            */
     673             :     /*      searched with CSLFetchNameValue().                              */
     674             :     /* -------------------------------------------------------------------- */
     675          46 :     poDS->papszAuxLines = CSLLoad2(osAuxFilename, 1024, 1024, nullptr);
     676          46 :     poDS->pszAuxFilename = CPLStrdup(osAuxFilename);
     677             : 
     678             :     /* -------------------------------------------------------------------- */
     679             :     /*      Find the RawDefinition line to establish overall parameters.    */
     680             :     /* -------------------------------------------------------------------- */
     681          46 :     pszLine = CSLFetchNameValue(poDS->papszAuxLines, "RawDefinition");
     682             : 
     683             :     // It seems PCI now writes out .aux files without RawDefinition in
     684             :     // some cases.  See bug 947.
     685          46 :     if (pszLine == nullptr)
     686             :     {
     687           2 :         return nullptr;
     688             :     }
     689             : 
     690          88 :     const CPLStringList aosTokens(CSLTokenizeString(pszLine));
     691             : 
     692          44 :     if (aosTokens.size() < 3)
     693             :     {
     694           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     695             :                  "RawDefinition missing or corrupt in %s.",
     696             :                  poOpenInfo->pszFilename);
     697           0 :         return nullptr;
     698             :     }
     699             : 
     700          44 :     poDS->nRasterXSize = atoi(aosTokens[0]);
     701          44 :     poDS->nRasterYSize = atoi(aosTokens[1]);
     702          44 :     int l_nBands = atoi(aosTokens[2]);
     703          44 :     poDS->eAccess = poOpenInfo->eAccess;
     704             : 
     705          88 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
     706          44 :         !GDALCheckBandCount(l_nBands, FALSE))
     707             :     {
     708           2 :         return nullptr;
     709             :     }
     710             : 
     711             :     /* -------------------------------------------------------------------- */
     712             :     /*      Open the file.                                                  */
     713             :     /* -------------------------------------------------------------------- */
     714          42 :     if (poOpenInfo->eAccess == GA_Update)
     715             :     {
     716          25 :         poDS->fpImage = VSIFOpenL(osTarget, "rb+");
     717             : 
     718          25 :         if (poDS->fpImage == nullptr)
     719             :         {
     720           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     721             :                      "File %s is missing or read-only, check permissions.",
     722             :                      osTarget.c_str());
     723           0 :             return nullptr;
     724             :         }
     725             :     }
     726             :     else
     727             :     {
     728          17 :         poDS->fpImage = VSIFOpenL(osTarget, "rb");
     729             : 
     730          17 :         if (poDS->fpImage == nullptr)
     731             :         {
     732           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     733             :                      "File %s is missing or unreadable.", osTarget.c_str());
     734           0 :             return nullptr;
     735             :         }
     736             :     }
     737             : 
     738             :     /* -------------------------------------------------------------------- */
     739             :     /*      Collect raw definitions of each channel and create              */
     740             :     /*      corresponding bands.                                            */
     741             :     /* -------------------------------------------------------------------- */
     742         130 :     for (int i = 0; i < l_nBands; i++)
     743             :     {
     744          88 :         char szDefnName[32] = {'\0'};
     745          88 :         snprintf(szDefnName, sizeof(szDefnName), "ChanDefinition-%d", i + 1);
     746             : 
     747          88 :         pszLine = CSLFetchNameValue(poDS->papszAuxLines, szDefnName);
     748          88 :         if (pszLine == nullptr)
     749             :         {
     750           4 :             continue;
     751             :         }
     752             : 
     753          84 :         const CPLStringList aosTokensBand(CSLTokenizeString(pszLine));
     754          84 :         if (aosTokensBand.size() < 4)
     755             :         {
     756             :             // Skip the band with broken description
     757           0 :             continue;
     758             :         }
     759             : 
     760          84 :         GDALDataType eType = GDT_Unknown;
     761          84 :         if (EQUAL(aosTokensBand[0], "16U"))
     762          17 :             eType = GDT_UInt16;
     763          67 :         else if (EQUAL(aosTokensBand[0], "16S"))
     764           9 :             eType = GDT_Int16;
     765          58 :         else if (EQUAL(aosTokensBand[0], "32R"))
     766           9 :             eType = GDT_Float32;
     767             :         else
     768          49 :             eType = GDT_Byte;
     769             : 
     770          84 :         bool bNative = true;
     771          84 :         if (CSLCount(aosTokensBand) > 4)
     772             :         {
     773             : #ifdef CPL_LSB
     774          84 :             bNative = EQUAL(aosTokensBand[4], "Swapped");
     775             : #else
     776             :             bNative = EQUAL(aosTokensBand[4], "Unswapped");
     777             : #endif
     778             :         }
     779             : 
     780          84 :         const vsi_l_offset nBandOffset = CPLScanUIntBig(
     781          84 :             aosTokensBand[1], static_cast<int>(strlen(aosTokensBand[1])));
     782          84 :         const int nPixelOffset = atoi(aosTokensBand[2]);
     783          84 :         const int nLineOffset = atoi(aosTokensBand[3]);
     784             : 
     785          84 :         if (nPixelOffset <= 0 || nLineOffset <= 0)
     786             :         {
     787             :             // Skip the band with broken offsets.
     788           0 :             continue;
     789             :         }
     790             : 
     791             :         auto poBand = std::make_unique<PAuxRasterBand>(
     792          84 :             poDS.get(), poDS->nBands + 1, poDS->fpImage, nBandOffset,
     793          84 :             nPixelOffset, nLineOffset, eType, bNative);
     794          84 :         if (!poBand->IsValid())
     795           0 :             return nullptr;
     796          84 :         poDS->SetBand(poDS->nBands + 1, std::move(poBand));
     797             :     }
     798             : 
     799             :     /* -------------------------------------------------------------------- */
     800             :     /*      Get the projection.                                             */
     801             :     /* -------------------------------------------------------------------- */
     802             :     const char *pszMapUnits =
     803          42 :         CSLFetchNameValue(poDS->papszAuxLines, "MapUnits");
     804             :     const char *pszProjParams =
     805          42 :         CSLFetchNameValue(poDS->papszAuxLines, "ProjParams");
     806             : 
     807          42 :     if (pszMapUnits != nullptr)
     808             :     {
     809           4 :         poDS->m_oSRS = PCI2SRS(pszMapUnits, pszProjParams);
     810             :     }
     811             : 
     812             :     /* -------------------------------------------------------------------- */
     813             :     /*      Initialize any PAM information.                                 */
     814             :     /* -------------------------------------------------------------------- */
     815          42 :     poDS->SetDescription(osTarget);
     816          42 :     poDS->TryLoadXML();
     817             : 
     818             :     /* -------------------------------------------------------------------- */
     819             :     /*      Check for overviews.                                            */
     820             :     /* -------------------------------------------------------------------- */
     821          42 :     poDS->oOvManager.Initialize(poDS.get(), osTarget);
     822             : 
     823          42 :     poDS->ScanForGCPs();
     824          42 :     poDS->bAuxUpdated = FALSE;
     825             : 
     826          42 :     return poDS.release();
     827             : }
     828             : 
     829             : /************************************************************************/
     830             : /*                               Create()                               */
     831             : /************************************************************************/
     832             : 
     833          62 : GDALDataset *PAuxDataset::Create(const char *pszFilename, int nXSize,
     834             :                                  int nYSize, int nBandsIn, GDALDataType eType,
     835             :                                  char **papszOptions)
     836             : 
     837             : {
     838          62 :     const char *pszInterleave = CSLFetchNameValue(papszOptions, "INTERLEAVE");
     839          62 :     if (pszInterleave == nullptr)
     840          62 :         pszInterleave = "BAND";
     841             : 
     842             :     /* -------------------------------------------------------------------- */
     843             :     /*      Verify input options.                                           */
     844             :     /* -------------------------------------------------------------------- */
     845          62 :     if (eType != GDT_Byte && eType != GDT_Float32 && eType != GDT_UInt16 &&
     846             :         eType != GDT_Int16)
     847             :     {
     848          27 :         CPLError(CE_Failure, CPLE_AppDefined,
     849             :                  "Attempt to create PCI .Aux labelled dataset with an illegal\n"
     850             :                  "data type (%s).\n",
     851             :                  GDALGetDataTypeName(eType));
     852             : 
     853          27 :         return nullptr;
     854             :     }
     855             : 
     856             :     /* -------------------------------------------------------------------- */
     857             :     /*      Sum the sizes of the band pixel types.                          */
     858             :     /* -------------------------------------------------------------------- */
     859          35 :     int nPixelSizeSum = 0;
     860             : 
     861          95 :     for (int iBand = 0; iBand < nBandsIn; iBand++)
     862          60 :         nPixelSizeSum += GDALGetDataTypeSizeBytes(eType);
     863             : 
     864             :     /* -------------------------------------------------------------------- */
     865             :     /*      Try to create the file.                                         */
     866             :     /* -------------------------------------------------------------------- */
     867          35 :     VSILFILE *fp = VSIFOpenL(pszFilename, "w");
     868          35 :     if (fp == nullptr)
     869             :     {
     870           3 :         CPLError(CE_Failure, CPLE_OpenFailed,
     871             :                  "Attempt to create file `%s' failed.\n", pszFilename);
     872           3 :         return nullptr;
     873             :     }
     874             : 
     875             :     /* -------------------------------------------------------------------- */
     876             :     /*      Just write out a couple of bytes to establish the binary        */
     877             :     /*      file, and then close it.                                        */
     878             :     /* -------------------------------------------------------------------- */
     879          32 :     CPL_IGNORE_RET_VAL(VSIFWriteL("\0\0", 2, 1, fp));
     880          32 :     CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     881             : 
     882             :     /* -------------------------------------------------------------------- */
     883             :     /*      Create the aux filename.                                        */
     884             :     /* -------------------------------------------------------------------- */
     885             :     char *pszAuxFilename =
     886          32 :         static_cast<char *>(CPLMalloc(strlen(pszFilename) + 5));
     887          32 :     strcpy(pszAuxFilename, pszFilename);
     888             : 
     889         975 :     for (int i = static_cast<int>(strlen(pszAuxFilename)) - 1; i > 0; i--)
     890             :     {
     891         945 :         if (pszAuxFilename[i] == '.')
     892             :         {
     893           2 :             pszAuxFilename[i] = '\0';
     894           2 :             break;
     895             :         }
     896             :     }
     897             : 
     898          32 :     strcat(pszAuxFilename, ".aux");
     899             : 
     900             :     /* -------------------------------------------------------------------- */
     901             :     /*      Open the file.                                                  */
     902             :     /* -------------------------------------------------------------------- */
     903          32 :     fp = VSIFOpenL(pszAuxFilename, "wt");
     904          32 :     if (fp == nullptr)
     905             :     {
     906           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     907             :                  "Attempt to create file `%s' failed.\n", pszAuxFilename);
     908           0 :         return nullptr;
     909             :     }
     910          32 :     CPLFree(pszAuxFilename);
     911             : 
     912             :     /* -------------------------------------------------------------------- */
     913             :     /*      We need to write out the original filename but without any      */
     914             :     /*      path components in the AuxilaryTarget line.  Do so now.         */
     915             :     /* -------------------------------------------------------------------- */
     916          32 :     int iStart = static_cast<int>(strlen(pszFilename)) - 1;
     917         273 :     while (iStart > 0 && pszFilename[iStart - 1] != '/' &&
     918         241 :            pszFilename[iStart - 1] != '\\')
     919         241 :         iStart--;
     920             : 
     921          32 :     CPL_IGNORE_RET_VAL(
     922          32 :         VSIFPrintfL(fp, "AuxilaryTarget: %s\n", pszFilename + iStart));
     923             : 
     924             :     /* -------------------------------------------------------------------- */
     925             :     /*      Write out the raw definition for the dataset as a whole.        */
     926             :     /* -------------------------------------------------------------------- */
     927          32 :     CPL_IGNORE_RET_VAL(
     928          32 :         VSIFPrintfL(fp, "RawDefinition: %d %d %d\n", nXSize, nYSize, nBandsIn));
     929             : 
     930             :     /* -------------------------------------------------------------------- */
     931             :     /*      Write out a definition for each band.  We always write band     */
     932             :     /*      sequential files for now as these are pretty efficiently        */
     933             :     /*      handled by GDAL.                                                */
     934             :     /* -------------------------------------------------------------------- */
     935          32 :     vsi_l_offset nImgOffset = 0;
     936             : 
     937          89 :     for (int iBand = 0; iBand < nBandsIn; iBand++)
     938             :     {
     939          57 :         int nPixelOffset = 0;
     940          57 :         int nLineOffset = 0;
     941          57 :         vsi_l_offset nNextImgOffset = 0;
     942             : 
     943             :         /* --------------------------------------------------------------------
     944             :          */
     945             :         /*      Establish our file layout based on supplied interleaving. */
     946             :         /* --------------------------------------------------------------------
     947             :          */
     948          57 :         if (EQUAL(pszInterleave, "LINE"))
     949             :         {
     950           0 :             nPixelOffset = GDALGetDataTypeSizeBytes(eType);
     951           0 :             nLineOffset = nXSize * nPixelSizeSum;
     952           0 :             nNextImgOffset =
     953           0 :                 nImgOffset + static_cast<vsi_l_offset>(nPixelOffset) * nXSize;
     954             :         }
     955          57 :         else if (EQUAL(pszInterleave, "PIXEL"))
     956             :         {
     957           0 :             nPixelOffset = nPixelSizeSum;
     958           0 :             nLineOffset = nXSize * nPixelOffset;
     959           0 :             nNextImgOffset = nImgOffset + GDALGetDataTypeSizeBytes(eType);
     960             :         }
     961             :         else /* default to band */
     962             :         {
     963          57 :             nPixelOffset = GDALGetDataTypeSize(eType) / 8;
     964          57 :             nLineOffset = nXSize * nPixelOffset;
     965          57 :             nNextImgOffset =
     966          57 :                 nImgOffset + nYSize * static_cast<vsi_l_offset>(nLineOffset);
     967             :         }
     968             : 
     969             :         /* --------------------------------------------------------------------
     970             :          */
     971             :         /*      Write out line indicating layout. */
     972             :         /* --------------------------------------------------------------------
     973             :          */
     974          57 :         const char *pszTypeName = nullptr;
     975          57 :         if (eType == GDT_Float32)
     976           5 :             pszTypeName = "32R";
     977          52 :         else if (eType == GDT_Int16)
     978           5 :             pszTypeName = "16S";
     979          47 :         else if (eType == GDT_UInt16)
     980           5 :             pszTypeName = "16U";
     981             :         else
     982          42 :             pszTypeName = "8U";
     983             : 
     984          57 :         CPL_IGNORE_RET_VAL(VSIFPrintfL(
     985             :             fp, "ChanDefinition-%d: %s " CPL_FRMT_GIB " %d %d %s\n", iBand + 1,
     986             :             pszTypeName, static_cast<GIntBig>(nImgOffset), nPixelOffset,
     987             :             nLineOffset,
     988             : #ifdef CPL_LSB
     989             :             "Swapped"
     990             : #else
     991             :             "Unswapped"
     992             : #endif
     993             :             ));
     994             : 
     995          57 :         nImgOffset = nNextImgOffset;
     996             :     }
     997             : 
     998             :     /* -------------------------------------------------------------------- */
     999             :     /*      Cleanup                                                         */
    1000             :     /* -------------------------------------------------------------------- */
    1001          32 :     CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
    1002             : 
    1003          32 :     return static_cast<GDALDataset *>(GDALOpen(pszFilename, GA_Update));
    1004             : }
    1005             : 
    1006             : /************************************************************************/
    1007             : /*                             PAuxDelete()                             */
    1008             : /************************************************************************/
    1009             : 
    1010           6 : static CPLErr PAuxDelete(const char *pszBasename)
    1011             : 
    1012             : {
    1013           6 :     VSILFILE *fp = VSIFOpenL(CPLResetExtension(pszBasename, "aux"), "r");
    1014           6 :     if (fp == nullptr)
    1015             :     {
    1016           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1017             :                  "%s does not appear to be a PAux dataset: "
    1018             :                  "there is no .aux file.",
    1019             :                  pszBasename);
    1020           0 :         return CE_Failure;
    1021             :     }
    1022             : 
    1023           6 :     const char *pszLine = CPLReadLineL(fp);
    1024           6 :     CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
    1025             : 
    1026           6 :     if (pszLine == nullptr || !STARTS_WITH_CI(pszLine, "AuxilaryTarget"))
    1027             :     {
    1028           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1029             :                  "%s does not appear to be a PAux dataset:"
    1030             :                  "the .aux file does not start with AuxilaryTarget",
    1031             :                  pszBasename);
    1032           0 :         return CE_Failure;
    1033             :     }
    1034             : 
    1035           6 :     if (VSIUnlink(pszBasename) != 0)
    1036             :     {
    1037           0 :         CPLError(CE_Failure, CPLE_AppDefined, "OS unlinking file %s.",
    1038             :                  pszBasename);
    1039           0 :         return CE_Failure;
    1040             :     }
    1041             : 
    1042           6 :     VSIUnlink(CPLResetExtension(pszBasename, "aux"));
    1043             : 
    1044           6 :     return CE_None;
    1045             : }
    1046             : 
    1047             : /************************************************************************/
    1048             : /*                         GDALRegister_PAux()                          */
    1049             : /************************************************************************/
    1050             : 
    1051        1595 : void GDALRegister_PAux()
    1052             : 
    1053             : {
    1054        1595 :     if (GDALGetDriverByName("PAux") != nullptr)
    1055         302 :         return;
    1056             : 
    1057        1293 :     GDALDriver *poDriver = new GDALDriver();
    1058             : 
    1059        1293 :     poDriver->SetDescription("PAux");
    1060        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
    1061        1293 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "PCI .aux Labelled");
    1062        1293 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/paux.html");
    1063        1293 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
    1064        1293 :                               "Byte Int16 UInt16 Float32");
    1065        1293 :     poDriver->SetMetadataItem(
    1066             :         GDAL_DMD_CREATIONOPTIONLIST,
    1067             :         "<CreationOptionList>"
    1068             :         "   <Option name='INTERLEAVE' type='string-select' default='BAND'>"
    1069             :         "       <Value>BAND</Value>"
    1070             :         "       <Value>LINE</Value>"
    1071             :         "       <Value>PIXEL</Value>"
    1072             :         "   </Option>"
    1073        1293 :         "</CreationOptionList>");
    1074        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
    1075             : 
    1076        1293 :     poDriver->pfnOpen = PAuxDataset::Open;
    1077        1293 :     poDriver->pfnCreate = PAuxDataset::Create;
    1078        1293 :     poDriver->pfnDelete = PAuxDelete;
    1079             : 
    1080        1293 :     GetGDALDriverManager()->RegisterDriver(poDriver);
    1081             : }

Generated by: LCOV version 1.14