LCOV - code coverage report
Current view: top level - frmts/raw - pauxdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 154 265 58.1 %
Date: 2025-03-28 21:34:50 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(double *) 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(double *padfGeoTransform)
     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 :         padfGeoTransform[0] = 0.0;
     441           0 :         padfGeoTransform[1] = 1.0;
     442           0 :         padfGeoTransform[2] = 0.0;
     443           0 :         padfGeoTransform[3] = 0.0;
     444           0 :         padfGeoTransform[4] = 0.0;
     445           0 :         padfGeoTransform[5] = 1.0;
     446             : 
     447           0 :         return CE_Failure;
     448             :     }
     449             : 
     450             :     const double dfUpLeftX =
     451           0 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "UpLeftX"));
     452             :     const double dfUpLeftY =
     453           0 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "UpLeftY"));
     454             :     const double dfLoRightX =
     455           0 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "LoRightX"));
     456             :     const double dfLoRightY =
     457           0 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "LoRightY"));
     458             : 
     459           0 :     padfGeoTransform[0] = dfUpLeftX;
     460           0 :     padfGeoTransform[1] = (dfLoRightX - dfUpLeftX) / GetRasterXSize();
     461           0 :     padfGeoTransform[2] = 0.0;
     462           0 :     padfGeoTransform[3] = dfUpLeftY;
     463           0 :     padfGeoTransform[4] = 0.0;
     464           0 :     padfGeoTransform[5] = (dfLoRightY - dfUpLeftY) / GetRasterYSize();
     465             : 
     466           0 :     return CE_None;
     467             : }
     468             : 
     469             : /************************************************************************/
     470             : /*                                Open()                                */
     471             : /************************************************************************/
     472             : 
     473       29542 : GDALDataset *PAuxDataset::Open(GDALOpenInfo *poOpenInfo)
     474             : 
     475             : {
     476       29542 :     if (poOpenInfo->nHeaderBytes < 1)
     477       26180 :         return nullptr;
     478             : 
     479             :     /* -------------------------------------------------------------------- */
     480             :     /*      If this is an .aux file, fetch out and form the name of the     */
     481             :     /*      file it references.                                             */
     482             :     /* -------------------------------------------------------------------- */
     483             : 
     484        6724 :     CPLString osTarget = poOpenInfo->pszFilename;
     485             : 
     486        3364 :     if (poOpenInfo->IsExtensionEqualToCI("aux") &&
     487           2 :         STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
     488             :                        "AuxilaryTarget: "))
     489             :     {
     490           2 :         const char *pszSrc =
     491           2 :             reinterpret_cast<const char *>(poOpenInfo->pabyHeader + 16);
     492             : 
     493           2 :         char szAuxTarget[1024] = {'\0'};
     494           2 :         for (int i = 0; i < static_cast<int>(sizeof(szAuxTarget)) - 1 &&
     495          24 :                         pszSrc[i] != 10 && pszSrc[i] != 13 && pszSrc[i] != '\0';
     496             :              i++)
     497             :         {
     498          22 :             szAuxTarget[i] = pszSrc[i];
     499             :         }
     500           2 :         szAuxTarget[sizeof(szAuxTarget) - 1] = '\0';
     501             : 
     502           2 :         const std::string osPath(CPLGetPathSafe(poOpenInfo->pszFilename));
     503           2 :         osTarget = CPLFormFilenameSafe(osPath.c_str(), szAuxTarget, nullptr);
     504             :     }
     505             : 
     506             :     /* -------------------------------------------------------------------- */
     507             :     /*      Now we need to tear apart the filename to form a .aux           */
     508             :     /*      filename.                                                       */
     509             :     /* -------------------------------------------------------------------- */
     510        6724 :     CPLString osAuxFilename = CPLResetExtensionSafe(osTarget, "aux");
     511             : 
     512             :     /* -------------------------------------------------------------------- */
     513             :     /*      Do we have a .aux file?                                         */
     514             :     /* -------------------------------------------------------------------- */
     515        3362 :     char **papszSiblingFiles = poOpenInfo->GetSiblingFiles();
     516        6688 :     if (papszSiblingFiles != nullptr &&
     517        3326 :         CSLFindString(papszSiblingFiles, CPLGetFilename(osAuxFilename)) == -1)
     518             :     {
     519        3322 :         return nullptr;
     520             :     }
     521             : 
     522          40 :     VSILFILE *fp = VSIFOpenL(osAuxFilename, "r");
     523          40 :     if (fp == nullptr)
     524             :     {
     525          36 :         osAuxFilename = CPLResetExtensionSafe(osTarget, "AUX");
     526          36 :         fp = VSIFOpenL(osAuxFilename, "r");
     527             :     }
     528             : 
     529          40 :     if (fp == nullptr)
     530          36 :         return nullptr;
     531             : 
     532             :     /* -------------------------------------------------------------------- */
     533             :     /*      Is this file a PCI .aux file?  Check the first line for the     */
     534             :     /*      telltale AuxilaryTarget keyword.                                */
     535             :     /*                                                                      */
     536             :     /*      At this point we should be verifying that it refers to our      */
     537             :     /*      binary file, but that is a pretty involved test.                */
     538             :     /* -------------------------------------------------------------------- */
     539           4 :     CPLPushErrorHandler(CPLQuietErrorHandler);
     540           4 :     const char *pszLine = CPLReadLine2L(fp, 1024, nullptr);
     541           4 :     CPLPopErrorHandler();
     542             : 
     543           4 :     CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     544             : 
     545           4 :     if (pszLine == nullptr || (!STARTS_WITH_CI(pszLine, "AuxilaryTarget") &&
     546           0 :                                !STARTS_WITH_CI(pszLine, "AuxiliaryTarget")))
     547             :     {
     548           0 :         CPLErrorReset();
     549           0 :         return nullptr;
     550             :     }
     551             : 
     552             :     /* -------------------------------------------------------------------- */
     553             :     /*      Create a corresponding GDALDataset.                             */
     554             :     /* -------------------------------------------------------------------- */
     555           8 :     auto poDS = std::make_unique<PAuxDataset>();
     556             : 
     557             :     /* -------------------------------------------------------------------- */
     558             :     /*      Load the .aux file into a string list suitable to be            */
     559             :     /*      searched with CSLFetchNameValue().                              */
     560             :     /* -------------------------------------------------------------------- */
     561           4 :     poDS->papszAuxLines = CSLLoad2(osAuxFilename, 1024, 1024, nullptr);
     562           4 :     poDS->pszAuxFilename = CPLStrdup(osAuxFilename);
     563             : 
     564             :     /* -------------------------------------------------------------------- */
     565             :     /*      Find the RawDefinition line to establish overall parameters.    */
     566             :     /* -------------------------------------------------------------------- */
     567           4 :     pszLine = CSLFetchNameValue(poDS->papszAuxLines, "RawDefinition");
     568             : 
     569             :     // It seems PCI now writes out .aux files without RawDefinition in
     570             :     // some cases.  See bug 947.
     571           4 :     if (pszLine == nullptr)
     572             :     {
     573           0 :         return nullptr;
     574             :     }
     575             : 
     576           8 :     const CPLStringList aosTokens(CSLTokenizeString(pszLine));
     577             : 
     578           4 :     if (aosTokens.size() < 3)
     579             :     {
     580           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     581             :                  "RawDefinition missing or corrupt in %s.",
     582             :                  poOpenInfo->pszFilename);
     583           0 :         return nullptr;
     584             :     }
     585             : 
     586           4 :     poDS->nRasterXSize = atoi(aosTokens[0]);
     587           4 :     poDS->nRasterYSize = atoi(aosTokens[1]);
     588           4 :     int l_nBands = atoi(aosTokens[2]);
     589           4 :     poDS->eAccess = poOpenInfo->eAccess;
     590             : 
     591           8 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
     592           4 :         !GDALCheckBandCount(l_nBands, FALSE))
     593             :     {
     594           0 :         return nullptr;
     595             :     }
     596             : 
     597             :     /* -------------------------------------------------------------------- */
     598             :     /*      Open the file.                                                  */
     599             :     /* -------------------------------------------------------------------- */
     600           4 :     if (poOpenInfo->eAccess == GA_Update)
     601             :     {
     602           0 :         poDS->fpImage = VSIFOpenL(osTarget, "rb+");
     603             : 
     604           0 :         if (poDS->fpImage == nullptr)
     605             :         {
     606           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     607             :                      "File %s is missing or read-only, check permissions.",
     608             :                      osTarget.c_str());
     609           0 :             return nullptr;
     610             :         }
     611             :     }
     612             :     else
     613             :     {
     614           4 :         poDS->fpImage = VSIFOpenL(osTarget, "rb");
     615             : 
     616           4 :         if (poDS->fpImage == nullptr)
     617             :         {
     618           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     619             :                      "File %s is missing or unreadable.", osTarget.c_str());
     620           0 :             return nullptr;
     621             :         }
     622             :     }
     623             : 
     624             :     /* -------------------------------------------------------------------- */
     625             :     /*      Collect raw definitions of each channel and create              */
     626             :     /*      corresponding bands.                                            */
     627             :     /* -------------------------------------------------------------------- */
     628          12 :     for (int i = 0; i < l_nBands; i++)
     629             :     {
     630           8 :         char szDefnName[32] = {'\0'};
     631           8 :         snprintf(szDefnName, sizeof(szDefnName), "ChanDefinition-%d", i + 1);
     632             : 
     633           8 :         pszLine = CSLFetchNameValue(poDS->papszAuxLines, szDefnName);
     634           8 :         if (pszLine == nullptr)
     635             :         {
     636           0 :             continue;
     637             :         }
     638             : 
     639           8 :         const CPLStringList aosTokensBand(CSLTokenizeString(pszLine));
     640           8 :         if (aosTokensBand.size() < 4)
     641             :         {
     642             :             // Skip the band with broken description
     643           0 :             continue;
     644             :         }
     645             : 
     646           8 :         GDALDataType eType = GDT_Unknown;
     647           8 :         if (EQUAL(aosTokensBand[0], "16U"))
     648           8 :             eType = GDT_UInt16;
     649           0 :         else if (EQUAL(aosTokensBand[0], "16S"))
     650           0 :             eType = GDT_Int16;
     651           0 :         else if (EQUAL(aosTokensBand[0], "32R"))
     652           0 :             eType = GDT_Float32;
     653             :         else
     654           0 :             eType = GDT_Byte;
     655             : 
     656           8 :         bool bNative = true;
     657           8 :         if (CSLCount(aosTokensBand) > 4)
     658             :         {
     659             : #ifdef CPL_LSB
     660           8 :             bNative = EQUAL(aosTokensBand[4], "Swapped");
     661             : #else
     662             :             bNative = EQUAL(aosTokensBand[4], "Unswapped");
     663             : #endif
     664             :         }
     665             : 
     666           8 :         const vsi_l_offset nBandOffset = CPLScanUIntBig(
     667           8 :             aosTokensBand[1], static_cast<int>(strlen(aosTokensBand[1])));
     668           8 :         const int nPixelOffset = atoi(aosTokensBand[2]);
     669           8 :         const int nLineOffset = atoi(aosTokensBand[3]);
     670             : 
     671           8 :         if (nPixelOffset <= 0 || nLineOffset <= 0)
     672             :         {
     673             :             // Skip the band with broken offsets.
     674           0 :             continue;
     675             :         }
     676             : 
     677             :         auto poBand = std::make_unique<PAuxRasterBand>(
     678           8 :             poDS.get(), poDS->nBands + 1, poDS->fpImage, nBandOffset,
     679           8 :             nPixelOffset, nLineOffset, eType, bNative);
     680           8 :         if (!poBand->IsValid())
     681           0 :             return nullptr;
     682           8 :         poDS->SetBand(poDS->nBands + 1, std::move(poBand));
     683             :     }
     684             : 
     685             :     /* -------------------------------------------------------------------- */
     686             :     /*      Get the projection.                                             */
     687             :     /* -------------------------------------------------------------------- */
     688             :     const char *pszMapUnits =
     689           4 :         CSLFetchNameValue(poDS->papszAuxLines, "MapUnits");
     690             :     const char *pszProjParams =
     691           4 :         CSLFetchNameValue(poDS->papszAuxLines, "ProjParams");
     692             : 
     693           4 :     if (pszMapUnits != nullptr)
     694             :     {
     695           4 :         poDS->m_oSRS = PCI2SRS(pszMapUnits, pszProjParams);
     696             :     }
     697             : 
     698             :     /* -------------------------------------------------------------------- */
     699             :     /*      Initialize any PAM information.                                 */
     700             :     /* -------------------------------------------------------------------- */
     701           4 :     poDS->SetDescription(osTarget);
     702           4 :     poDS->TryLoadXML();
     703             : 
     704             :     /* -------------------------------------------------------------------- */
     705             :     /*      Check for overviews.                                            */
     706             :     /* -------------------------------------------------------------------- */
     707           4 :     poDS->oOvManager.Initialize(poDS.get(), osTarget);
     708             : 
     709           4 :     poDS->ScanForGCPs();
     710             : 
     711           4 :     return poDS.release();
     712             : }
     713             : 
     714             : /************************************************************************/
     715             : /*                         GDALRegister_PAux()                          */
     716             : /************************************************************************/
     717             : 
     718        1667 : void GDALRegister_PAux()
     719             : 
     720             : {
     721        1667 :     if (GDALGetDriverByName("PAux") != nullptr)
     722         282 :         return;
     723             : 
     724        1385 :     GDALDriver *poDriver = new GDALDriver();
     725             : 
     726        1385 :     poDriver->SetDescription("PAux");
     727        1385 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     728        1385 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "PCI .aux Labelled");
     729        1385 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/paux.html");
     730        1385 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     731             : 
     732        1385 :     poDriver->pfnOpen = PAuxDataset::Open;
     733             : 
     734        1385 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     735             : }

Generated by: LCOV version 1.14