LCOV - code coverage report
Current view: top level - frmts/raw - pauxdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 156 264 59.1 %
Date: 2025-10-18 18:51:02 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 "gdal_priv.h"
      17             : #include "ogr_spatialref.h"
      18             : #include "rawdataset.h"
      19             : 
      20             : #include <cmath>
      21             : 
      22             : /************************************************************************/
      23             : /* ==================================================================== */
      24             : /*                              PAuxDataset                             */
      25             : /* ==================================================================== */
      26             : /************************************************************************/
      27             : 
      28             : class PAuxRasterBand;
      29             : 
      30             : class PAuxDataset final : public RawDataset
      31             : {
      32             :     friend class PAuxRasterBand;
      33             : 
      34             :     VSILFILE *fpImage;  // Image data file.
      35             : 
      36             :     int nGCPCount;
      37             :     GDAL_GCP *pasGCPList;
      38             :     OGRSpatialReference m_oGCPSRS{};
      39             : 
      40             :     void ScanForGCPs();
      41             :     static OGRSpatialReference PCI2SRS(const char *pszGeosys,
      42             :                                        const char *pszProjParams);
      43             : 
      44             :     OGRSpatialReference m_oSRS{};
      45             : 
      46             :     CPL_DISALLOW_COPY_ASSIGN(PAuxDataset)
      47             : 
      48             :     CPLErr Close() override;
      49             : 
      50             :   public:
      51             :     PAuxDataset();
      52             :     ~PAuxDataset() override;
      53             : 
      54             :     // TODO(schwehr): Why are these public?
      55             :     char *pszAuxFilename;
      56             :     char **papszAuxLines;
      57             : 
      58           0 :     const OGRSpatialReference *GetSpatialRef() const override
      59             :     {
      60           0 :         return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
      61             :     }
      62             : 
      63             :     CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
      64             : 
      65             :     int GetGCPCount() override;
      66             : 
      67           0 :     const OGRSpatialReference *GetGCPSpatialRef() const override
      68             :     {
      69           0 :         return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
      70             :     }
      71             : 
      72             :     const GDAL_GCP *GetGCPs() override;
      73             : 
      74             :     char **GetFileList() override;
      75             : 
      76             :     static GDALDataset *Open(GDALOpenInfo *);
      77             : };
      78             : 
      79             : /************************************************************************/
      80             : /* ==================================================================== */
      81             : /*                           PAuxRasterBand                             */
      82             : /* ==================================================================== */
      83             : /************************************************************************/
      84             : 
      85             : class PAuxRasterBand final : public RawRasterBand
      86             : {
      87             :     CPL_DISALLOW_COPY_ASSIGN(PAuxRasterBand)
      88             : 
      89             :   public:
      90             :     PAuxRasterBand(GDALDataset *poDS, int nBand, VSILFILE *fpRaw,
      91             :                    vsi_l_offset nImgOffset, int nPixelOffset, int nLineOffset,
      92             :                    GDALDataType eDataType, int bNativeOrder);
      93             : 
      94             :     ~PAuxRasterBand() override;
      95             : 
      96             :     double GetNoDataValue(int *pbSuccess = nullptr) override;
      97             : 
      98             :     GDALColorTable *GetColorTable() override;
      99             :     GDALColorInterp GetColorInterpretation() override;
     100             : };
     101             : 
     102             : /************************************************************************/
     103             : /*                           PAuxRasterBand()                           */
     104             : /************************************************************************/
     105             : 
     106           8 : PAuxRasterBand::PAuxRasterBand(GDALDataset *poDSIn, int nBandIn,
     107             :                                VSILFILE *fpRawIn, vsi_l_offset nImgOffsetIn,
     108             :                                int nPixelOffsetIn, int nLineOffsetIn,
     109           8 :                                GDALDataType eDataTypeIn, int bNativeOrderIn)
     110             :     : RawRasterBand(poDSIn, nBandIn, fpRawIn, nImgOffsetIn, nPixelOffsetIn,
     111             :                     nLineOffsetIn, eDataTypeIn, bNativeOrderIn,
     112           8 :                     RawRasterBand::OwnFP::NO)
     113             : {
     114           8 :     PAuxDataset *poPDS = cpl::down_cast<PAuxDataset *>(poDS);
     115             : 
     116             :     /* -------------------------------------------------------------------- */
     117             :     /*      Does this channel have a description?                           */
     118             :     /* -------------------------------------------------------------------- */
     119           8 :     char szTarget[128] = {'\0'};
     120             : 
     121           8 :     snprintf(szTarget, sizeof(szTarget), "ChanDesc-%d", nBand);
     122           8 :     if (CSLFetchNameValue(poPDS->papszAuxLines, szTarget) != nullptr)
     123           0 :         GDALRasterBand::SetDescription(
     124           0 :             CSLFetchNameValue(poPDS->papszAuxLines, szTarget));
     125             : 
     126             :     /* -------------------------------------------------------------------- */
     127             :     /*      See if we have colors.  Currently we must have color zero,      */
     128             :     /*      but this should not really be a limitation.                     */
     129             :     /* -------------------------------------------------------------------- */
     130           8 :     snprintf(szTarget, sizeof(szTarget), "METADATA_IMG_%d_Class_%d_Color",
     131             :              nBand, 0);
     132           8 :     if (CSLFetchNameValue(poPDS->papszAuxLines, szTarget) != nullptr)
     133             :     {
     134           0 :         poCT = new GDALColorTable();
     135             : 
     136           0 :         for (int i = 0; i < 256; i++)
     137             :         {
     138           0 :             snprintf(szTarget, sizeof(szTarget),
     139             :                      "METADATA_IMG_%d_Class_%d_Color", nBand, i);
     140             :             const char *pszLine =
     141           0 :                 CSLFetchNameValue(poPDS->papszAuxLines, szTarget);
     142           0 :             while (pszLine && *pszLine == ' ')
     143           0 :                 pszLine++;
     144             : 
     145           0 :             int nRed = 0;
     146           0 :             int nGreen = 0;
     147           0 :             int nBlue = 0;
     148             :             // TODO(schwehr): Replace sscanf with something safe.
     149           0 :             if (pszLine != nullptr && STARTS_WITH_CI(pszLine, "(RGB:") &&
     150           0 :                 sscanf(pszLine + 5, "%d %d %d", &nRed, &nGreen, &nBlue) == 3)
     151             :             {
     152           0 :                 GDALColorEntry oColor = {static_cast<short>(nRed),
     153             :                                          static_cast<short>(nGreen),
     154           0 :                                          static_cast<short>(nBlue), 255};
     155             : 
     156           0 :                 poCT->SetColorEntry(i, &oColor);
     157             :             }
     158             :         }
     159             :     }
     160           8 : }
     161             : 
     162             : /************************************************************************/
     163             : /*                          ~PAuxRasterBand()                           */
     164             : /************************************************************************/
     165             : 
     166          16 : PAuxRasterBand::~PAuxRasterBand()
     167             : 
     168             : {
     169          16 : }
     170             : 
     171             : /************************************************************************/
     172             : /*                           GetNoDataValue()                           */
     173             : /************************************************************************/
     174             : 
     175           0 : double PAuxRasterBand::GetNoDataValue(int *pbSuccess)
     176             : 
     177             : {
     178           0 :     char szTarget[128] = {'\0'};
     179           0 :     snprintf(szTarget, sizeof(szTarget), "METADATA_IMG_%d_NO_DATA_VALUE",
     180             :              nBand);
     181             : 
     182           0 :     PAuxDataset *poPDS = cpl::down_cast<PAuxDataset *>(poDS);
     183           0 :     const char *pszLine = CSLFetchNameValue(poPDS->papszAuxLines, szTarget);
     184             : 
     185           0 :     if (pbSuccess != nullptr)
     186           0 :         *pbSuccess = (pszLine != nullptr);
     187             : 
     188           0 :     if (pszLine == nullptr)
     189           0 :         return -1.0e8;
     190             : 
     191           0 :     return CPLAtof(pszLine);
     192             : }
     193             : 
     194             : /************************************************************************/
     195             : /*                           GetColorTable()                            */
     196             : /************************************************************************/
     197             : 
     198           0 : GDALColorTable *PAuxRasterBand::GetColorTable()
     199             : 
     200             : {
     201           0 :     return poCT;
     202             : }
     203             : 
     204             : /************************************************************************/
     205             : /*                       GetColorInterpretation()                       */
     206             : /************************************************************************/
     207             : 
     208           0 : GDALColorInterp PAuxRasterBand::GetColorInterpretation()
     209             : 
     210             : {
     211           0 :     if (poCT == nullptr)
     212           0 :         return GCI_Undefined;
     213             : 
     214           0 :     return GCI_PaletteIndex;
     215             : }
     216             : 
     217             : /************************************************************************/
     218             : /* ==================================================================== */
     219             : /*                              PAuxDataset                             */
     220             : /* ==================================================================== */
     221             : /************************************************************************/
     222             : 
     223             : /************************************************************************/
     224             : /*                            PAuxDataset()                             */
     225             : /************************************************************************/
     226             : 
     227           4 : PAuxDataset::PAuxDataset()
     228             :     : fpImage(nullptr), nGCPCount(0), pasGCPList(nullptr),
     229           4 :       pszAuxFilename(nullptr), papszAuxLines(nullptr)
     230             : {
     231           4 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     232           4 :     m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     233           4 : }
     234             : 
     235             : /************************************************************************/
     236             : /*                            ~PAuxDataset()                            */
     237             : /************************************************************************/
     238             : 
     239           8 : PAuxDataset::~PAuxDataset()
     240             : 
     241             : {
     242           4 :     PAuxDataset::Close();
     243           8 : }
     244             : 
     245             : /************************************************************************/
     246             : /*                              Close()                                 */
     247             : /************************************************************************/
     248             : 
     249           8 : CPLErr PAuxDataset::Close()
     250             : {
     251           8 :     CPLErr eErr = CE_None;
     252           8 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
     253             :     {
     254           4 :         if (PAuxDataset::FlushCache(true) != CE_None)
     255           0 :             eErr = CE_Failure;
     256             : 
     257           4 :         if (fpImage != nullptr)
     258             :         {
     259           4 :             if (VSIFCloseL(fpImage) != 0)
     260             :             {
     261           0 :                 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     262           0 :                 eErr = CE_Failure;
     263             :             }
     264             :         }
     265             : 
     266           4 :         GDALDeinitGCPs(nGCPCount, pasGCPList);
     267           4 :         CPLFree(pasGCPList);
     268             : 
     269           4 :         CPLFree(pszAuxFilename);
     270           4 :         CSLDestroy(papszAuxLines);
     271             : 
     272           4 :         if (GDALPamDataset::Close() != CE_None)
     273           0 :             eErr = CE_Failure;
     274             :     }
     275           8 :     return eErr;
     276             : }
     277             : 
     278             : /************************************************************************/
     279             : /*                            GetFileList()                             */
     280             : /************************************************************************/
     281             : 
     282           1 : char **PAuxDataset::GetFileList()
     283             : 
     284             : {
     285           1 :     char **papszFileList = RawDataset::GetFileList();
     286           1 :     papszFileList = CSLAddString(papszFileList, pszAuxFilename);
     287           1 :     return papszFileList;
     288             : }
     289             : 
     290             : /************************************************************************/
     291             : /*                              PCI2SRS()                               */
     292             : /*                                                                      */
     293             : /*      Convert PCI coordinate system to WKT.  For now this is very     */
     294             : /*      incomplete, but can be filled out in the future.                */
     295             : /************************************************************************/
     296             : 
     297           8 : OGRSpatialReference PAuxDataset::PCI2SRS(const char *pszGeosys,
     298             :                                          const char *pszProjParams)
     299             : 
     300             : {
     301           8 :     while (*pszGeosys == ' ')
     302           4 :         pszGeosys++;
     303             : 
     304             :     /* -------------------------------------------------------------------- */
     305             :     /*      Parse projection parameters array.                              */
     306             :     /* -------------------------------------------------------------------- */
     307           4 :     double adfProjParams[16] = {0.0};
     308             : 
     309           4 :     if (pszProjParams != nullptr)
     310             :     {
     311           4 :         char **papszTokens = CSLTokenizeString(pszProjParams);
     312             : 
     313           4 :         for (int i = 0;
     314          68 :              i < 16 && papszTokens != nullptr && papszTokens[i] != nullptr; i++)
     315          64 :             adfProjParams[i] = CPLAtof(papszTokens[i]);
     316             : 
     317           4 :         CSLDestroy(papszTokens);
     318             :     }
     319             : 
     320             :     /* -------------------------------------------------------------------- */
     321             :     /*      Convert to SRS.                                                 */
     322             :     /* -------------------------------------------------------------------- */
     323           4 :     OGRSpatialReference oSRS;
     324           4 :     oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     325           4 :     if (oSRS.importFromPCI(pszGeosys, nullptr, adfProjParams) != OGRERR_NONE)
     326             :     {
     327           0 :         oSRS.Clear();
     328             :     }
     329             : 
     330           8 :     return oSRS;
     331             : }
     332             : 
     333             : /************************************************************************/
     334             : /*                            ScanForGCPs()                             */
     335             : /************************************************************************/
     336             : 
     337           4 : void PAuxDataset::ScanForGCPs()
     338             : 
     339             : {
     340           4 :     const int MAX_GCP = 256;
     341             : 
     342           4 :     nGCPCount = 0;
     343           4 :     CPLAssert(pasGCPList == nullptr);
     344           4 :     pasGCPList = static_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       31613 : GDALDataset *PAuxDataset::Open(GDALOpenInfo *poOpenInfo)
     468             : 
     469             : {
     470       33122 :     if (poOpenInfo->nHeaderBytes < 1 ||
     471        3018 :         (!poOpenInfo->IsSingleAllowedDriver("PAux") &&
     472        1509 :          poOpenInfo->IsExtensionEqualToCI("zarr")))
     473             :     {
     474       30099 :         return nullptr;
     475             :     }
     476             : 
     477             :     /* -------------------------------------------------------------------- */
     478             :     /*      If this is an .aux file, fetch out and form the name of the     */
     479             :     /*      file it references.                                             */
     480             :     /* -------------------------------------------------------------------- */
     481             : 
     482        3023 :     CPLString osTarget = poOpenInfo->pszFilename;
     483             : 
     484        1511 :     if (poOpenInfo->IsExtensionEqualToCI("aux") &&
     485           2 :         STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
     486             :                        "AuxilaryTarget: "))
     487             :     {
     488           2 :         const char *pszSrc =
     489           2 :             reinterpret_cast<const char *>(poOpenInfo->pabyHeader + 16);
     490             : 
     491           2 :         char szAuxTarget[1024] = {'\0'};
     492           2 :         for (int i = 0; i < static_cast<int>(sizeof(szAuxTarget)) - 1 &&
     493          24 :                         pszSrc[i] != 10 && pszSrc[i] != 13 && pszSrc[i] != '\0';
     494             :              i++)
     495             :         {
     496          22 :             szAuxTarget[i] = pszSrc[i];
     497             :         }
     498           2 :         szAuxTarget[sizeof(szAuxTarget) - 1] = '\0';
     499             : 
     500           2 :         if (CPLHasPathTraversal(szAuxTarget))
     501             :         {
     502           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     503             :                      "Path traversal detected in %s", szAuxTarget);
     504           0 :             return nullptr;
     505             :         }
     506           2 :         const std::string osPath(CPLGetPathSafe(poOpenInfo->pszFilename));
     507           2 :         osTarget = CPLFormFilenameSafe(osPath.c_str(), szAuxTarget, nullptr);
     508             :     }
     509             : 
     510             :     /* -------------------------------------------------------------------- */
     511             :     /*      Now we need to tear apart the filename to form a .aux           */
     512             :     /*      filename.                                                       */
     513             :     /* -------------------------------------------------------------------- */
     514        3018 :     CPLString osAuxFilename = CPLResetExtensionSafe(osTarget, "aux");
     515             : 
     516             :     /* -------------------------------------------------------------------- */
     517             :     /*      Do we have a .aux file?                                         */
     518             :     /* -------------------------------------------------------------------- */
     519        1509 :     CSLConstList papszSiblingFiles = poOpenInfo->GetSiblingFiles();
     520        3010 :     if (papszSiblingFiles != nullptr &&
     521        1501 :         CSLFindString(papszSiblingFiles, CPLGetFilename(osAuxFilename)) == -1)
     522             :     {
     523        1497 :         return nullptr;
     524             :     }
     525             : 
     526          12 :     VSILFILE *fp = VSIFOpenL(osAuxFilename, "r");
     527          12 :     if (fp == nullptr)
     528             :     {
     529           8 :         osAuxFilename = CPLResetExtensionSafe(osTarget, "AUX");
     530           8 :         fp = VSIFOpenL(osAuxFilename, "r");
     531             :     }
     532             : 
     533          12 :     if (fp == nullptr)
     534           8 :         return nullptr;
     535             : 
     536             :     /* -------------------------------------------------------------------- */
     537             :     /*      Is this file a PCI .aux file?  Check the first line for the     */
     538             :     /*      telltale AuxilaryTarget keyword.                                */
     539             :     /*                                                                      */
     540             :     /*      At this point we should be verifying that it refers to our      */
     541             :     /*      binary file, but that is a pretty involved test.                */
     542             :     /* -------------------------------------------------------------------- */
     543           4 :     CPLPushErrorHandler(CPLQuietErrorHandler);
     544           4 :     const char *pszLine = CPLReadLine2L(fp, 1024, nullptr);
     545           4 :     CPLPopErrorHandler();
     546             : 
     547           4 :     CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     548             : 
     549           4 :     if (pszLine == nullptr || (!STARTS_WITH_CI(pszLine, "AuxilaryTarget") &&
     550           0 :                                !STARTS_WITH_CI(pszLine, "AuxiliaryTarget")))
     551             :     {
     552           0 :         CPLErrorReset();
     553           0 :         return nullptr;
     554             :     }
     555             : 
     556             :     /* -------------------------------------------------------------------- */
     557             :     /*      Create a corresponding GDALDataset.                             */
     558             :     /* -------------------------------------------------------------------- */
     559           8 :     auto poDS = std::make_unique<PAuxDataset>();
     560             : 
     561             :     /* -------------------------------------------------------------------- */
     562             :     /*      Load the .aux file into a string list suitable to be            */
     563             :     /*      searched with CSLFetchNameValue().                              */
     564             :     /* -------------------------------------------------------------------- */
     565           4 :     poDS->papszAuxLines = CSLLoad2(osAuxFilename, 1024, 1024, nullptr);
     566           4 :     poDS->pszAuxFilename = CPLStrdup(osAuxFilename);
     567             : 
     568             :     /* -------------------------------------------------------------------- */
     569             :     /*      Find the RawDefinition line to establish overall parameters.    */
     570             :     /* -------------------------------------------------------------------- */
     571           4 :     pszLine = CSLFetchNameValue(poDS->papszAuxLines, "RawDefinition");
     572             : 
     573             :     // It seems PCI now writes out .aux files without RawDefinition in
     574             :     // some cases.  See bug 947.
     575           4 :     if (pszLine == nullptr)
     576             :     {
     577           0 :         return nullptr;
     578             :     }
     579             : 
     580           8 :     const CPLStringList aosTokens(CSLTokenizeString(pszLine));
     581             : 
     582           4 :     if (aosTokens.size() < 3)
     583             :     {
     584           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     585             :                  "RawDefinition missing or corrupt in %s.",
     586             :                  poOpenInfo->pszFilename);
     587           0 :         return nullptr;
     588             :     }
     589             : 
     590           4 :     poDS->nRasterXSize = atoi(aosTokens[0]);
     591           4 :     poDS->nRasterYSize = atoi(aosTokens[1]);
     592           4 :     int l_nBands = atoi(aosTokens[2]);
     593           4 :     poDS->eAccess = poOpenInfo->eAccess;
     594             : 
     595           8 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
     596           4 :         !GDALCheckBandCount(l_nBands, FALSE))
     597             :     {
     598           0 :         return nullptr;
     599             :     }
     600             : 
     601             :     /* -------------------------------------------------------------------- */
     602             :     /*      Open the file.                                                  */
     603             :     /* -------------------------------------------------------------------- */
     604           4 :     if (poOpenInfo->eAccess == GA_Update)
     605             :     {
     606           0 :         poDS->fpImage = VSIFOpenL(osTarget, "rb+");
     607             : 
     608           0 :         if (poDS->fpImage == nullptr)
     609             :         {
     610           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     611             :                      "File %s is missing or read-only, check permissions.",
     612             :                      osTarget.c_str());
     613           0 :             return nullptr;
     614             :         }
     615             :     }
     616             :     else
     617             :     {
     618           4 :         poDS->fpImage = VSIFOpenL(osTarget, "rb");
     619             : 
     620           4 :         if (poDS->fpImage == nullptr)
     621             :         {
     622           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     623             :                      "File %s is missing or unreadable.", osTarget.c_str());
     624           0 :             return nullptr;
     625             :         }
     626             :     }
     627             : 
     628             :     /* -------------------------------------------------------------------- */
     629             :     /*      Collect raw definitions of each channel and create              */
     630             :     /*      corresponding bands.                                            */
     631             :     /* -------------------------------------------------------------------- */
     632          12 :     for (int i = 0; i < l_nBands; i++)
     633             :     {
     634           8 :         char szDefnName[32] = {'\0'};
     635           8 :         snprintf(szDefnName, sizeof(szDefnName), "ChanDefinition-%d", i + 1);
     636             : 
     637           8 :         pszLine = CSLFetchNameValue(poDS->papszAuxLines, szDefnName);
     638           8 :         if (pszLine == nullptr)
     639             :         {
     640           0 :             continue;
     641             :         }
     642             : 
     643           8 :         const CPLStringList aosTokensBand(CSLTokenizeString(pszLine));
     644           8 :         if (aosTokensBand.size() < 4)
     645             :         {
     646             :             // Skip the band with broken description
     647           0 :             continue;
     648             :         }
     649             : 
     650           8 :         GDALDataType eType = GDT_Unknown;
     651           8 :         if (EQUAL(aosTokensBand[0], "16U"))
     652           8 :             eType = GDT_UInt16;
     653           0 :         else if (EQUAL(aosTokensBand[0], "16S"))
     654           0 :             eType = GDT_Int16;
     655           0 :         else if (EQUAL(aosTokensBand[0], "32R"))
     656           0 :             eType = GDT_Float32;
     657             :         else
     658           0 :             eType = GDT_Byte;
     659             : 
     660           8 :         bool bNative = true;
     661           8 :         if (CSLCount(aosTokensBand) > 4)
     662             :         {
     663             : #ifdef CPL_LSB
     664           8 :             bNative = EQUAL(aosTokensBand[4], "Swapped");
     665             : #else
     666             :             bNative = EQUAL(aosTokensBand[4], "Unswapped");
     667             : #endif
     668             :         }
     669             : 
     670           8 :         const vsi_l_offset nBandOffset = CPLScanUIntBig(
     671           8 :             aosTokensBand[1], static_cast<int>(strlen(aosTokensBand[1])));
     672           8 :         const int nPixelOffset = atoi(aosTokensBand[2]);
     673           8 :         const int nLineOffset = atoi(aosTokensBand[3]);
     674             : 
     675           8 :         if (nPixelOffset <= 0 || nLineOffset <= 0)
     676             :         {
     677             :             // Skip the band with broken offsets.
     678           0 :             continue;
     679             :         }
     680             : 
     681             :         auto poBand = std::make_unique<PAuxRasterBand>(
     682           8 :             poDS.get(), poDS->nBands + 1, poDS->fpImage, nBandOffset,
     683           8 :             nPixelOffset, nLineOffset, eType, bNative);
     684           8 :         if (!poBand->IsValid())
     685           0 :             return nullptr;
     686           8 :         poDS->SetBand(poDS->nBands + 1, std::move(poBand));
     687             :     }
     688             : 
     689             :     /* -------------------------------------------------------------------- */
     690             :     /*      Get the projection.                                             */
     691             :     /* -------------------------------------------------------------------- */
     692             :     const char *pszMapUnits =
     693           4 :         CSLFetchNameValue(poDS->papszAuxLines, "MapUnits");
     694             :     const char *pszProjParams =
     695           4 :         CSLFetchNameValue(poDS->papszAuxLines, "ProjParams");
     696             : 
     697           4 :     if (pszMapUnits != nullptr)
     698             :     {
     699           4 :         poDS->m_oSRS = PCI2SRS(pszMapUnits, pszProjParams);
     700             :     }
     701             : 
     702             :     /* -------------------------------------------------------------------- */
     703             :     /*      Initialize any PAM information.                                 */
     704             :     /* -------------------------------------------------------------------- */
     705           4 :     poDS->SetDescription(osTarget);
     706           4 :     poDS->TryLoadXML();
     707             : 
     708             :     /* -------------------------------------------------------------------- */
     709             :     /*      Check for overviews.                                            */
     710             :     /* -------------------------------------------------------------------- */
     711           4 :     poDS->oOvManager.Initialize(poDS.get(), osTarget);
     712             : 
     713           4 :     poDS->ScanForGCPs();
     714             : 
     715           4 :     return poDS.release();
     716             : }
     717             : 
     718             : /************************************************************************/
     719             : /*                         GDALRegister_PAux()                          */
     720             : /************************************************************************/
     721             : 
     722        2033 : void GDALRegister_PAux()
     723             : 
     724             : {
     725        2033 :     if (GDALGetDriverByName("PAux") != nullptr)
     726         283 :         return;
     727             : 
     728        1750 :     GDALDriver *poDriver = new GDALDriver();
     729             : 
     730        1750 :     poDriver->SetDescription("PAux");
     731        1750 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     732        1750 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "PCI .aux Labelled");
     733        1750 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/paux.html");
     734        1750 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     735             : 
     736        1750 :     poDriver->pfnOpen = PAuxDataset::Open;
     737             : 
     738        1750 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     739             : }

Generated by: LCOV version 1.14