LCOV - code coverage report
Current view: top level - frmts/raw - pauxdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 153 259 59.1 %
Date: 2025-08-01 10:10:57 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 = cpl::down_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 = cpl::down_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 = static_cast<GDAL_GCP *>(CPLCalloc(sizeof(GDAL_GCP), MAX_GCP));
     344             : 
     345             :     /* -------------------------------------------------------------------- */
     346             :     /*      Get the GCP coordinate system.                                  */
     347             :     /* -------------------------------------------------------------------- */
     348             :     const char *pszMapUnits =
     349           4 :         CSLFetchNameValue(papszAuxLines, "GCP_1_MapUnits");
     350             :     const char *pszProjParams =
     351           4 :         CSLFetchNameValue(papszAuxLines, "GCP_1_ProjParms");
     352             : 
     353           4 :     if (pszMapUnits != nullptr)
     354           0 :         m_oGCPSRS = PCI2SRS(pszMapUnits, pszProjParams);
     355             : 
     356             :     /* -------------------------------------------------------------------- */
     357             :     /*      Collect standalone GCPs.  They look like:                       */
     358             :     /*                                                                      */
     359             :     /*      GCP_1_n = row, col, x, y [,z [,"id"[, "desc"]]]                 */
     360             :     /* -------------------------------------------------------------------- */
     361           4 :     for (int i = 0; nGCPCount < MAX_GCP; i++)
     362             :     {
     363           4 :         char szName[50] = {'\0'};
     364           4 :         snprintf(szName, sizeof(szName), "GCP_1_%d", i + 1);
     365           4 :         if (CSLFetchNameValue(papszAuxLines, szName) == nullptr)
     366           4 :             break;
     367             : 
     368           0 :         char **papszTokens = CSLTokenizeStringComplex(
     369           0 :             CSLFetchNameValue(papszAuxLines, szName), " ", TRUE, FALSE);
     370             : 
     371           0 :         if (CSLCount(papszTokens) >= 4)
     372             :         {
     373           0 :             GDALInitGCPs(1, pasGCPList + nGCPCount);
     374             : 
     375           0 :             pasGCPList[nGCPCount].dfGCPX = CPLAtof(papszTokens[2]);
     376           0 :             pasGCPList[nGCPCount].dfGCPY = CPLAtof(papszTokens[3]);
     377           0 :             pasGCPList[nGCPCount].dfGCPPixel = CPLAtof(papszTokens[0]);
     378           0 :             pasGCPList[nGCPCount].dfGCPLine = CPLAtof(papszTokens[1]);
     379             : 
     380           0 :             if (CSLCount(papszTokens) > 4)
     381           0 :                 pasGCPList[nGCPCount].dfGCPZ = CPLAtof(papszTokens[4]);
     382             : 
     383           0 :             CPLFree(pasGCPList[nGCPCount].pszId);
     384           0 :             if (CSLCount(papszTokens) > 5)
     385             :             {
     386           0 :                 pasGCPList[nGCPCount].pszId = CPLStrdup(papszTokens[5]);
     387             :             }
     388             :             else
     389             :             {
     390           0 :                 snprintf(szName, sizeof(szName), "GCP_%d", i + 1);
     391           0 :                 pasGCPList[nGCPCount].pszId = CPLStrdup(szName);
     392             :             }
     393             : 
     394           0 :             if (CSLCount(papszTokens) > 6)
     395             :             {
     396           0 :                 CPLFree(pasGCPList[nGCPCount].pszInfo);
     397           0 :                 pasGCPList[nGCPCount].pszInfo = CPLStrdup(papszTokens[6]);
     398             :             }
     399             : 
     400           0 :             nGCPCount++;
     401             :         }
     402             : 
     403           0 :         CSLDestroy(papszTokens);
     404             :     }
     405           4 : }
     406             : 
     407             : /************************************************************************/
     408             : /*                            GetGCPCount()                             */
     409             : /************************************************************************/
     410             : 
     411           0 : int PAuxDataset::GetGCPCount()
     412             : 
     413             : {
     414           0 :     return nGCPCount;
     415             : }
     416             : 
     417             : /************************************************************************/
     418             : /*                               GetGCP()                               */
     419             : /************************************************************************/
     420             : 
     421           0 : const GDAL_GCP *PAuxDataset::GetGCPs()
     422             : 
     423             : {
     424           0 :     return pasGCPList;
     425             : }
     426             : 
     427             : /************************************************************************/
     428             : /*                          GetGeoTransform()                           */
     429             : /************************************************************************/
     430             : 
     431           0 : CPLErr PAuxDataset::GetGeoTransform(GDALGeoTransform &gt) const
     432             : 
     433             : {
     434           0 :     if (CSLFetchNameValue(papszAuxLines, "UpLeftX") == nullptr ||
     435           0 :         CSLFetchNameValue(papszAuxLines, "UpLeftY") == nullptr ||
     436           0 :         CSLFetchNameValue(papszAuxLines, "LoRightX") == nullptr ||
     437           0 :         CSLFetchNameValue(papszAuxLines, "LoRightY") == nullptr)
     438             :     {
     439           0 :         gt = GDALGeoTransform();
     440           0 :         return CE_Failure;
     441             :     }
     442             : 
     443             :     const double dfUpLeftX =
     444           0 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "UpLeftX"));
     445             :     const double dfUpLeftY =
     446           0 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "UpLeftY"));
     447             :     const double dfLoRightX =
     448           0 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "LoRightX"));
     449             :     const double dfLoRightY =
     450           0 :         CPLAtof(CSLFetchNameValue(papszAuxLines, "LoRightY"));
     451             : 
     452           0 :     gt[0] = dfUpLeftX;
     453           0 :     gt[1] = (dfLoRightX - dfUpLeftX) / GetRasterXSize();
     454           0 :     gt[2] = 0.0;
     455           0 :     gt[3] = dfUpLeftY;
     456           0 :     gt[4] = 0.0;
     457           0 :     gt[5] = (dfLoRightY - dfUpLeftY) / GetRasterYSize();
     458             : 
     459           0 :     return CE_None;
     460             : }
     461             : 
     462             : /************************************************************************/
     463             : /*                                Open()                                */
     464             : /************************************************************************/
     465             : 
     466       33834 : GDALDataset *PAuxDataset::Open(GDALOpenInfo *poOpenInfo)
     467             : 
     468             : {
     469       33834 :     if (poOpenInfo->nHeaderBytes < 1)
     470       30327 :         return nullptr;
     471             : 
     472             :     /* -------------------------------------------------------------------- */
     473             :     /*      If this is an .aux file, fetch out and form the name of the     */
     474             :     /*      file it references.                                             */
     475             :     /* -------------------------------------------------------------------- */
     476             : 
     477        7014 :     CPLString osTarget = poOpenInfo->pszFilename;
     478             : 
     479        3509 :     if (poOpenInfo->IsExtensionEqualToCI("aux") &&
     480           2 :         STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
     481             :                        "AuxilaryTarget: "))
     482             :     {
     483           2 :         const char *pszSrc =
     484           2 :             reinterpret_cast<const char *>(poOpenInfo->pabyHeader + 16);
     485             : 
     486           2 :         char szAuxTarget[1024] = {'\0'};
     487           2 :         for (int i = 0; i < static_cast<int>(sizeof(szAuxTarget)) - 1 &&
     488          24 :                         pszSrc[i] != 10 && pszSrc[i] != 13 && pszSrc[i] != '\0';
     489             :              i++)
     490             :         {
     491          22 :             szAuxTarget[i] = pszSrc[i];
     492             :         }
     493           2 :         szAuxTarget[sizeof(szAuxTarget) - 1] = '\0';
     494             : 
     495           2 :         const std::string osPath(CPLGetPathSafe(poOpenInfo->pszFilename));
     496           2 :         osTarget = CPLFormFilenameSafe(osPath.c_str(), szAuxTarget, nullptr);
     497             :     }
     498             : 
     499             :     /* -------------------------------------------------------------------- */
     500             :     /*      Now we need to tear apart the filename to form a .aux           */
     501             :     /*      filename.                                                       */
     502             :     /* -------------------------------------------------------------------- */
     503        7014 :     CPLString osAuxFilename = CPLResetExtensionSafe(osTarget, "aux");
     504             : 
     505             :     /* -------------------------------------------------------------------- */
     506             :     /*      Do we have a .aux file?                                         */
     507             :     /* -------------------------------------------------------------------- */
     508        3507 :     char **papszSiblingFiles = poOpenInfo->GetSiblingFiles();
     509        6968 :     if (papszSiblingFiles != nullptr &&
     510        3461 :         CSLFindString(papszSiblingFiles, CPLGetFilename(osAuxFilename)) == -1)
     511             :     {
     512        3457 :         return nullptr;
     513             :     }
     514             : 
     515          50 :     VSILFILE *fp = VSIFOpenL(osAuxFilename, "r");
     516          50 :     if (fp == nullptr)
     517             :     {
     518          46 :         osAuxFilename = CPLResetExtensionSafe(osTarget, "AUX");
     519          46 :         fp = VSIFOpenL(osAuxFilename, "r");
     520             :     }
     521             : 
     522          50 :     if (fp == nullptr)
     523          46 :         return nullptr;
     524             : 
     525             :     /* -------------------------------------------------------------------- */
     526             :     /*      Is this file a PCI .aux file?  Check the first line for the     */
     527             :     /*      telltale AuxilaryTarget keyword.                                */
     528             :     /*                                                                      */
     529             :     /*      At this point we should be verifying that it refers to our      */
     530             :     /*      binary file, but that is a pretty involved test.                */
     531             :     /* -------------------------------------------------------------------- */
     532           4 :     CPLPushErrorHandler(CPLQuietErrorHandler);
     533           4 :     const char *pszLine = CPLReadLine2L(fp, 1024, nullptr);
     534           4 :     CPLPopErrorHandler();
     535             : 
     536           4 :     CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     537             : 
     538           4 :     if (pszLine == nullptr || (!STARTS_WITH_CI(pszLine, "AuxilaryTarget") &&
     539           0 :                                !STARTS_WITH_CI(pszLine, "AuxiliaryTarget")))
     540             :     {
     541           0 :         CPLErrorReset();
     542           0 :         return nullptr;
     543             :     }
     544             : 
     545             :     /* -------------------------------------------------------------------- */
     546             :     /*      Create a corresponding GDALDataset.                             */
     547             :     /* -------------------------------------------------------------------- */
     548           8 :     auto poDS = std::make_unique<PAuxDataset>();
     549             : 
     550             :     /* -------------------------------------------------------------------- */
     551             :     /*      Load the .aux file into a string list suitable to be            */
     552             :     /*      searched with CSLFetchNameValue().                              */
     553             :     /* -------------------------------------------------------------------- */
     554           4 :     poDS->papszAuxLines = CSLLoad2(osAuxFilename, 1024, 1024, nullptr);
     555           4 :     poDS->pszAuxFilename = CPLStrdup(osAuxFilename);
     556             : 
     557             :     /* -------------------------------------------------------------------- */
     558             :     /*      Find the RawDefinition line to establish overall parameters.    */
     559             :     /* -------------------------------------------------------------------- */
     560           4 :     pszLine = CSLFetchNameValue(poDS->papszAuxLines, "RawDefinition");
     561             : 
     562             :     // It seems PCI now writes out .aux files without RawDefinition in
     563             :     // some cases.  See bug 947.
     564           4 :     if (pszLine == nullptr)
     565             :     {
     566           0 :         return nullptr;
     567             :     }
     568             : 
     569           8 :     const CPLStringList aosTokens(CSLTokenizeString(pszLine));
     570             : 
     571           4 :     if (aosTokens.size() < 3)
     572             :     {
     573           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     574             :                  "RawDefinition missing or corrupt in %s.",
     575             :                  poOpenInfo->pszFilename);
     576           0 :         return nullptr;
     577             :     }
     578             : 
     579           4 :     poDS->nRasterXSize = atoi(aosTokens[0]);
     580           4 :     poDS->nRasterYSize = atoi(aosTokens[1]);
     581           4 :     int l_nBands = atoi(aosTokens[2]);
     582           4 :     poDS->eAccess = poOpenInfo->eAccess;
     583             : 
     584           8 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
     585           4 :         !GDALCheckBandCount(l_nBands, FALSE))
     586             :     {
     587           0 :         return nullptr;
     588             :     }
     589             : 
     590             :     /* -------------------------------------------------------------------- */
     591             :     /*      Open the file.                                                  */
     592             :     /* -------------------------------------------------------------------- */
     593           4 :     if (poOpenInfo->eAccess == GA_Update)
     594             :     {
     595           0 :         poDS->fpImage = VSIFOpenL(osTarget, "rb+");
     596             : 
     597           0 :         if (poDS->fpImage == nullptr)
     598             :         {
     599           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     600             :                      "File %s is missing or read-only, check permissions.",
     601             :                      osTarget.c_str());
     602           0 :             return nullptr;
     603             :         }
     604             :     }
     605             :     else
     606             :     {
     607           4 :         poDS->fpImage = VSIFOpenL(osTarget, "rb");
     608             : 
     609           4 :         if (poDS->fpImage == nullptr)
     610             :         {
     611           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     612             :                      "File %s is missing or unreadable.", osTarget.c_str());
     613           0 :             return nullptr;
     614             :         }
     615             :     }
     616             : 
     617             :     /* -------------------------------------------------------------------- */
     618             :     /*      Collect raw definitions of each channel and create              */
     619             :     /*      corresponding bands.                                            */
     620             :     /* -------------------------------------------------------------------- */
     621          12 :     for (int i = 0; i < l_nBands; i++)
     622             :     {
     623           8 :         char szDefnName[32] = {'\0'};
     624           8 :         snprintf(szDefnName, sizeof(szDefnName), "ChanDefinition-%d", i + 1);
     625             : 
     626           8 :         pszLine = CSLFetchNameValue(poDS->papszAuxLines, szDefnName);
     627           8 :         if (pszLine == nullptr)
     628             :         {
     629           0 :             continue;
     630             :         }
     631             : 
     632           8 :         const CPLStringList aosTokensBand(CSLTokenizeString(pszLine));
     633           8 :         if (aosTokensBand.size() < 4)
     634             :         {
     635             :             // Skip the band with broken description
     636           0 :             continue;
     637             :         }
     638             : 
     639           8 :         GDALDataType eType = GDT_Unknown;
     640           8 :         if (EQUAL(aosTokensBand[0], "16U"))
     641           8 :             eType = GDT_UInt16;
     642           0 :         else if (EQUAL(aosTokensBand[0], "16S"))
     643           0 :             eType = GDT_Int16;
     644           0 :         else if (EQUAL(aosTokensBand[0], "32R"))
     645           0 :             eType = GDT_Float32;
     646             :         else
     647           0 :             eType = GDT_Byte;
     648             : 
     649           8 :         bool bNative = true;
     650           8 :         if (CSLCount(aosTokensBand) > 4)
     651             :         {
     652             : #ifdef CPL_LSB
     653           8 :             bNative = EQUAL(aosTokensBand[4], "Swapped");
     654             : #else
     655             :             bNative = EQUAL(aosTokensBand[4], "Unswapped");
     656             : #endif
     657             :         }
     658             : 
     659           8 :         const vsi_l_offset nBandOffset = CPLScanUIntBig(
     660           8 :             aosTokensBand[1], static_cast<int>(strlen(aosTokensBand[1])));
     661           8 :         const int nPixelOffset = atoi(aosTokensBand[2]);
     662           8 :         const int nLineOffset = atoi(aosTokensBand[3]);
     663             : 
     664           8 :         if (nPixelOffset <= 0 || nLineOffset <= 0)
     665             :         {
     666             :             // Skip the band with broken offsets.
     667           0 :             continue;
     668             :         }
     669             : 
     670             :         auto poBand = std::make_unique<PAuxRasterBand>(
     671           8 :             poDS.get(), poDS->nBands + 1, poDS->fpImage, nBandOffset,
     672           8 :             nPixelOffset, nLineOffset, eType, bNative);
     673           8 :         if (!poBand->IsValid())
     674           0 :             return nullptr;
     675           8 :         poDS->SetBand(poDS->nBands + 1, std::move(poBand));
     676             :     }
     677             : 
     678             :     /* -------------------------------------------------------------------- */
     679             :     /*      Get the projection.                                             */
     680             :     /* -------------------------------------------------------------------- */
     681             :     const char *pszMapUnits =
     682           4 :         CSLFetchNameValue(poDS->papszAuxLines, "MapUnits");
     683             :     const char *pszProjParams =
     684           4 :         CSLFetchNameValue(poDS->papszAuxLines, "ProjParams");
     685             : 
     686           4 :     if (pszMapUnits != nullptr)
     687             :     {
     688           4 :         poDS->m_oSRS = PCI2SRS(pszMapUnits, pszProjParams);
     689             :     }
     690             : 
     691             :     /* -------------------------------------------------------------------- */
     692             :     /*      Initialize any PAM information.                                 */
     693             :     /* -------------------------------------------------------------------- */
     694           4 :     poDS->SetDescription(osTarget);
     695           4 :     poDS->TryLoadXML();
     696             : 
     697             :     /* -------------------------------------------------------------------- */
     698             :     /*      Check for overviews.                                            */
     699             :     /* -------------------------------------------------------------------- */
     700           4 :     poDS->oOvManager.Initialize(poDS.get(), osTarget);
     701             : 
     702           4 :     poDS->ScanForGCPs();
     703             : 
     704           4 :     return poDS.release();
     705             : }
     706             : 
     707             : /************************************************************************/
     708             : /*                         GDALRegister_PAux()                          */
     709             : /************************************************************************/
     710             : 
     711        1961 : void GDALRegister_PAux()
     712             : 
     713             : {
     714        1961 :     if (GDALGetDriverByName("PAux") != nullptr)
     715         283 :         return;
     716             : 
     717        1678 :     GDALDriver *poDriver = new GDALDriver();
     718             : 
     719        1678 :     poDriver->SetDescription("PAux");
     720        1678 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     721        1678 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "PCI .aux Labelled");
     722        1678 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/paux.html");
     723        1678 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     724             : 
     725        1678 :     poDriver->pfnOpen = PAuxDataset::Open;
     726             : 
     727        1678 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     728             : }

Generated by: LCOV version 1.14