LCOV - code coverage report
Current view: top level - frmts/raw - pauxdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 154 260 59.2 %
Date: 2025-07-09 17:50:03 Functions: 12 20 60.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             : 
      57           0 :     const OGRSpatialReference *GetSpatialRef() const override
      58             :     {
      59           0 :         return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
      60             :     }
      61             : 
      62             :     CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
      63             : 
      64             :     int GetGCPCount() override;
      65             : 
      66           0 :     const OGRSpatialReference *GetGCPSpatialRef() const override
      67             :     {
      68           0 :         return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
      69             :     }
      70             : 
      71             :     const GDAL_GCP *GetGCPs() override;
      72             : 
      73             :     char **GetFileList() override;
      74             : 
      75             :     static GDALDataset *Open(GDALOpenInfo *);
      76             : };
      77             : 
      78             : /************************************************************************/
      79             : /* ==================================================================== */
      80             : /*                           PAuxRasterBand                             */
      81             : /* ==================================================================== */
      82             : /************************************************************************/
      83             : 
      84             : class PAuxRasterBand final : public RawRasterBand
      85             : {
      86             :     CPL_DISALLOW_COPY_ASSIGN(PAuxRasterBand)
      87             : 
      88             :   public:
      89             :     PAuxRasterBand(GDALDataset *poDS, int nBand, VSILFILE *fpRaw,
      90             :                    vsi_l_offset nImgOffset, int nPixelOffset, int nLineOffset,
      91             :                    GDALDataType eDataType, int bNativeOrder);
      92             : 
      93             :     ~PAuxRasterBand() override;
      94             : 
      95             :     double GetNoDataValue(int *pbSuccess = nullptr) override;
      96             : 
      97             :     GDALColorTable *GetColorTable() override;
      98             :     GDALColorInterp GetColorInterpretation() override;
      99             : };
     100             : 
     101             : /************************************************************************/
     102             : /*                           PAuxRasterBand()                           */
     103             : /************************************************************************/
     104             : 
     105           8 : PAuxRasterBand::PAuxRasterBand(GDALDataset *poDSIn, int nBandIn,
     106             :                                VSILFILE *fpRawIn, vsi_l_offset nImgOffsetIn,
     107             :                                int nPixelOffsetIn, int nLineOffsetIn,
     108           8 :                                GDALDataType eDataTypeIn, int bNativeOrderIn)
     109             :     : RawRasterBand(poDSIn, nBandIn, fpRawIn, nImgOffsetIn, nPixelOffsetIn,
     110             :                     nLineOffsetIn, eDataTypeIn, bNativeOrderIn,
     111           8 :                     RawRasterBand::OwnFP::NO)
     112             : {
     113           8 :     PAuxDataset *poPDS = reinterpret_cast<PAuxDataset *>(poDS);
     114             : 
     115             :     /* -------------------------------------------------------------------- */
     116             :     /*      Does this channel have a description?                           */
     117             :     /* -------------------------------------------------------------------- */
     118           8 :     char szTarget[128] = {'\0'};
     119             : 
     120           8 :     snprintf(szTarget, sizeof(szTarget), "ChanDesc-%d", nBand);
     121           8 :     if (CSLFetchNameValue(poPDS->papszAuxLines, szTarget) != nullptr)
     122           0 :         GDALRasterBand::SetDescription(
     123           0 :             CSLFetchNameValue(poPDS->papszAuxLines, szTarget));
     124             : 
     125             :     /* -------------------------------------------------------------------- */
     126             :     /*      See if we have colors.  Currently we must have color zero,      */
     127             :     /*      but this should not really be a limitation.                     */
     128             :     /* -------------------------------------------------------------------- */
     129           8 :     snprintf(szTarget, sizeof(szTarget), "METADATA_IMG_%d_Class_%d_Color",
     130             :              nBand, 0);
     131           8 :     if (CSLFetchNameValue(poPDS->papszAuxLines, szTarget) != nullptr)
     132             :     {
     133           0 :         poCT = new GDALColorTable();
     134             : 
     135           0 :         for (int i = 0; i < 256; i++)
     136             :         {
     137           0 :             snprintf(szTarget, sizeof(szTarget),
     138             :                      "METADATA_IMG_%d_Class_%d_Color", nBand, i);
     139             :             const char *pszLine =
     140           0 :                 CSLFetchNameValue(poPDS->papszAuxLines, szTarget);
     141           0 :             while (pszLine && *pszLine == ' ')
     142           0 :                 pszLine++;
     143             : 
     144           0 :             int nRed = 0;
     145           0 :             int nGreen = 0;
     146           0 :             int nBlue = 0;
     147             :             // TODO(schwehr): Replace sscanf with something safe.
     148           0 :             if (pszLine != nullptr && STARTS_WITH_CI(pszLine, "(RGB:") &&
     149           0 :                 sscanf(pszLine + 5, "%d %d %d", &nRed, &nGreen, &nBlue) == 3)
     150             :             {
     151           0 :                 GDALColorEntry oColor = {static_cast<short>(nRed),
     152             :                                          static_cast<short>(nGreen),
     153           0 :                                          static_cast<short>(nBlue), 255};
     154             : 
     155           0 :                 poCT->SetColorEntry(i, &oColor);
     156             :             }
     157             :         }
     158             :     }
     159           8 : }
     160             : 
     161             : /************************************************************************/
     162             : /*                          ~PAuxRasterBand()                           */
     163             : /************************************************************************/
     164             : 
     165          16 : PAuxRasterBand::~PAuxRasterBand()
     166             : 
     167             : {
     168          16 : }
     169             : 
     170             : /************************************************************************/
     171             : /*                           GetNoDataValue()                           */
     172             : /************************************************************************/
     173             : 
     174           0 : double PAuxRasterBand::GetNoDataValue(int *pbSuccess)
     175             : 
     176             : {
     177           0 :     char szTarget[128] = {'\0'};
     178           0 :     snprintf(szTarget, sizeof(szTarget), "METADATA_IMG_%d_NO_DATA_VALUE",
     179             :              nBand);
     180             : 
     181           0 :     PAuxDataset *poPDS = reinterpret_cast<PAuxDataset *>(poDS);
     182           0 :     const char *pszLine = CSLFetchNameValue(poPDS->papszAuxLines, szTarget);
     183             : 
     184           0 :     if (pbSuccess != nullptr)
     185           0 :         *pbSuccess = (pszLine != nullptr);
     186             : 
     187           0 :     if (pszLine == nullptr)
     188           0 :         return -1.0e8;
     189             : 
     190           0 :     return CPLAtof(pszLine);
     191             : }
     192             : 
     193             : /************************************************************************/
     194             : /*                           GetColorTable()                            */
     195             : /************************************************************************/
     196             : 
     197           0 : GDALColorTable *PAuxRasterBand::GetColorTable()
     198             : 
     199             : {
     200           0 :     return poCT;
     201             : }
     202             : 
     203             : /************************************************************************/
     204             : /*                       GetColorInterpretation()                       */
     205             : /************************************************************************/
     206             : 
     207           0 : GDALColorInterp PAuxRasterBand::GetColorInterpretation()
     208             : 
     209             : {
     210           0 :     if (poCT == nullptr)
     211           0 :         return GCI_Undefined;
     212             : 
     213           0 :     return GCI_PaletteIndex;
     214             : }
     215             : 
     216             : /************************************************************************/
     217             : /* ==================================================================== */
     218             : /*                              PAuxDataset                             */
     219             : /* ==================================================================== */
     220             : /************************************************************************/
     221             : 
     222             : /************************************************************************/
     223             : /*                            PAuxDataset()                             */
     224             : /************************************************************************/
     225             : 
     226           4 : PAuxDataset::PAuxDataset()
     227             :     : fpImage(nullptr), nGCPCount(0), pasGCPList(nullptr),
     228           4 :       pszAuxFilename(nullptr), papszAuxLines(nullptr)
     229             : {
     230           4 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     231           4 :     m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     232           4 : }
     233             : 
     234             : /************************************************************************/
     235             : /*                            ~PAuxDataset()                            */
     236             : /************************************************************************/
     237             : 
     238           8 : PAuxDataset::~PAuxDataset()
     239             : 
     240             : {
     241           4 :     PAuxDataset::Close();
     242           8 : }
     243             : 
     244             : /************************************************************************/
     245             : /*                              Close()                                 */
     246             : /************************************************************************/
     247             : 
     248           8 : CPLErr PAuxDataset::Close()
     249             : {
     250           8 :     CPLErr eErr = CE_None;
     251           8 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
     252             :     {
     253           4 :         if (PAuxDataset::FlushCache(true) != CE_None)
     254           0 :             eErr = CE_Failure;
     255             : 
     256           4 :         if (fpImage != nullptr)
     257             :         {
     258           4 :             if (VSIFCloseL(fpImage) != 0)
     259             :             {
     260           0 :                 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     261           0 :                 eErr = CE_Failure;
     262             :             }
     263             :         }
     264             : 
     265           4 :         GDALDeinitGCPs(nGCPCount, pasGCPList);
     266           4 :         CPLFree(pasGCPList);
     267             : 
     268           4 :         CPLFree(pszAuxFilename);
     269           4 :         CSLDestroy(papszAuxLines);
     270             : 
     271           4 :         if (GDALPamDataset::Close() != CE_None)
     272           0 :             eErr = CE_Failure;
     273             :     }
     274           8 :     return eErr;
     275             : }
     276             : 
     277             : /************************************************************************/
     278             : /*                            GetFileList()                             */
     279             : /************************************************************************/
     280             : 
     281           1 : char **PAuxDataset::GetFileList()
     282             : 
     283             : {
     284           1 :     char **papszFileList = RawDataset::GetFileList();
     285           1 :     papszFileList = CSLAddString(papszFileList, pszAuxFilename);
     286           1 :     return papszFileList;
     287             : }
     288             : 
     289             : /************************************************************************/
     290             : /*                              PCI2SRS()                               */
     291             : /*                                                                      */
     292             : /*      Convert PCI coordinate system to WKT.  For now this is very     */
     293             : /*      incomplete, but can be filled out in the future.                */
     294             : /************************************************************************/
     295             : 
     296           8 : OGRSpatialReference PAuxDataset::PCI2SRS(const char *pszGeosys,
     297             :                                          const char *pszProjParams)
     298             : 
     299             : {
     300           8 :     while (*pszGeosys == ' ')
     301           4 :         pszGeosys++;
     302             : 
     303             :     /* -------------------------------------------------------------------- */
     304             :     /*      Parse projection parameters array.                              */
     305             :     /* -------------------------------------------------------------------- */
     306           4 :     double adfProjParams[16] = {0.0};
     307             : 
     308           4 :     if (pszProjParams != nullptr)
     309             :     {
     310           4 :         char **papszTokens = CSLTokenizeString(pszProjParams);
     311             : 
     312           4 :         for (int i = 0;
     313          68 :              i < 16 && papszTokens != nullptr && papszTokens[i] != nullptr; i++)
     314          64 :             adfProjParams[i] = CPLAtof(papszTokens[i]);
     315             : 
     316           4 :         CSLDestroy(papszTokens);
     317             :     }
     318             : 
     319             :     /* -------------------------------------------------------------------- */
     320             :     /*      Convert to SRS.                                                 */
     321             :     /* -------------------------------------------------------------------- */
     322           4 :     OGRSpatialReference oSRS;
     323           4 :     oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     324           4 :     if (oSRS.importFromPCI(pszGeosys, nullptr, adfProjParams) != OGRERR_NONE)
     325             :     {
     326           0 :         oSRS.Clear();
     327             :     }
     328             : 
     329           8 :     return oSRS;
     330             : }
     331             : 
     332             : /************************************************************************/
     333             : /*                            ScanForGCPs()                             */
     334             : /************************************************************************/
     335             : 
     336           4 : void PAuxDataset::ScanForGCPs()
     337             : 
     338             : {
     339           4 :     const int MAX_GCP = 256;
     340             : 
     341           4 :     nGCPCount = 0;
     342           4 :     CPLAssert(pasGCPList == nullptr);
     343           4 :     pasGCPList =
     344           4 :         reinterpret_cast<GDAL_GCP *>(CPLCalloc(sizeof(GDAL_GCP), MAX_GCP));
     345             : 
     346             :     /* -------------------------------------------------------------------- */
     347             :     /*      Get the GCP coordinate system.                                  */
     348             :     /* -------------------------------------------------------------------- */
     349             :     const char *pszMapUnits =
     350           4 :         CSLFetchNameValue(papszAuxLines, "GCP_1_MapUnits");
     351             :     const char *pszProjParams =
     352           4 :         CSLFetchNameValue(papszAuxLines, "GCP_1_ProjParms");
     353             : 
     354           4 :     if (pszMapUnits != nullptr)
     355           0 :         m_oGCPSRS = PCI2SRS(pszMapUnits, pszProjParams);
     356             : 
     357             :     /* -------------------------------------------------------------------- */
     358             :     /*      Collect standalone GCPs.  They look like:                       */
     359             :     /*                                                                      */
     360             :     /*      GCP_1_n = row, col, x, y [,z [,"id"[, "desc"]]]                 */
     361             :     /* -------------------------------------------------------------------- */
     362           4 :     for (int i = 0; nGCPCount < MAX_GCP; i++)
     363             :     {
     364           4 :         char szName[50] = {'\0'};
     365           4 :         snprintf(szName, sizeof(szName), "GCP_1_%d", i + 1);
     366           4 :         if (CSLFetchNameValue(papszAuxLines, szName) == nullptr)
     367           4 :             break;
     368             : 
     369           0 :         char **papszTokens = CSLTokenizeStringComplex(
     370           0 :             CSLFetchNameValue(papszAuxLines, szName), " ", TRUE, FALSE);
     371             : 
     372           0 :         if (CSLCount(papszTokens) >= 4)
     373             :         {
     374           0 :             GDALInitGCPs(1, pasGCPList + nGCPCount);
     375             : 
     376           0 :             pasGCPList[nGCPCount].dfGCPX = CPLAtof(papszTokens[2]);
     377           0 :             pasGCPList[nGCPCount].dfGCPY = CPLAtof(papszTokens[3]);
     378           0 :             pasGCPList[nGCPCount].dfGCPPixel = CPLAtof(papszTokens[0]);
     379           0 :             pasGCPList[nGCPCount].dfGCPLine = CPLAtof(papszTokens[1]);
     380             : 
     381           0 :             if (CSLCount(papszTokens) > 4)
     382           0 :                 pasGCPList[nGCPCount].dfGCPZ = CPLAtof(papszTokens[4]);
     383             : 
     384           0 :             CPLFree(pasGCPList[nGCPCount].pszId);
     385           0 :             if (CSLCount(papszTokens) > 5)
     386             :             {
     387           0 :                 pasGCPList[nGCPCount].pszId = CPLStrdup(papszTokens[5]);
     388             :             }
     389             :             else
     390             :             {
     391           0 :                 snprintf(szName, sizeof(szName), "GCP_%d", i + 1);
     392           0 :                 pasGCPList[nGCPCount].pszId = CPLStrdup(szName);
     393             :             }
     394             : 
     395           0 :             if (CSLCount(papszTokens) > 6)
     396             :             {
     397           0 :                 CPLFree(pasGCPList[nGCPCount].pszInfo);
     398           0 :                 pasGCPList[nGCPCount].pszInfo = CPLStrdup(papszTokens[6]);
     399             :             }
     400             : 
     401           0 :             nGCPCount++;
     402             :         }
     403             : 
     404           0 :         CSLDestroy(papszTokens);
     405             :     }
     406           4 : }
     407             : 
     408             : /************************************************************************/
     409             : /*                            GetGCPCount()                             */
     410             : /************************************************************************/
     411             : 
     412           0 : int PAuxDataset::GetGCPCount()
     413             : 
     414             : {
     415           0 :     return nGCPCount;
     416             : }
     417             : 
     418             : /************************************************************************/
     419             : /*                               GetGCP()                               */
     420             : /************************************************************************/
     421             : 
     422           0 : const GDAL_GCP *PAuxDataset::GetGCPs()
     423             : 
     424             : {
     425           0 :     return pasGCPList;
     426             : }
     427             : 
     428             : /************************************************************************/
     429             : /*                          GetGeoTransform()                           */
     430             : /************************************************************************/
     431             : 
     432           0 : CPLErr PAuxDataset::GetGeoTransform(GDALGeoTransform &gt) const
     433             : 
     434             : {
     435           0 :     if (CSLFetchNameValue(papszAuxLines, "UpLeftX") == nullptr ||
     436           0 :         CSLFetchNameValue(papszAuxLines, "UpLeftY") == nullptr ||
     437           0 :         CSLFetchNameValue(papszAuxLines, "LoRightX") == nullptr ||
     438           0 :         CSLFetchNameValue(papszAuxLines, "LoRightY") == nullptr)
     439             :     {
     440           0 :         gt = GDALGeoTransform();
     441           0 :         return CE_Failure;
     442             :     }
     443             : 
     444             :     const double dfUpLeftX =
     445           0 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "UpLeftX"));
     446             :     const double dfUpLeftY =
     447           0 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "UpLeftY"));
     448             :     const double dfLoRightX =
     449           0 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "LoRightX"));
     450             :     const double dfLoRightY =
     451           0 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "LoRightY"));
     452             : 
     453           0 :     gt[0] = dfUpLeftX;
     454           0 :     gt[1] = (dfLoRightX - dfUpLeftX) / GetRasterXSize();
     455           0 :     gt[2] = 0.0;
     456           0 :     gt[3] = dfUpLeftY;
     457           0 :     gt[4] = 0.0;
     458           0 :     gt[5] = (dfLoRightY - dfUpLeftY) / GetRasterYSize();
     459             : 
     460           0 :     return CE_None;
     461             : }
     462             : 
     463             : /************************************************************************/
     464             : /*                                Open()                                */
     465             : /************************************************************************/
     466             : 
     467       33551 : GDALDataset *PAuxDataset::Open(GDALOpenInfo *poOpenInfo)
     468             : 
     469             : {
     470       33551 :     if (poOpenInfo->nHeaderBytes < 1)
     471       30071 :         return nullptr;
     472             : 
     473             :     /* -------------------------------------------------------------------- */
     474             :     /*      If this is an .aux file, fetch out and form the name of the     */
     475             :     /*      file it references.                                             */
     476             :     /* -------------------------------------------------------------------- */
     477             : 
     478        6960 :     CPLString osTarget = poOpenInfo->pszFilename;
     479             : 
     480        3482 :     if (poOpenInfo->IsExtensionEqualToCI("aux") &&
     481           2 :         STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
     482             :                        "AuxilaryTarget: "))
     483             :     {
     484           2 :         const char *pszSrc =
     485           2 :             reinterpret_cast<const char *>(poOpenInfo->pabyHeader + 16);
     486             : 
     487           2 :         char szAuxTarget[1024] = {'\0'};
     488           2 :         for (int i = 0; i < static_cast<int>(sizeof(szAuxTarget)) - 1 &&
     489          24 :                         pszSrc[i] != 10 && pszSrc[i] != 13 && pszSrc[i] != '\0';
     490             :              i++)
     491             :         {
     492          22 :             szAuxTarget[i] = pszSrc[i];
     493             :         }
     494           2 :         szAuxTarget[sizeof(szAuxTarget) - 1] = '\0';
     495             : 
     496           2 :         const std::string osPath(CPLGetPathSafe(poOpenInfo->pszFilename));
     497           2 :         osTarget = CPLFormFilenameSafe(osPath.c_str(), szAuxTarget, nullptr);
     498             :     }
     499             : 
     500             :     /* -------------------------------------------------------------------- */
     501             :     /*      Now we need to tear apart the filename to form a .aux           */
     502             :     /*      filename.                                                       */
     503             :     /* -------------------------------------------------------------------- */
     504        6960 :     CPLString osAuxFilename = CPLResetExtensionSafe(osTarget, "aux");
     505             : 
     506             :     /* -------------------------------------------------------------------- */
     507             :     /*      Do we have a .aux file?                                         */
     508             :     /* -------------------------------------------------------------------- */
     509        3480 :     char **papszSiblingFiles = poOpenInfo->GetSiblingFiles();
     510        6924 :     if (papszSiblingFiles != nullptr &&
     511        3444 :         CSLFindString(papszSiblingFiles, CPLGetFilename(osAuxFilename)) == -1)
     512             :     {
     513        3440 :         return nullptr;
     514             :     }
     515             : 
     516          40 :     VSILFILE *fp = VSIFOpenL(osAuxFilename, "r");
     517          40 :     if (fp == nullptr)
     518             :     {
     519          36 :         osAuxFilename = CPLResetExtensionSafe(osTarget, "AUX");
     520          36 :         fp = VSIFOpenL(osAuxFilename, "r");
     521             :     }
     522             : 
     523          40 :     if (fp == nullptr)
     524          36 :         return nullptr;
     525             : 
     526             :     /* -------------------------------------------------------------------- */
     527             :     /*      Is this file a PCI .aux file?  Check the first line for the     */
     528             :     /*      telltale AuxilaryTarget keyword.                                */
     529             :     /*                                                                      */
     530             :     /*      At this point we should be verifying that it refers to our      */
     531             :     /*      binary file, but that is a pretty involved test.                */
     532             :     /* -------------------------------------------------------------------- */
     533           4 :     CPLPushErrorHandler(CPLQuietErrorHandler);
     534           4 :     const char *pszLine = CPLReadLine2L(fp, 1024, nullptr);
     535           4 :     CPLPopErrorHandler();
     536             : 
     537           4 :     CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     538             : 
     539           4 :     if (pszLine == nullptr || (!STARTS_WITH_CI(pszLine, "AuxilaryTarget") &&
     540           0 :                                !STARTS_WITH_CI(pszLine, "AuxiliaryTarget")))
     541             :     {
     542           0 :         CPLErrorReset();
     543           0 :         return nullptr;
     544             :     }
     545             : 
     546             :     /* -------------------------------------------------------------------- */
     547             :     /*      Create a corresponding GDALDataset.                             */
     548             :     /* -------------------------------------------------------------------- */
     549           8 :     auto poDS = std::make_unique<PAuxDataset>();
     550             : 
     551             :     /* -------------------------------------------------------------------- */
     552             :     /*      Load the .aux file into a string list suitable to be            */
     553             :     /*      searched with CSLFetchNameValue().                              */
     554             :     /* -------------------------------------------------------------------- */
     555           4 :     poDS->papszAuxLines = CSLLoad2(osAuxFilename, 1024, 1024, nullptr);
     556           4 :     poDS->pszAuxFilename = CPLStrdup(osAuxFilename);
     557             : 
     558             :     /* -------------------------------------------------------------------- */
     559             :     /*      Find the RawDefinition line to establish overall parameters.    */
     560             :     /* -------------------------------------------------------------------- */
     561           4 :     pszLine = CSLFetchNameValue(poDS->papszAuxLines, "RawDefinition");
     562             : 
     563             :     // It seems PCI now writes out .aux files without RawDefinition in
     564             :     // some cases.  See bug 947.
     565           4 :     if (pszLine == nullptr)
     566             :     {
     567           0 :         return nullptr;
     568             :     }
     569             : 
     570           8 :     const CPLStringList aosTokens(CSLTokenizeString(pszLine));
     571             : 
     572           4 :     if (aosTokens.size() < 3)
     573             :     {
     574           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     575             :                  "RawDefinition missing or corrupt in %s.",
     576             :                  poOpenInfo->pszFilename);
     577           0 :         return nullptr;
     578             :     }
     579             : 
     580           4 :     poDS->nRasterXSize = atoi(aosTokens[0]);
     581           4 :     poDS->nRasterYSize = atoi(aosTokens[1]);
     582           4 :     int l_nBands = atoi(aosTokens[2]);
     583           4 :     poDS->eAccess = poOpenInfo->eAccess;
     584             : 
     585           8 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
     586           4 :         !GDALCheckBandCount(l_nBands, FALSE))
     587             :     {
     588           0 :         return nullptr;
     589             :     }
     590             : 
     591             :     /* -------------------------------------------------------------------- */
     592             :     /*      Open the file.                                                  */
     593             :     /* -------------------------------------------------------------------- */
     594           4 :     if (poOpenInfo->eAccess == GA_Update)
     595             :     {
     596           0 :         poDS->fpImage = VSIFOpenL(osTarget, "rb+");
     597             : 
     598           0 :         if (poDS->fpImage == nullptr)
     599             :         {
     600           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     601             :                      "File %s is missing or read-only, check permissions.",
     602             :                      osTarget.c_str());
     603           0 :             return nullptr;
     604             :         }
     605             :     }
     606             :     else
     607             :     {
     608           4 :         poDS->fpImage = VSIFOpenL(osTarget, "rb");
     609             : 
     610           4 :         if (poDS->fpImage == nullptr)
     611             :         {
     612           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     613             :                      "File %s is missing or unreadable.", osTarget.c_str());
     614           0 :             return nullptr;
     615             :         }
     616             :     }
     617             : 
     618             :     /* -------------------------------------------------------------------- */
     619             :     /*      Collect raw definitions of each channel and create              */
     620             :     /*      corresponding bands.                                            */
     621             :     /* -------------------------------------------------------------------- */
     622          12 :     for (int i = 0; i < l_nBands; i++)
     623             :     {
     624           8 :         char szDefnName[32] = {'\0'};
     625           8 :         snprintf(szDefnName, sizeof(szDefnName), "ChanDefinition-%d", i + 1);
     626             : 
     627           8 :         pszLine = CSLFetchNameValue(poDS->papszAuxLines, szDefnName);
     628           8 :         if (pszLine == nullptr)
     629             :         {
     630           0 :             continue;
     631             :         }
     632             : 
     633           8 :         const CPLStringList aosTokensBand(CSLTokenizeString(pszLine));
     634           8 :         if (aosTokensBand.size() < 4)
     635             :         {
     636             :             // Skip the band with broken description
     637           0 :             continue;
     638             :         }
     639             : 
     640           8 :         GDALDataType eType = GDT_Unknown;
     641           8 :         if (EQUAL(aosTokensBand[0], "16U"))
     642           8 :             eType = GDT_UInt16;
     643           0 :         else if (EQUAL(aosTokensBand[0], "16S"))
     644           0 :             eType = GDT_Int16;
     645           0 :         else if (EQUAL(aosTokensBand[0], "32R"))
     646           0 :             eType = GDT_Float32;
     647             :         else
     648           0 :             eType = GDT_Byte;
     649             : 
     650           8 :         bool bNative = true;
     651           8 :         if (CSLCount(aosTokensBand) > 4)
     652             :         {
     653             : #ifdef CPL_LSB
     654           8 :             bNative = EQUAL(aosTokensBand[4], "Swapped");
     655             : #else
     656             :             bNative = EQUAL(aosTokensBand[4], "Unswapped");
     657             : #endif
     658             :         }
     659             : 
     660           8 :         const vsi_l_offset nBandOffset = CPLScanUIntBig(
     661           8 :             aosTokensBand[1], static_cast<int>(strlen(aosTokensBand[1])));
     662           8 :         const int nPixelOffset = atoi(aosTokensBand[2]);
     663           8 :         const int nLineOffset = atoi(aosTokensBand[3]);
     664             : 
     665           8 :         if (nPixelOffset <= 0 || nLineOffset <= 0)
     666             :         {
     667             :             // Skip the band with broken offsets.
     668           0 :             continue;
     669             :         }
     670             : 
     671             :         auto poBand = std::make_unique<PAuxRasterBand>(
     672           8 :             poDS.get(), poDS->nBands + 1, poDS->fpImage, nBandOffset,
     673           8 :             nPixelOffset, nLineOffset, eType, bNative);
     674           8 :         if (!poBand->IsValid())
     675           0 :             return nullptr;
     676           8 :         poDS->SetBand(poDS->nBands + 1, std::move(poBand));
     677             :     }
     678             : 
     679             :     /* -------------------------------------------------------------------- */
     680             :     /*      Get the projection.                                             */
     681             :     /* -------------------------------------------------------------------- */
     682             :     const char *pszMapUnits =
     683           4 :         CSLFetchNameValue(poDS->papszAuxLines, "MapUnits");
     684             :     const char *pszProjParams =
     685           4 :         CSLFetchNameValue(poDS->papszAuxLines, "ProjParams");
     686             : 
     687           4 :     if (pszMapUnits != nullptr)
     688             :     {
     689           4 :         poDS->m_oSRS = PCI2SRS(pszMapUnits, pszProjParams);
     690             :     }
     691             : 
     692             :     /* -------------------------------------------------------------------- */
     693             :     /*      Initialize any PAM information.                                 */
     694             :     /* -------------------------------------------------------------------- */
     695           4 :     poDS->SetDescription(osTarget);
     696           4 :     poDS->TryLoadXML();
     697             : 
     698             :     /* -------------------------------------------------------------------- */
     699             :     /*      Check for overviews.                                            */
     700             :     /* -------------------------------------------------------------------- */
     701           4 :     poDS->oOvManager.Initialize(poDS.get(), osTarget);
     702             : 
     703           4 :     poDS->ScanForGCPs();
     704             : 
     705           4 :     return poDS.release();
     706             : }
     707             : 
     708             : /************************************************************************/
     709             : /*                         GDALRegister_PAux()                          */
     710             : /************************************************************************/
     711             : 
     712        1935 : void GDALRegister_PAux()
     713             : 
     714             : {
     715        1935 :     if (GDALGetDriverByName("PAux") != nullptr)
     716         282 :         return;
     717             : 
     718        1653 :     GDALDriver *poDriver = new GDALDriver();
     719             : 
     720        1653 :     poDriver->SetDescription("PAux");
     721        1653 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     722        1653 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "PCI .aux Labelled");
     723        1653 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/paux.html");
     724        1653 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     725             : 
     726        1653 :     poDriver->pfnOpen = PAuxDataset::Open;
     727             : 
     728        1653 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     729             : }

Generated by: LCOV version 1.14