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

Generated by: LCOV version 1.14