LCOV - code coverage report
Current view: top level - frmts/raw - roipacdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 269 349 77.1 %
Date: 2025-10-21 22:35:35 Functions: 15 15 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  ROI_PAC Raster Reader
       4             :  * Purpose:  Implementation of the ROI_PAC raster reader
       5             :  * Author:   Matthieu Volat (ISTerre), matthieu.volat@ujf-grenoble.fr
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2014, Matthieu Volat <matthieu.volat@ujf-grenoble.fr>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdal_frmts.h"
      14             : #include "ogr_spatialref.h"
      15             : #include "gdal_priv.h"
      16             : #include "rawdataset.h"
      17             : 
      18             : #include <algorithm>
      19             : 
      20             : /************************************************************************/
      21             : /* ==================================================================== */
      22             : /*                             ROIPACDataset                            */
      23             : /* ==================================================================== */
      24             : /************************************************************************/
      25             : 
      26             : class ROIPACDataset final : public RawDataset
      27             : {
      28             :     VSILFILE *fpImage;
      29             :     VSILFILE *fpRsc;
      30             : 
      31             :     char *pszRscFilename;
      32             : 
      33             :     GDALGeoTransform m_gt{};
      34             :     bool bValidGeoTransform;
      35             : 
      36             :     OGRSpatialReference m_oSRS{};
      37             : 
      38             :     CPL_DISALLOW_COPY_ASSIGN(ROIPACDataset)
      39             : 
      40             :     CPLErr Close() override;
      41             : 
      42             :   public:
      43             :     ROIPACDataset();
      44             :     ~ROIPACDataset() override;
      45             : 
      46             :     static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
      47             :     static int Identify(GDALOpenInfo *poOpenInfo);
      48             :     static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
      49             :                                int nBandsIn, GDALDataType eType,
      50             :                                char **papszOptions);
      51             : 
      52             :     CPLErr FlushCache(bool bAtClosing) override;
      53             :     CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
      54             :     CPLErr SetGeoTransform(const GDALGeoTransform &gt) override;
      55             : 
      56           3 :     const OGRSpatialReference *GetSpatialRef() const override
      57             :     {
      58           3 :         return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
      59             :     }
      60             : 
      61             :     CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
      62             : 
      63             :     char **GetFileList() override;
      64             : };
      65             : 
      66             : /************************************************************************/
      67             : /*                           getRscFilename()                           */
      68             : /************************************************************************/
      69             : 
      70         176 : static CPLString getRscFilename(GDALOpenInfo *poOpenInfo)
      71             : {
      72         176 :     char **papszSiblingFiles = poOpenInfo->GetSiblingFiles();
      73         176 :     if (papszSiblingFiles == nullptr)
      74             :     {
      75             :         CPLString osRscFilename =
      76         190 :             CPLFormFilenameSafe(nullptr, poOpenInfo->pszFilename, "rsc");
      77             :         VSIStatBufL psRscStatBuf;
      78          95 :         if (VSIStatL(osRscFilename, &psRscStatBuf) != 0)
      79             :         {
      80          95 :             return "";
      81             :         }
      82           0 :         return osRscFilename;
      83             :     }
      84             : 
      85             :     /* ------------------------------------------------------------ */
      86             :     /*      We need to tear apart the filename to form a .rsc       */
      87             :     /*      filename.                                               */
      88             :     /* ------------------------------------------------------------ */
      89         162 :     const CPLString osPath = CPLGetPathSafe(poOpenInfo->pszFilename);
      90         162 :     const CPLString osName = CPLGetFilename(poOpenInfo->pszFilename);
      91             : 
      92          81 :     int iFile = CSLFindString(
      93         162 :         papszSiblingFiles, CPLFormFilenameSafe(nullptr, osName, "rsc").c_str());
      94          81 :     if (iFile >= 0)
      95             :     {
      96          90 :         return CPLFormFilenameSafe(osPath, papszSiblingFiles[iFile], nullptr);
      97             :     }
      98             : 
      99          36 :     return "";
     100             : }
     101             : 
     102             : /************************************************************************/
     103             : /*                            ROIPACDataset()                           */
     104             : /************************************************************************/
     105             : 
     106          15 : ROIPACDataset::ROIPACDataset()
     107             :     : fpImage(nullptr), fpRsc(nullptr), pszRscFilename(nullptr),
     108          15 :       bValidGeoTransform(false)
     109             : {
     110          15 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     111          15 : }
     112             : 
     113             : /************************************************************************/
     114             : /*                            ~ROIPACDataset()                          */
     115             : /************************************************************************/
     116             : 
     117          30 : ROIPACDataset::~ROIPACDataset()
     118             : {
     119          15 :     ROIPACDataset::Close();
     120          30 : }
     121             : 
     122             : /************************************************************************/
     123             : /*                              Close()                                 */
     124             : /************************************************************************/
     125             : 
     126          30 : CPLErr ROIPACDataset::Close()
     127             : {
     128          30 :     CPLErr eErr = CE_None;
     129          30 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
     130             :     {
     131          15 :         if (ROIPACDataset::FlushCache(true) != CE_None)
     132           0 :             eErr = CE_Failure;
     133             : 
     134          15 :         if (fpRsc != nullptr && VSIFCloseL(fpRsc) != 0)
     135             :         {
     136           0 :             eErr = CE_Failure;
     137           0 :             CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     138             :         }
     139          15 :         if (fpImage != nullptr && VSIFCloseL(fpImage) != 0)
     140             :         {
     141           0 :             eErr = CE_Failure;
     142           0 :             CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     143             :         }
     144          15 :         CPLFree(pszRscFilename);
     145             : 
     146          15 :         if (GDALPamDataset::Close() != CE_None)
     147           0 :             eErr = CE_Failure;
     148             :     }
     149          30 :     return eErr;
     150             : }
     151             : 
     152             : /************************************************************************/
     153             : /*                                Open()                                */
     154             : /************************************************************************/
     155             : 
     156          15 : GDALDataset *ROIPACDataset::Open(GDALOpenInfo *poOpenInfo)
     157             : {
     158             :     /* -------------------------------------------------------------------- */
     159             :     /*      Confirm that the header is compatible with a ROIPAC dataset.    */
     160             :     /* -------------------------------------------------------------------- */
     161          15 :     if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
     162             :     {
     163           0 :         return nullptr;
     164             :     }
     165             : 
     166             :     /* -------------------------------------------------------------------- */
     167             :     /*      Open the .rsc file                                              */
     168             :     /* -------------------------------------------------------------------- */
     169          30 :     CPLString osRscFilename = getRscFilename(poOpenInfo);
     170          15 :     if (osRscFilename.empty())
     171             :     {
     172           0 :         return nullptr;
     173             :     }
     174          15 :     VSILFILE *fpRsc = nullptr;
     175          15 :     if (poOpenInfo->eAccess == GA_Update)
     176             :     {
     177           3 :         fpRsc = VSIFOpenL(osRscFilename, "r+");
     178             :     }
     179             :     else
     180             :     {
     181          12 :         fpRsc = VSIFOpenL(osRscFilename, "r");
     182             :     }
     183          15 :     if (fpRsc == nullptr)
     184             :     {
     185           0 :         return nullptr;
     186             :     }
     187             : 
     188             :     /* -------------------------------------------------------------------- */
     189             :     /*      Load the .rsc information.                                      */
     190             :     /* -------------------------------------------------------------------- */
     191          30 :     CPLStringList aosRSC;
     192             :     while (true)
     193             :     {
     194         189 :         const char *pszLine = CPLReadLineL(fpRsc);
     195         189 :         if (pszLine == nullptr)
     196             :         {
     197          15 :             break;
     198             :         }
     199             : 
     200             :         char **papszTokens =
     201         174 :             CSLTokenizeString2(pszLine, " \t",
     202             :                                CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES |
     203             :                                    CSLT_PRESERVEQUOTES | CSLT_PRESERVEESCAPES);
     204         174 :         if (papszTokens == nullptr || papszTokens[0] == nullptr ||
     205         174 :             papszTokens[1] == nullptr)
     206             :         {
     207           0 :             CSLDestroy(papszTokens);
     208           0 :             break;
     209             :         }
     210         174 :         aosRSC.SetNameValue(papszTokens[0], papszTokens[1]);
     211             : 
     212         174 :         CSLDestroy(papszTokens);
     213         174 :     }
     214             : 
     215             :     /* -------------------------------------------------------------------- */
     216             :     /*      Fetch required fields.                                          */
     217             :     /* -------------------------------------------------------------------- */
     218          30 :     if (aosRSC.FetchNameValue("WIDTH") == nullptr ||
     219          15 :         aosRSC.FetchNameValue("FILE_LENGTH") == nullptr)
     220             :     {
     221           0 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpRsc));
     222           0 :         return nullptr;
     223             :     }
     224          15 :     const int nWidth = atoi(aosRSC.FetchNameValue("WIDTH"));
     225          15 :     const int nFileLength = atoi(aosRSC.FetchNameValue("FILE_LENGTH"));
     226             : 
     227          15 :     if (!GDALCheckDatasetDimensions(nWidth, nFileLength))
     228             :     {
     229           0 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpRsc));
     230           0 :         return nullptr;
     231             :     }
     232             : 
     233             :     /* -------------------------------------------------------------------- */
     234             :     /*      Create a corresponding GDALDataset.                             */
     235             :     /* -------------------------------------------------------------------- */
     236          30 :     auto poDS = std::make_unique<ROIPACDataset>();
     237          15 :     poDS->nRasterXSize = nWidth;
     238          15 :     poDS->nRasterYSize = nFileLength;
     239          15 :     poDS->eAccess = poOpenInfo->eAccess;
     240          15 :     poDS->fpRsc = fpRsc;
     241          15 :     poDS->pszRscFilename = CPLStrdup(osRscFilename.c_str());
     242          15 :     std::swap(poDS->fpImage, poOpenInfo->fpL);
     243             : 
     244             :     /* -------------------------------------------------------------------- */
     245             :     /*      Create band information objects.                                */
     246             :     /* -------------------------------------------------------------------- */
     247          15 :     GDALDataType eDataType = GDT_Unknown;
     248          15 :     int nBands = 0;
     249             : 
     250             :     enum Interleave
     251             :     {
     252             :         UNKNOWN,
     253             :         LINE,
     254             :         PIXEL
     255          15 :     } eInterleave = UNKNOWN;
     256             : 
     257          15 :     const char *pszExtension = poOpenInfo->osExtension.c_str();
     258          15 :     if (strcmp(pszExtension, "raw") == 0)
     259             :     {
     260             :         /* ------------------------------------------------------------ */
     261             :         /* TODO: ROI_PAC raw images are what would be GDT_CInt8 typed,  */
     262             :         /* but since that type do not exist, we will have to implement  */
     263             :         /* a specific case in the RasterBand to convert it to           */
     264             :         /* GDT_CInt16 for example                                       */
     265             :         /* ------------------------------------------------------------ */
     266             : #if 0
     267             :         eDataType = GDT_CInt8;
     268             :         nBands = 1;
     269             :         eInterleave = PIXEL;
     270             : #else
     271           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     272             :                  "Reading ROI_PAC raw files is not supported yet.");
     273           0 :         return nullptr;
     274             : #endif
     275             :     }
     276          15 :     else if (strcmp(pszExtension, "int") == 0 ||
     277          15 :              strcmp(pszExtension, "slc") == 0)
     278             :     {
     279           0 :         eDataType = GDT_CFloat32;
     280           0 :         nBands = 1;
     281           0 :         eInterleave = PIXEL;
     282             :     }
     283          15 :     else if (strcmp(pszExtension, "amp") == 0)
     284             :     {
     285           0 :         eDataType = GDT_Float32;
     286           0 :         nBands = 2;
     287           0 :         eInterleave = PIXEL;
     288             :     }
     289          15 :     else if (strcmp(pszExtension, "cor") == 0 ||
     290          15 :              strcmp(pszExtension, "hgt") == 0 ||
     291          15 :              strcmp(pszExtension, "unw") == 0 ||
     292          15 :              strcmp(pszExtension, "msk") == 0 ||
     293          15 :              strcmp(pszExtension, "trans") == 0)
     294             :     {
     295           0 :         eDataType = GDT_Float32;
     296           0 :         nBands = 2;
     297           0 :         eInterleave = LINE;
     298             :     }
     299          15 :     else if (strcmp(pszExtension, "dem") == 0)
     300             :     {
     301          12 :         eDataType = GDT_Int16;
     302          12 :         nBands = 1;
     303          12 :         eInterleave = PIXEL;
     304             :     }
     305           3 :     else if (strcmp(pszExtension, "flg") == 0)
     306             :     {
     307           3 :         eDataType = GDT_Byte;
     308           3 :         nBands = 1;
     309           3 :         eInterleave = PIXEL;
     310             :     }
     311             :     else
     312             :     { /* Eeek */
     313           0 :         return nullptr;
     314             :     }
     315             : 
     316          15 :     int nPixelOffset = 0;
     317          15 :     int nLineOffset = 0;
     318          15 :     vsi_l_offset nBandOffset = 0;
     319          15 :     const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
     320          15 :     bool bIntOverflow = false;
     321          15 :     if (eInterleave == LINE)
     322             :     {
     323           0 :         nPixelOffset = nDTSize;
     324           0 :         if (nWidth > INT_MAX / (nPixelOffset * nBands))
     325           0 :             bIntOverflow = true;
     326             :         else
     327             :         {
     328           0 :             nLineOffset = nPixelOffset * nWidth * nBands;
     329           0 :             nBandOffset = static_cast<vsi_l_offset>(nDTSize) * nWidth;
     330             :         }
     331             :     }
     332             :     else
     333             :     { /* PIXEL */
     334          15 :         nPixelOffset = nDTSize * nBands;
     335          15 :         if (nWidth > INT_MAX / nPixelOffset)
     336           0 :             bIntOverflow = true;
     337             :         else
     338             :         {
     339          15 :             nLineOffset = nPixelOffset * nWidth;
     340          15 :             nBandOffset = nDTSize;
     341             : 
     342          15 :             if (nBands > 1)
     343             :             {
     344             :                 // GDAL 2.0.[0-3] and 2.1.0  had a value of nLineOffset that was
     345             :                 // equal to the theoretical nLineOffset multiplied by nBands.
     346           0 :                 VSIFSeekL(poDS->fpImage, 0, SEEK_END);
     347           0 :                 const GUIntBig nWrongFileSize =
     348           0 :                     static_cast<GUIntBig>(nDTSize) * nWidth *
     349           0 :                     (static_cast<GUIntBig>(nFileLength - 1) * nBands * nBands +
     350             :                      nBands);
     351           0 :                 if (VSIFTellL(poDS->fpImage) == nWrongFileSize)
     352             :                 {
     353           0 :                     CPLError(
     354             :                         CE_Warning, CPLE_AppDefined,
     355             :                         "This file has been incorrectly generated by an older "
     356             :                         "GDAL version whose line offset computation was "
     357             :                         "erroneous.  Taking that into account, "
     358             :                         "but the file should be re-encoded ideally.");
     359           0 :                     nLineOffset = nLineOffset * nBands;
     360             :                 }
     361             :             }
     362             :         }
     363             :     }
     364             : 
     365          15 :     if (bIntOverflow)
     366             :     {
     367           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Int overflow occurred.");
     368           0 :         return nullptr;
     369             :     }
     370             : 
     371          30 :     for (int b = 0; b < nBands; b++)
     372             :     {
     373             :         auto poBand = RawRasterBand::Create(
     374          30 :             poDS.get(), b + 1, poDS->fpImage, nBandOffset * b, nPixelOffset,
     375             :             nLineOffset, eDataType,
     376             :             RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN,
     377          15 :             RawRasterBand::OwnFP::NO);
     378          15 :         if (!poBand)
     379           0 :             return nullptr;
     380          15 :         poDS->SetBand(b + 1, std::move(poBand));
     381             :     }
     382             : 
     383             :     /* -------------------------------------------------------------------- */
     384             :     /*      Interpret georeferencing, if present.                           */
     385             :     /* -------------------------------------------------------------------- */
     386          15 :     if (aosRSC.FetchNameValue("X_FIRST") != nullptr &&
     387          12 :         aosRSC.FetchNameValue("X_STEP") != nullptr &&
     388          39 :         aosRSC.FetchNameValue("Y_FIRST") != nullptr &&
     389          12 :         aosRSC.FetchNameValue("Y_STEP") != nullptr)
     390             :     {
     391          12 :         poDS->m_gt[0] = CPLAtof(aosRSC.FetchNameValue("X_FIRST"));
     392          12 :         poDS->m_gt[1] = CPLAtof(aosRSC.FetchNameValue("X_STEP"));
     393          12 :         poDS->m_gt[2] = 0.0;
     394          12 :         poDS->m_gt[3] = CPLAtof(aosRSC.FetchNameValue("Y_FIRST"));
     395          12 :         poDS->m_gt[4] = 0.0;
     396          12 :         poDS->m_gt[5] = CPLAtof(aosRSC.FetchNameValue("Y_STEP"));
     397          12 :         poDS->bValidGeoTransform = true;
     398             :     }
     399          15 :     if (aosRSC.FetchNameValue("PROJECTION") != nullptr)
     400             :     {
     401             :         /* ------------------------------------------------------------ */
     402             :         /* In ROI_PAC, images are georeferenced either with lat/long or */
     403             :         /* UTM projection. However, using UTM projection is dangerous   */
     404             :         /* because there is no North/South field, or use of latitude    */
     405             :         /* bands!                                                       */
     406             :         /* ------------------------------------------------------------ */
     407          24 :         OGRSpatialReference oSRS;
     408          12 :         if (strcmp(aosRSC.FetchNameValue("PROJECTION"), "LL") == 0)
     409             :         {
     410          10 :             if (aosRSC.FetchNameValue("DATUM") != nullptr)
     411             :             {
     412          10 :                 oSRS.SetWellKnownGeogCS(aosRSC.FetchNameValue("DATUM"));
     413             :             }
     414             :             else
     415             :             {
     416           0 :                 oSRS.SetWellKnownGeogCS("WGS84");
     417             :             }
     418             :         }
     419           2 :         else if (STARTS_WITH(aosRSC.FetchNameValue("PROJECTION"), "UTM"))
     420             :         {
     421           2 :             const char *pszZone = aosRSC.FetchNameValue("PROJECTION") + 3;
     422           2 :             oSRS.SetUTM(atoi(pszZone), TRUE); /* FIXME: north/south? */
     423           2 :             if (aosRSC.FetchNameValue("DATUM") != nullptr)
     424             :             {
     425           2 :                 oSRS.SetWellKnownGeogCS(aosRSC.FetchNameValue("DATUM"));
     426             :             }
     427             :             else
     428             :             {
     429           0 :                 oSRS.SetWellKnownGeogCS("NAD27");
     430             :             }
     431             :         }
     432          12 :         poDS->m_oSRS = std::move(oSRS);
     433          12 :         poDS->m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     434             :     }
     435          15 :     if (aosRSC.FetchNameValue("Z_OFFSET") != nullptr)
     436             :     {
     437             :         const double dfOffset =
     438          12 :             strtod(aosRSC.FetchNameValue("Z_OFFSET"), nullptr);
     439          24 :         for (int b = 1; b <= nBands; b++)
     440             :         {
     441          12 :             GDALRasterBand *poBand = poDS->GetRasterBand(b);
     442          12 :             poBand->SetOffset(dfOffset);
     443             :         }
     444             :     }
     445          15 :     if (aosRSC.FetchNameValue("Z_SCALE") != nullptr)
     446             :     {
     447             :         const double dfScale =
     448          12 :             strtod(aosRSC.FetchNameValue("Z_SCALE"), nullptr);
     449          24 :         for (int b = 1; b <= nBands; b++)
     450             :         {
     451          12 :             GDALRasterBand *poBand = poDS->GetRasterBand(b);
     452          12 :             poBand->SetScale(dfScale);
     453             :         }
     454             :     }
     455             : 
     456             :     /* -------------------------------------------------------------------- */
     457             :     /*      Set all the other header metadata into the ROI_PAC domain       */
     458             :     /* -------------------------------------------------------------------- */
     459         189 :     for (int i = 0; i < aosRSC.size(); ++i)
     460             :     {
     461         348 :         char **papszTokens = CSLTokenizeString2(
     462         174 :             aosRSC[i], "=", CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
     463         348 :         if (CSLCount(papszTokens) < 2 || strcmp(papszTokens[0], "WIDTH") == 0 ||
     464         159 :             strcmp(papszTokens[0], "FILE_LENGTH") == 0 ||
     465         144 :             strcmp(papszTokens[0], "X_FIRST") == 0 ||
     466         132 :             strcmp(papszTokens[0], "X_STEP") == 0 ||
     467         120 :             strcmp(papszTokens[0], "Y_FIRST") == 0 ||
     468         108 :             strcmp(papszTokens[0], "Y_STEP") == 0 ||
     469          96 :             strcmp(papszTokens[0], "PROJECTION") == 0 ||
     470          84 :             strcmp(papszTokens[0], "DATUM") == 0 ||
     471         408 :             strcmp(papszTokens[0], "Z_OFFSET") == 0 ||
     472          60 :             strcmp(papszTokens[0], "Z_SCALE") == 0)
     473             :         {
     474         126 :             CSLDestroy(papszTokens);
     475         126 :             continue;
     476             :         }
     477          48 :         poDS->SetMetadataItem(papszTokens[0], papszTokens[1], "ROI_PAC");
     478          48 :         CSLDestroy(papszTokens);
     479             :     }
     480             :     /* -------------------------------------------------------------------- */
     481             :     /*      Initialize any PAM information.                                 */
     482             :     /* -------------------------------------------------------------------- */
     483          15 :     poDS->SetDescription(poOpenInfo->pszFilename);
     484          15 :     poDS->TryLoadXML();
     485             : 
     486             :     /* -------------------------------------------------------------------- */
     487             :     /*      Check for overviews.                                            */
     488             :     /* -------------------------------------------------------------------- */
     489          15 :     poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
     490             : 
     491          15 :     return poDS.release();
     492             : }
     493             : 
     494             : /************************************************************************/
     495             : /*                             Identify()                               */
     496             : /************************************************************************/
     497             : 
     498       58997 : int ROIPACDataset::Identify(GDALOpenInfo *poOpenInfo)
     499             : {
     500             :     /* -------------------------------------------------------------------- */
     501             :     /*      Check if:                                                       */
     502             :     /*      * 1. The data file extension is known                           */
     503             :     /* -------------------------------------------------------------------- */
     504       58997 :     const char *pszExtension = poOpenInfo->osExtension.c_str();
     505       58997 :     if (strcmp(pszExtension, "raw") == 0)
     506             :     {
     507             :         /* Since gdal do not read natively CInt8, more work is needed
     508             :          * to read raw files */
     509          25 :         return false;
     510             :     }
     511       58972 :     const bool bExtensionIsValid =
     512       58968 :         strcmp(pszExtension, "int") == 0 || strcmp(pszExtension, "slc") == 0 ||
     513       58950 :         strcmp(pszExtension, "amp") == 0 || strcmp(pszExtension, "cor") == 0 ||
     514       58950 :         strcmp(pszExtension, "hgt") == 0 || strcmp(pszExtension, "unw") == 0 ||
     515       58929 :         strcmp(pszExtension, "msk") == 0 ||
     516       58880 :         strcmp(pszExtension, "trans") == 0 ||
     517      117940 :         strcmp(pszExtension, "dem") == 0 || strcmp(pszExtension, "flg") == 0;
     518       58972 :     if (!bExtensionIsValid)
     519             :     {
     520       58811 :         return false;
     521             :     }
     522             : 
     523             :     /* -------------------------------------------------------------------- */
     524             :     /*      * 2. there is a .rsc file                                      */
     525             :     /* -------------------------------------------------------------------- */
     526         322 :     CPLString osRscFilename = getRscFilename(poOpenInfo);
     527         161 :     if (osRscFilename.empty())
     528             :     {
     529         131 :         return false;
     530             :     }
     531             : 
     532          30 :     return true;
     533             : }
     534             : 
     535             : /************************************************************************/
     536             : /*                              Create()                                */
     537             : /************************************************************************/
     538             : 
     539          52 : GDALDataset *ROIPACDataset::Create(const char *pszFilename, int nXSize,
     540             :                                    int nYSize, int nBandsIn, GDALDataType eType,
     541             :                                    char ** /* papszOptions */)
     542             : {
     543             :     /* -------------------------------------------------------------------- */
     544             :     /*      Verify input options.                                           */
     545             :     /* -------------------------------------------------------------------- */
     546         104 :     const std::string osExtension = CPLGetExtensionSafe(pszFilename);
     547          52 :     const char *pszExtension = osExtension.c_str();
     548          52 :     if (strcmp(pszExtension, "int") == 0 || strcmp(pszExtension, "slc") == 0)
     549             :     {
     550           0 :         if (nBandsIn != 1 || eType != GDT_CFloat32)
     551             :         {
     552           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     553             :                      "Attempt to create ROI_PAC %s dataset with an illegal "
     554             :                      "number of bands (%d) and/or data type (%s).",
     555             :                      pszExtension, nBandsIn, GDALGetDataTypeName(eType));
     556           0 :             return nullptr;
     557             :         }
     558             :     }
     559          52 :     else if (strcmp(pszExtension, "amp") == 0)
     560             :     {
     561           0 :         if (nBandsIn != 2 || eType != GDT_Float32)
     562             :         {
     563           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     564             :                      "Attempt to create ROI_PAC %s dataset with an illegal "
     565             :                      "number of bands (%d) and/or data type (%s).",
     566             :                      pszExtension, nBandsIn, GDALGetDataTypeName(eType));
     567           0 :             return nullptr;
     568             :         }
     569             :     }
     570          52 :     else if (strcmp(pszExtension, "cor") == 0 ||
     571          52 :              strcmp(pszExtension, "hgt") == 0 ||
     572          52 :              strcmp(pszExtension, "unw") == 0 ||
     573          52 :              strcmp(pszExtension, "msk") == 0 ||
     574          52 :              strcmp(pszExtension, "trans") == 0)
     575             :     {
     576           0 :         if (nBandsIn != 2 || eType != GDT_Float32)
     577             :         {
     578           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     579             :                      "Attempt to create ROI_PAC %s dataset with an illegal "
     580             :                      "number of bands (%d) and/or data type (%s).",
     581             :                      pszExtension, nBandsIn, GDALGetDataTypeName(eType));
     582           0 :             return nullptr;
     583             :         }
     584             :     }
     585          52 :     else if (strcmp(pszExtension, "dem") == 0)
     586             :     {
     587           2 :         if (nBandsIn != 1 || eType != GDT_Int16)
     588             :         {
     589           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     590             :                      "Attempt to create ROI_PAC %s dataset with an illegal "
     591             :                      "number of bands (%d) and/or data type (%s).",
     592             :                      pszExtension, nBandsIn, GDALGetDataTypeName(eType));
     593           0 :             return nullptr;
     594             :         }
     595             :     }
     596          50 :     else if (strcmp(pszExtension, "flg") == 0)
     597             :     {
     598           1 :         if (nBandsIn != 1 || eType != GDT_Byte)
     599             :         {
     600           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     601             :                      "Attempt to create ROI_PAC %s dataset with an illegal "
     602             :                      "number of bands (%d) and/or data type (%s).",
     603             :                      pszExtension, nBandsIn, GDALGetDataTypeName(eType));
     604           0 :             return nullptr;
     605             :         }
     606             :     }
     607             :     else
     608             :     { /* Eeek */
     609          49 :         CPLError(CE_Failure, CPLE_AppDefined,
     610             :                  "Attempt to create ROI_PAC dataset with an unknown type (%s)",
     611             :                  pszExtension);
     612          49 :         return nullptr;
     613             :     }
     614             : 
     615             :     /* -------------------------------------------------------------------- */
     616             :     /*      Try to create the file.                                         */
     617             :     /* -------------------------------------------------------------------- */
     618           3 :     VSILFILE *fp = VSIFOpenL(pszFilename, "wb");
     619           3 :     if (fp == nullptr)
     620             :     {
     621           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     622             :                  "Attempt to create file `%s' failed.", pszFilename);
     623           0 :         return nullptr;
     624             :     }
     625             : 
     626             :     /* -------------------------------------------------------------------- */
     627             :     /*      Just write out a couple of bytes to establish the binary        */
     628             :     /*      file, and then close it.                                        */
     629             :     /* -------------------------------------------------------------------- */
     630           3 :     CPL_IGNORE_RET_VAL(VSIFWriteL("\0\0", 2, 1, fp));
     631           3 :     CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     632             : 
     633             :     /* -------------------------------------------------------------------- */
     634             :     /*      Open the RSC file.                                              */
     635             :     /* -------------------------------------------------------------------- */
     636             :     const std::string osRSCFilename =
     637           6 :         CPLFormFilenameSafe(nullptr, pszFilename, "rsc");
     638           3 :     fp = VSIFOpenL(osRSCFilename.c_str(), "wt");
     639           3 :     if (fp == nullptr)
     640             :     {
     641           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     642             :                  "Attempt to create file `%s' failed.", osRSCFilename.c_str());
     643           0 :         return nullptr;
     644             :     }
     645             : 
     646             :     /* -------------------------------------------------------------------- */
     647             :     /*      Write out the header.                                           */
     648             :     /* -------------------------------------------------------------------- */
     649           3 :     CPL_IGNORE_RET_VAL(VSIFPrintfL(fp, "%-40s %d\n", "WIDTH", nXSize));
     650           3 :     CPL_IGNORE_RET_VAL(VSIFPrintfL(fp, "%-40s %d\n", "FILE_LENGTH", nYSize));
     651           3 :     CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     652             : 
     653           3 :     return GDALDataset::FromHandle(GDALOpen(pszFilename, GA_Update));
     654             : }
     655             : 
     656             : /************************************************************************/
     657             : /*                             FlushCache()                             */
     658             : /************************************************************************/
     659             : 
     660          15 : CPLErr ROIPACDataset::FlushCache(bool bAtClosing)
     661             : {
     662          15 :     CPLErr eErr = RawDataset::FlushCache(bAtClosing);
     663             : 
     664          15 :     GDALRasterBand *band = (GetRasterCount() > 0) ? GetRasterBand(1) : nullptr;
     665             : 
     666          15 :     if (eAccess == GA_ReadOnly || band == nullptr)
     667          12 :         return eErr;
     668             : 
     669             :     // If opening an existing file in Update mode (i.e. "r+") we need to make
     670             :     // sure any existing content is cleared, otherwise the file may contain
     671             :     // trailing content from the previous write.
     672           3 :     bool bOK = VSIFTruncateL(fpRsc, 0) == 0;
     673             : 
     674           3 :     bOK &= VSIFSeekL(fpRsc, 0, SEEK_SET) == 0;
     675             :     /* -------------------------------------------------------------------- */
     676             :     /*      Rewrite out the header.                                         */
     677             :     /* -------------------------------------------------------------------- */
     678             :     /* -------------------------------------------------------------------- */
     679             :     /*      Raster dimensions.                                              */
     680             :     /* -------------------------------------------------------------------- */
     681           3 :     bOK &= VSIFPrintfL(fpRsc, "%-40s %d\n", "WIDTH", nRasterXSize) > 0;
     682           3 :     bOK &= VSIFPrintfL(fpRsc, "%-40s %d\n", "FILE_LENGTH", nRasterYSize) > 0;
     683             : 
     684             :     /* -------------------------------------------------------------------- */
     685             :     /*      Georeferencing.                                                 */
     686             :     /* -------------------------------------------------------------------- */
     687           3 :     if (!m_oSRS.IsEmpty())
     688             :     {
     689           3 :         int bNorth = FALSE;
     690           3 :         int iUTMZone = m_oSRS.GetUTMZone(&bNorth);
     691           3 :         if (iUTMZone != 0)
     692             :         {
     693           1 :             bOK &= VSIFPrintfL(fpRsc, "%-40s %s%d\n", "PROJECTION", "UTM",
     694           1 :                                iUTMZone) > 0;
     695             :         }
     696           2 :         else if (m_oSRS.IsGeographic())
     697             :         {
     698           2 :             bOK &= VSIFPrintfL(fpRsc, "%-40s %s\n", "PROJECTION", "LL") > 0;
     699             :         }
     700             :         else
     701             :         {
     702           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     703             :                      "ROI_PAC format only support Latitude/Longitude and "
     704             :                      "UTM projections, discarding projection.");
     705             :         }
     706             : 
     707           3 :         if (m_oSRS.GetAttrValue("DATUM") != nullptr)
     708             :         {
     709           3 :             if (strcmp(m_oSRS.GetAttrValue("DATUM"), "WGS_1984") == 0)
     710             :             {
     711           2 :                 bOK &= VSIFPrintfL(fpRsc, "%-40s %s\n", "DATUM", "WGS84") > 0;
     712             :             }
     713             :             else
     714             :             {
     715           1 :                 CPLError(CE_Warning, CPLE_AppDefined,
     716             :                          "Datum \"%s\" probably not supported in the "
     717             :                          "ROI_PAC format, saving it anyway",
     718             :                          m_oSRS.GetAttrValue("DATUM"));
     719           1 :                 bOK &= VSIFPrintfL(fpRsc, "%-40s %s\n", "DATUM",
     720           1 :                                    m_oSRS.GetAttrValue("DATUM")) > 0;
     721             :             }
     722             :         }
     723           3 :         if (m_oSRS.GetAttrValue("UNIT") != nullptr)
     724             :         {
     725           3 :             bOK &= VSIFPrintfL(fpRsc, "%-40s %s\n", "X_UNIT",
     726           3 :                                m_oSRS.GetAttrValue("UNIT")) > 0;
     727           3 :             bOK &= VSIFPrintfL(fpRsc, "%-40s %s\n", "Y_UNIT",
     728           3 :                                m_oSRS.GetAttrValue("UNIT")) > 0;
     729             :         }
     730             :     }
     731           3 :     if (bValidGeoTransform)
     732             :     {
     733           3 :         if (m_gt[2] != 0 || m_gt[4] != 0)
     734             :         {
     735           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     736             :                      "ROI_PAC format do not support geotransform with "
     737             :                      "rotation, discarding info.");
     738             :         }
     739             :         else
     740             :         {
     741           3 :             bOK &= VSIFPrintfL(fpRsc, "%-40s %.16g\n", "X_FIRST", m_gt[0]) > 0;
     742           3 :             bOK &= VSIFPrintfL(fpRsc, "%-40s %.16g\n", "X_STEP", m_gt[1]) > 0;
     743           3 :             bOK &= VSIFPrintfL(fpRsc, "%-40s %.16g\n", "Y_FIRST", m_gt[3]) > 0;
     744           3 :             bOK &= VSIFPrintfL(fpRsc, "%-40s %.16g\n", "Y_STEP", m_gt[5]) > 0;
     745           3 :             bOK &= VSIFPrintfL(fpRsc, "%-40s %.16g\n", "Z_OFFSET",
     746           3 :                                band->GetOffset(nullptr)) > 0;
     747           3 :             bOK &= VSIFPrintfL(fpRsc, "%-40s %.16g\n", "Z_SCALE",
     748           6 :                                band->GetScale(nullptr)) > 0;
     749             :         }
     750             :     }
     751             : 
     752             :     /* -------------------------------------------------------------------- */
     753             :     /*      Metadata stored in the ROI_PAC domain.                          */
     754             :     /* -------------------------------------------------------------------- */
     755           3 :     char **papszROIPACMetadata = GetMetadata("ROI_PAC");
     756           3 :     for (int i = 0; i < CSLCount(papszROIPACMetadata); i++)
     757             :     {
     758             :         /* Get the tokens from the metadata item */
     759             :         char **papszTokens =
     760           0 :             CSLTokenizeString2(papszROIPACMetadata[i], "=",
     761             :                                CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
     762           0 :         if (CSLCount(papszTokens) != 2)
     763             :         {
     764           0 :             CPLDebug("ROI_PAC",
     765             :                      "Line of header file could not be split at = "
     766             :                      "into two elements: %s",
     767           0 :                      papszROIPACMetadata[i]);
     768           0 :             CSLDestroy(papszTokens);
     769           0 :             continue;
     770             :         }
     771             : 
     772             :         /* Don't write it out if it is one of the bits of metadata that is
     773             :          * written out elsewhere in this routine */
     774           0 :         if (strcmp(papszTokens[0], "WIDTH") == 0 ||
     775           0 :             strcmp(papszTokens[0], "FILE_LENGTH") == 0)
     776             :         {
     777           0 :             CSLDestroy(papszTokens);
     778           0 :             continue;
     779             :         }
     780           0 :         bOK &= VSIFPrintfL(fpRsc, "%-40s %s\n", papszTokens[0],
     781           0 :                            papszTokens[1]) > 0;
     782           0 :         CSLDestroy(papszTokens);
     783             :     }
     784           3 :     if (!bOK)
     785           0 :         eErr = CE_Failure;
     786           3 :     return eErr;
     787             : }
     788             : 
     789             : /************************************************************************/
     790             : /*                         GetGeoTransform()                            */
     791             : /************************************************************************/
     792             : 
     793           8 : CPLErr ROIPACDataset::GetGeoTransform(GDALGeoTransform &gt) const
     794             : {
     795           8 :     gt = m_gt;
     796           8 :     return bValidGeoTransform ? CE_None : CE_Failure;
     797             : }
     798             : 
     799             : /************************************************************************/
     800             : /*                          SetGeoTransform()                           */
     801             : /************************************************************************/
     802             : 
     803           3 : CPLErr ROIPACDataset::SetGeoTransform(const GDALGeoTransform &gt)
     804             : {
     805           3 :     m_gt = gt;
     806           3 :     bValidGeoTransform = true;
     807           3 :     return CE_None;
     808             : }
     809             : 
     810             : /************************************************************************/
     811             : /*                           SetSpatialRef()                            */
     812             : /************************************************************************/
     813             : 
     814           3 : CPLErr ROIPACDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
     815             : 
     816             : {
     817           3 :     if (poSRS)
     818           3 :         m_oSRS = *poSRS;
     819             :     else
     820           0 :         m_oSRS.Clear();
     821           3 :     return CE_None;
     822             : }
     823             : 
     824             : /************************************************************************/
     825             : /*                            GetFileList()                             */
     826             : /************************************************************************/
     827             : 
     828           4 : char **ROIPACDataset::GetFileList()
     829             : {
     830             :     // Main data file, etc.
     831           4 :     char **papszFileList = RawDataset::GetFileList();
     832             : 
     833             :     // RSC file.
     834           4 :     papszFileList = CSLAddString(papszFileList, pszRscFilename);
     835             : 
     836           4 :     return papszFileList;
     837             : }
     838             : 
     839             : /************************************************************************/
     840             : /*                        GDALRegister_ROIPAC()                         */
     841             : /************************************************************************/
     842             : 
     843        2038 : void GDALRegister_ROIPAC()
     844             : {
     845        2038 :     if (GDALGetDriverByName("ROI_PAC") != nullptr)
     846         283 :         return;
     847             : 
     848        1755 :     GDALDriver *poDriver = new GDALDriver();
     849             : 
     850        1755 :     poDriver->SetDescription("ROI_PAC");
     851        1755 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "ROI_PAC raster");
     852        1755 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
     853        1755 :                               "drivers/raster/roi_pac.html");
     854        1755 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     855        1755 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     856             : 
     857        1755 :     poDriver->pfnOpen = ROIPACDataset::Open;
     858        1755 :     poDriver->pfnIdentify = ROIPACDataset::Identify;
     859        1755 :     poDriver->pfnCreate = ROIPACDataset::Create;
     860             : 
     861        1755 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     862             : }

Generated by: LCOV version 1.14