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-05-03 15:49:35 Functions: 15 15 100.0 %

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

Generated by: LCOV version 1.14