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

Generated by: LCOV version 1.14