LCOV - code coverage report
Current view: top level - frmts/raw - rrasterdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 688 750 91.7 %
Date: 2024-11-21 22:18:42 Functions: 43 44 97.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Implements R Raster Format.
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys dot com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2016, Even Rouault, <even dot rouault at spatialys dot com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_port.h"
      14             : 
      15             : #include "gdal_frmts.h"
      16             : #include "gdal_rat.h"
      17             : #include "gdal_priv.h"
      18             : 
      19             : #include "rawdataset.h"
      20             : #include "ogr_spatialref.h"
      21             : 
      22             : #include <algorithm>
      23             : #include <cmath>
      24             : #include <limits>
      25             : #include <memory>
      26             : 
      27             : /************************************************************************/
      28             : /* ==================================================================== */
      29             : /*                           RRASTERDataset                             */
      30             : /* ==================================================================== */
      31             : /************************************************************************/
      32             : 
      33             : class RRASTERDataset final : public RawDataset
      34             : {
      35             :     bool m_bHeaderDirty = false;
      36             :     CPLString m_osGriFilename{};
      37             :     bool m_bGeoTransformValid = false;
      38             :     double m_adfGeoTransform[6]{0, 1, 0, 0, 0, -1};
      39             :     VSILFILE *m_fpImage = nullptr;
      40             :     OGRSpatialReference m_oSRS{};
      41             :     std::shared_ptr<GDALRasterAttributeTable> m_poRAT{};
      42             :     std::shared_ptr<GDALColorTable> m_poCT{};
      43             :     bool m_bNativeOrder = true;
      44             :     CPLString m_osCreator{};
      45             :     CPLString m_osCreated{};
      46             :     CPLString m_osBandOrder{};
      47             :     CPLString m_osLegend{};
      48             :     bool m_bInitRaster = false;
      49             :     bool m_bSignedByte = false;
      50             : 
      51             :     static bool ComputeSpacings(const CPLString &osBandOrder, int nCols,
      52             :                                 int nRows, int l_nBands, GDALDataType eDT,
      53             :                                 int &nPixelOffset, int &nLineOffset,
      54             :                                 vsi_l_offset &nBandOffset);
      55             :     void RewriteHeader();
      56             : 
      57             :     CPL_DISALLOW_COPY_ASSIGN(RRASTERDataset)
      58             : 
      59             :     CPLErr Close() override;
      60             : 
      61             :   public:
      62             :     RRASTERDataset();
      63             :     ~RRASTERDataset() override;
      64             : 
      65             :     char **GetFileList() override;
      66             : 
      67             :     static GDALDataset *Open(GDALOpenInfo *);
      68             :     static int Identify(GDALOpenInfo *);
      69             :     static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
      70             :                                int nBandsIn, GDALDataType eType,
      71             :                                char **papszOptions);
      72             :     static GDALDataset *CreateCopy(const char *pszFilename,
      73             :                                    GDALDataset *poSrcDS, int bStrict,
      74             :                                    char **papszOptions,
      75             :                                    GDALProgressFunc pfnProgress,
      76             :                                    void *pProgressData);
      77             : 
      78             :     CPLErr GetGeoTransform(double *) override;
      79             :     CPLErr SetGeoTransform(double *padfGeoTransform) override;
      80             :     const OGRSpatialReference *GetSpatialRef() const override;
      81             :     CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
      82             : 
      83             :     CPLErr SetMetadata(char **papszMetadata,
      84             :                        const char *pszDomain = "") override;
      85             :     CPLErr SetMetadataItem(const char *pszName, const char *pszValue,
      86             :                            const char *pszDomain = "") override;
      87             : 
      88         173 :     void SetHeaderDirty()
      89             :     {
      90         173 :         m_bHeaderDirty = true;
      91         173 :     }
      92             : 
      93             :     void InitImageIfNeeded();
      94             : 
      95          80 :     inline bool IsSignedByte() const
      96             :     {
      97          80 :         return m_bSignedByte;
      98             :     }
      99             : };
     100             : 
     101             : /************************************************************************/
     102             : /* ==================================================================== */
     103             : /*                         RRASTERRasterBand                            */
     104             : /* ==================================================================== */
     105             : /************************************************************************/
     106             : 
     107             : class RRASTERRasterBand final : public RawRasterBand
     108             : {
     109             :     friend class RRASTERDataset;
     110             : 
     111             :     bool m_bHasNoDataValue = false;
     112             :     double m_dfNoDataValue = 0.0;
     113             :     double m_dfMin = std::numeric_limits<double>::infinity();
     114             :     double m_dfMax = -std::numeric_limits<double>::infinity();
     115             :     std::shared_ptr<GDALRasterAttributeTable> m_poRAT{};
     116             :     std::shared_ptr<GDALColorTable> m_poCT{};
     117             : 
     118             :     CPL_DISALLOW_COPY_ASSIGN(RRASTERRasterBand)
     119             : 
     120             :   public:
     121             :     RRASTERRasterBand(GDALDataset *poDS, int nBand, VSILFILE *fpRaw,
     122             :                       vsi_l_offset nImgOffset, int nPixelOffset,
     123             :                       int nLineOffset, GDALDataType eDataType,
     124             :                       int bNativeOrder);
     125             : 
     126             :     void SetMinMax(double dfMin, double dfMax);
     127             :     double GetMinimum(int *pbSuccess = nullptr) override;
     128             :     double GetMaximum(int *pbSuccess = nullptr) override;
     129             : 
     130             :     double GetNoDataValue(int *pbSuccess = nullptr) override;
     131             :     CPLErr SetNoDataValue(double dfNoData) override;
     132             : 
     133             :     GDALColorTable *GetColorTable() override;
     134             :     CPLErr SetColorTable(GDALColorTable *poNewCT) override;
     135             : 
     136             :     GDALRasterAttributeTable *GetDefaultRAT() override;
     137             :     CPLErr SetDefaultRAT(const GDALRasterAttributeTable *poRAT) override;
     138             : 
     139             :     void SetDescription(const char *pszDesc) override;
     140             : 
     141             :   protected:
     142             :     CPLErr IWriteBlock(int, int, void *) override;
     143             :     CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
     144             :                      GDALDataType, GSpacing nPixelSpace, GSpacing nLineSpace,
     145             :                      GDALRasterIOExtraArg *psExtraArg) override;
     146             : };
     147             : 
     148             : /************************************************************************/
     149             : /*                           RRASTERDataset()                           */
     150             : /************************************************************************/
     151             : 
     152         260 : RRASTERRasterBand::RRASTERRasterBand(GDALDataset *poDSIn, int nBandIn,
     153             :                                      VSILFILE *fpRawIn,
     154             :                                      vsi_l_offset nImgOffsetIn,
     155             :                                      int nPixelOffsetIn, int nLineOffsetIn,
     156             :                                      GDALDataType eDataTypeIn,
     157         260 :                                      int bNativeOrderIn)
     158             :     : RawRasterBand(poDSIn, nBandIn, fpRawIn, nImgOffsetIn, nPixelOffsetIn,
     159             :                     nLineOffsetIn, eDataTypeIn, bNativeOrderIn,
     160         260 :                     RawRasterBand::OwnFP::NO)
     161             : {
     162         260 : }
     163             : 
     164             : /************************************************************************/
     165             : /*                             SetMinMax()                              */
     166             : /************************************************************************/
     167             : 
     168          73 : void RRASTERRasterBand::SetMinMax(double dfMin, double dfMax)
     169             : {
     170          73 :     m_dfMin = dfMin;
     171          73 :     m_dfMax = dfMax;
     172          73 : }
     173             : 
     174             : /************************************************************************/
     175             : /*                            GetMinimum()                              */
     176             : /************************************************************************/
     177             : 
     178          29 : double RRASTERRasterBand::GetMinimum(int *pbSuccess)
     179             : {
     180          29 :     if (m_dfMin <= m_dfMax)
     181             :     {
     182          22 :         if (pbSuccess)
     183          22 :             *pbSuccess = TRUE;
     184          22 :         return m_dfMin;
     185             :     }
     186           7 :     return RawRasterBand::GetMinimum(pbSuccess);
     187             : }
     188             : 
     189             : /************************************************************************/
     190             : /*                            GetMaximum()                              */
     191             : /************************************************************************/
     192             : 
     193          28 : double RRASTERRasterBand::GetMaximum(int *pbSuccess)
     194             : {
     195          28 :     if (m_dfMin <= m_dfMax)
     196             :     {
     197          21 :         if (pbSuccess)
     198          21 :             *pbSuccess = TRUE;
     199          21 :         return m_dfMax;
     200             :     }
     201           7 :     return RawRasterBand::GetMaximum(pbSuccess);
     202             : }
     203             : 
     204             : /************************************************************************/
     205             : /*                           GetColorTable()                            */
     206             : /************************************************************************/
     207             : 
     208          86 : GDALColorTable *RRASTERRasterBand::GetColorTable()
     209             : {
     210          86 :     return m_poCT.get();
     211             : }
     212             : 
     213             : /************************************************************************/
     214             : /*                           SetColorTable()                            */
     215             : /************************************************************************/
     216             : 
     217           3 : CPLErr RRASTERRasterBand::SetColorTable(GDALColorTable *poNewCT)
     218             : {
     219           3 :     RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS);
     220           3 :     if (poGDS->GetAccess() != GA_Update)
     221           0 :         return CE_Failure;
     222             : 
     223           3 :     if (poNewCT == nullptr)
     224           1 :         m_poCT.reset();
     225             :     else
     226           2 :         m_poCT.reset(poNewCT->Clone());
     227             : 
     228           3 :     poGDS->SetHeaderDirty();
     229             : 
     230           3 :     return CE_None;
     231             : }
     232             : 
     233             : /************************************************************************/
     234             : /*                           GetDefaultRAT()                            */
     235             : /************************************************************************/
     236             : 
     237         110 : GDALRasterAttributeTable *RRASTERRasterBand::GetDefaultRAT()
     238             : {
     239         110 :     return m_poRAT.get();
     240             : }
     241             : 
     242             : /************************************************************************/
     243             : /*                            SetDefaultRAT()                           */
     244             : /************************************************************************/
     245             : 
     246           2 : CPLErr RRASTERRasterBand::SetDefaultRAT(const GDALRasterAttributeTable *poRAT)
     247             : {
     248           2 :     RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS);
     249           2 :     if (poGDS->GetAccess() != GA_Update)
     250           0 :         return CE_Failure;
     251             : 
     252           2 :     if (poRAT == nullptr)
     253           1 :         m_poRAT.reset();
     254             :     else
     255           1 :         m_poRAT.reset(poRAT->Clone());
     256             : 
     257           2 :     poGDS->SetHeaderDirty();
     258             : 
     259           2 :     return CE_None;
     260             : }
     261             : 
     262             : /************************************************************************/
     263             : /*                           SetDescription()                           */
     264             : /************************************************************************/
     265             : 
     266          20 : void RRASTERRasterBand::SetDescription(const char *pszDesc)
     267             : {
     268          20 :     RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS);
     269          20 :     if (poGDS->GetAccess() != GA_Update)
     270           0 :         return;
     271             : 
     272          20 :     GDALRasterBand::SetDescription(pszDesc);
     273             : 
     274          20 :     poGDS->SetHeaderDirty();
     275             : }
     276             : 
     277             : /************************************************************************/
     278             : /*                           GetNoDataValue()                           */
     279             : /************************************************************************/
     280             : 
     281         259 : double RRASTERRasterBand::GetNoDataValue(int *pbSuccess)
     282             : {
     283         259 :     if (pbSuccess)
     284         259 :         *pbSuccess = m_bHasNoDataValue;
     285         259 :     return m_dfNoDataValue;
     286             : }
     287             : 
     288             : /************************************************************************/
     289             : /*                           SetNoDataValue()                           */
     290             : /************************************************************************/
     291             : 
     292           2 : CPLErr RRASTERRasterBand::SetNoDataValue(double dfNoData)
     293             : {
     294           2 :     RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS);
     295           2 :     if (poGDS->GetAccess() != GA_Update)
     296           0 :         return CE_Failure;
     297             : 
     298           2 :     m_bHasNoDataValue = true;
     299           2 :     m_dfNoDataValue = dfNoData;
     300           2 :     poGDS->SetHeaderDirty();
     301           2 :     return CE_None;
     302             : }
     303             : 
     304             : /************************************************************************/
     305             : /*                             GetMinMax()                              */
     306             : /************************************************************************/
     307             : 
     308             : template <class T>
     309          80 : static void GetMinMax(const T *buffer, int nBufXSize, int nBufYSize,
     310             :                       GSpacing nPixelSpace, GSpacing nLineSpace,
     311             :                       double dfNoDataValue, double &dfMin, double &dfMax)
     312             : {
     313         702 :     for (int iY = 0; iY < nBufYSize; iY++)
     314             :     {
     315        9386 :         for (int iX = 0; iX < nBufXSize; iX++)
     316             :         {
     317        8764 :             const double dfVal = buffer[iY * nLineSpace + iX * nPixelSpace];
     318        8764 :             if (dfVal != dfNoDataValue && !std::isnan(dfVal))
     319             :             {
     320        8764 :                 dfMin = std::min(dfMin, dfVal);
     321        8764 :                 dfMax = std::max(dfMax, dfVal);
     322             :             }
     323             :         }
     324             :     }
     325          80 : }
     326             : 
     327          80 : static void GetMinMax(const void *pBuffer, GDALDataType eDT, int nBufXSize,
     328             :                       int nBufYSize, GSpacing nPixelSpace, GSpacing nLineSpace,
     329             :                       double dfNoDataValue, double &dfMin, double &dfMax)
     330             : {
     331          80 :     switch (eDT)
     332             :     {
     333          66 :         case GDT_Byte:
     334          66 :             GetMinMax(static_cast<const GByte *>(pBuffer), nBufXSize, nBufYSize,
     335             :                       nPixelSpace, nLineSpace, dfNoDataValue, dfMin, dfMax);
     336          66 :             break;
     337           2 :         case GDT_Int8:
     338           2 :             GetMinMax(static_cast<const GInt8 *>(pBuffer), nBufXSize, nBufYSize,
     339             :                       nPixelSpace, nLineSpace, dfNoDataValue, dfMin, dfMax);
     340           2 :             break;
     341           2 :         case GDT_UInt16:
     342           2 :             GetMinMax(static_cast<const GUInt16 *>(pBuffer), nBufXSize,
     343             :                       nBufYSize, nPixelSpace, nLineSpace, dfNoDataValue, dfMin,
     344             :                       dfMax);
     345           2 :             break;
     346           2 :         case GDT_Int16:
     347           2 :             GetMinMax(static_cast<const GInt16 *>(pBuffer), nBufXSize,
     348             :                       nBufYSize, nPixelSpace, nLineSpace, dfNoDataValue, dfMin,
     349             :                       dfMax);
     350           2 :             break;
     351           2 :         case GDT_UInt32:
     352           2 :             GetMinMax(static_cast<const GUInt32 *>(pBuffer), nBufXSize,
     353             :                       nBufYSize, nPixelSpace, nLineSpace, dfNoDataValue, dfMin,
     354             :                       dfMax);
     355           2 :             break;
     356           2 :         case GDT_Int32:
     357           2 :             GetMinMax(static_cast<const GInt32 *>(pBuffer), nBufXSize,
     358             :                       nBufYSize, nPixelSpace, nLineSpace, dfNoDataValue, dfMin,
     359             :                       dfMax);
     360           2 :             break;
     361           2 :         case GDT_Float32:
     362           2 :             GetMinMax(static_cast<const float *>(pBuffer), nBufXSize, nBufYSize,
     363             :                       nPixelSpace, nLineSpace, dfNoDataValue, dfMin, dfMax);
     364           2 :             break;
     365           2 :         case GDT_Float64:
     366           2 :             GetMinMax(static_cast<const double *>(pBuffer), nBufXSize,
     367             :                       nBufYSize, nPixelSpace, nLineSpace, dfNoDataValue, dfMin,
     368             :                       dfMax);
     369           2 :             break;
     370           0 :         default:
     371           0 :             CPLAssert(false);
     372             :             break;
     373             :     }
     374          80 : }
     375             : 
     376             : /************************************************************************/
     377             : /*                            IWriteBlock()                             */
     378             : /************************************************************************/
     379             : 
     380          20 : CPLErr RRASTERRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
     381             :                                       void *pImage)
     382             : {
     383          20 :     RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS);
     384          20 :     poGDS->InitImageIfNeeded();
     385             : 
     386          20 :     int bGotNoDataValue = false;
     387          20 :     double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
     388          20 :     if (!bGotNoDataValue)
     389          20 :         dfNoDataValue = std::numeric_limits<double>::quiet_NaN();
     390          20 :     GetMinMax(pImage, poGDS->IsSignedByte() ? GDT_Int8 : eDataType, nBlockXSize,
     391          20 :               nBlockYSize, 1, nBlockXSize, dfNoDataValue, m_dfMin, m_dfMax);
     392          40 :     return RawRasterBand::IWriteBlock(nBlockXOff, nBlockYOff, pImage);
     393             : }
     394             : 
     395             : /************************************************************************/
     396             : /*                             IRasterIO()                              */
     397             : /************************************************************************/
     398             : 
     399         323 : CPLErr RRASTERRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     400             :                                     int nXSize, int nYSize, void *pData,
     401             :                                     int nBufXSize, int nBufYSize,
     402             :                                     GDALDataType eBufType, GSpacing nPixelSpace,
     403             :                                     GSpacing nLineSpace,
     404             :                                     GDALRasterIOExtraArg *psExtraArg)
     405             : 
     406             : {
     407         323 :     if (eRWFlag == GF_Write)
     408             :     {
     409          60 :         RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS);
     410          60 :         poGDS->InitImageIfNeeded();
     411             : 
     412          60 :         const int nDTSize = std::max(1, GDALGetDataTypeSizeBytes(eDataType));
     413          60 :         int bGotNoDataValue = false;
     414          60 :         double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
     415          60 :         if (!bGotNoDataValue)
     416          59 :             dfNoDataValue = std::numeric_limits<double>::quiet_NaN();
     417          60 :         GetMinMax(pData, poGDS->IsSignedByte() ? GDT_Int8 : eDataType,
     418          60 :                   nBufXSize, nBufYSize, nPixelSpace / nDTSize,
     419          60 :                   nLineSpace / nDTSize, dfNoDataValue, m_dfMin, m_dfMax);
     420             :     }
     421         323 :     return RawRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     422             :                                     pData, nBufXSize, nBufYSize, eBufType,
     423         323 :                                     nPixelSpace, nLineSpace, psExtraArg);
     424             : }
     425             : 
     426             : /************************************************************************/
     427             : /*                           RRASTERDataset()                           */
     428             : /************************************************************************/
     429             : 
     430         142 : RRASTERDataset::RRASTERDataset()
     431             : {
     432         142 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     433         142 : }
     434             : 
     435             : /************************************************************************/
     436             : /*                          ~RRASTERDataset()                           */
     437             : /************************************************************************/
     438             : 
     439         284 : RRASTERDataset::~RRASTERDataset()
     440             : 
     441             : {
     442         142 :     RRASTERDataset::Close();
     443         284 : }
     444             : 
     445             : /************************************************************************/
     446             : /*                              Close()                                 */
     447             : /************************************************************************/
     448             : 
     449         277 : CPLErr RRASTERDataset::Close()
     450             : {
     451         277 :     CPLErr eErr = CE_None;
     452         277 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
     453             :     {
     454         142 :         if (m_fpImage)
     455             :         {
     456         142 :             InitImageIfNeeded();
     457         142 :             if (RRASTERDataset::FlushCache(true) != CE_None)
     458           2 :                 eErr = CE_Failure;
     459         142 :             if (VSIFCloseL(m_fpImage) != CE_None)
     460           0 :                 eErr = CE_Failure;
     461             :         }
     462         142 :         if (m_bHeaderDirty)
     463          59 :             RewriteHeader();
     464             : 
     465         142 :         if (GDALPamDataset::Close() != CE_None)
     466           0 :             eErr = CE_Failure;
     467             :     }
     468         277 :     return eErr;
     469             : }
     470             : 
     471             : /************************************************************************/
     472             : /*                        InitImageIfNeeded()                           */
     473             : /************************************************************************/
     474             : 
     475         222 : void RRASTERDataset::InitImageIfNeeded()
     476             : {
     477         222 :     CPLAssert(m_fpImage);
     478         222 :     if (!m_bInitRaster)
     479         201 :         return;
     480          21 :     m_bInitRaster = false;
     481          21 :     int bGotNoDataValue = false;
     482          21 :     double dfNoDataValue = GetRasterBand(1)->GetNoDataValue(&bGotNoDataValue);
     483          21 :     const GDALDataType eDT = GetRasterBand(1)->GetRasterDataType();
     484          21 :     const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
     485          21 :     if (dfNoDataValue == 0.0)
     486             :     {
     487          20 :         VSIFTruncateL(m_fpImage, static_cast<vsi_l_offset>(nRasterXSize) *
     488          20 :                                      nRasterYSize * nBands * nDTSize);
     489             :     }
     490             :     else
     491             :     {
     492             :         GByte abyNoDataValue[16];
     493           1 :         GDALCopyWords(&dfNoDataValue, GDT_Float64, 0, abyNoDataValue, eDT, 0,
     494             :                       1);
     495           2 :         for (GUIntBig i = 0;
     496           2 :              i < static_cast<GUIntBig>(nRasterXSize) * nRasterYSize * nBands;
     497             :              i++)
     498             :         {
     499           1 :             VSIFWriteL(abyNoDataValue, 1, nDTSize, m_fpImage);
     500             :         }
     501             :     }
     502             : }
     503             : 
     504             : /************************************************************************/
     505             : /*                           RewriteHeader()                            */
     506             : /************************************************************************/
     507             : 
     508          59 : void RRASTERDataset::RewriteHeader()
     509             : {
     510          59 :     VSILFILE *fp = VSIFOpenL(GetDescription(), "wb");
     511          59 :     if (!fp)
     512           0 :         return;
     513             : 
     514          59 :     VSIFPrintfL(fp, "[general]\n");
     515          59 :     if (!m_osCreator.empty())
     516           4 :         VSIFPrintfL(fp, "creator=%s\n", m_osCreator.c_str());
     517          59 :     if (!m_osCreated.empty())
     518           4 :         VSIFPrintfL(fp, "created=%s\n", m_osCreated.c_str());
     519             : 
     520          59 :     VSIFPrintfL(fp, "[data]\n");
     521          59 :     GDALDataType eDT = GetRasterBand(1)->GetRasterDataType();
     522         115 :     VSIFPrintfL(fp, "datatype=%s\n",
     523          56 :                 (eDT == GDT_Int8 || m_bSignedByte) ? "INT1S"
     524             :                 : (eDT == GDT_Byte)                ? "INT1U"
     525             :                 : (eDT == GDT_UInt16)              ? "INT2U"
     526             :                 : (eDT == GDT_UInt32)              ? "INT4U"
     527             :                 : (eDT == GDT_Int16)               ? "INT2S"
     528             :                 : (eDT == GDT_Int32)               ? "INT4S"
     529             :                 : (eDT == GDT_Float32)             ? "FLT4S"
     530             :                                                    :
     531             :                                        /*(eDT == GDT_Float64) ?*/ "FLT8S");
     532             : 
     533          59 :     int bGotNoDataValue = false;
     534          59 :     double dfNoDataValue = GetRasterBand(1)->GetNoDataValue(&bGotNoDataValue);
     535          59 :     if (bGotNoDataValue)
     536           2 :         VSIFPrintfL(fp, "nodatavalue=%.17g\n", dfNoDataValue);
     537             : 
     538             : #if CPL_IS_LSB
     539          59 :     VSIFPrintfL(fp, "byteorder=%s\n", m_bNativeOrder ? "little" : "big");
     540             : #else
     541             :     VSIFPrintfL(fp, "byteorder=%s\n", !m_bNativeOrder ? "little" : "big");
     542             : #endif
     543          59 :     VSIFPrintfL(fp, "nbands=%d\n", nBands);
     544          59 :     if (nBands > 1)
     545          20 :         VSIFPrintfL(fp, "bandorder=%s\n", m_osBandOrder.c_str());
     546         118 :     CPLString osMinValue, osMaxValue;
     547         119 :     for (int i = 1; i <= nBands; i++)
     548             :     {
     549             :         RRASTERRasterBand *poBand =
     550          81 :             static_cast<RRASTERRasterBand *>(GetRasterBand(i));
     551          81 :         if (i > 1)
     552             :         {
     553          22 :             osMinValue += ":";
     554          22 :             osMaxValue += ":";
     555             :         }
     556          81 :         if (poBand->m_dfMin > poBand->m_dfMax)
     557             :         {
     558          21 :             osMinValue.clear();
     559          21 :             break;
     560             :         }
     561          60 :         osMinValue += CPLSPrintf("%.17g", poBand->m_dfMin);
     562          60 :         osMaxValue += CPLSPrintf("%.17g", poBand->m_dfMax);
     563             :     }
     564          59 :     if (!osMinValue.empty())
     565             :     {
     566          38 :         VSIFPrintfL(fp, "minvalue=%s\n", osMinValue.c_str());
     567          38 :         VSIFPrintfL(fp, "maxvalue=%s\n", osMaxValue.c_str());
     568             :     }
     569             : 
     570          59 :     GDALColorTable *poCT = GetRasterBand(1)->GetColorTable();
     571          59 :     GDALRasterAttributeTable *poRAT = GetRasterBand(1)->GetDefaultRAT();
     572          59 :     if (poCT == nullptr && poRAT == nullptr)
     573             :     {
     574          56 :         VSIFPrintfL(fp, "categorical=FALSE\n");
     575             :     }
     576             :     else
     577             :     {
     578           3 :         VSIFPrintfL(fp, "categorical=TRUE\n");
     579           3 :         if (poCT && poRAT)
     580             :         {
     581           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     582             :                      "Both color table and raster attribute table defined. "
     583             :                      "Writing only the later");
     584             :         }
     585           3 :         if (poRAT)
     586             :         {
     587           2 :             CPLString osRatNames;
     588           2 :             CPLString osRatTypes;
     589          11 :             for (int i = 0; i < poRAT->GetColumnCount(); i++)
     590             :             {
     591          10 :                 if (!osRatNames.empty())
     592             :                 {
     593           9 :                     osRatNames += ":";
     594           9 :                     osRatTypes += ":";
     595             :                 }
     596             :                 osRatNames +=
     597          10 :                     CPLString(poRAT->GetNameOfCol(i)).replaceAll(':', '.');
     598          10 :                 GDALRATFieldType eColType = poRAT->GetTypeOfCol(i);
     599          10 :                 if (eColType == GFT_Integer)
     600           7 :                     osRatTypes += "integer";
     601           3 :                 else if (eColType == GFT_Real)
     602           1 :                     osRatTypes += "numeric";
     603             :                 else
     604           2 :                     osRatTypes += "character";
     605             :             }
     606           1 :             VSIFPrintfL(fp, "ratnames=%s\n", osRatNames.c_str());
     607           1 :             VSIFPrintfL(fp, "rattypes=%s\n", osRatTypes.c_str());
     608           2 :             CPLString osRatValues;
     609          11 :             for (int i = 0; i < poRAT->GetColumnCount(); i++)
     610             :             {
     611          10 :                 GDALRATFieldType eColType = poRAT->GetTypeOfCol(i);
     612          30 :                 for (int j = 0; j < poRAT->GetRowCount(); j++)
     613             :                 {
     614          20 :                     if (i != 0 || j != 0)
     615          19 :                         osRatValues += ":";
     616          20 :                     if (eColType == GFT_Integer)
     617             :                     {
     618             :                         osRatValues +=
     619          14 :                             CPLSPrintf("%d", poRAT->GetValueAsInt(j, i));
     620             :                     }
     621           6 :                     else if (eColType == GFT_Real)
     622             :                     {
     623             :                         osRatValues +=
     624           2 :                             CPLSPrintf("%.17g", poRAT->GetValueAsDouble(j, i));
     625             :                     }
     626             :                     else
     627             :                     {
     628           4 :                         const char *pszVal = poRAT->GetValueAsString(j, i);
     629           4 :                         if (pszVal)
     630             :                         {
     631             :                             osRatValues +=
     632           4 :                                 CPLString(pszVal).replaceAll(':', '.');
     633             :                         }
     634             :                     }
     635             :                 }
     636             :             }
     637           1 :             VSIFPrintfL(fp, "ratvalues=%s\n", osRatValues.c_str());
     638             :         }
     639             :         else
     640             :         {
     641           2 :             bool bNeedsAlpha = false;
     642           4 :             for (int i = 0; i < poCT->GetColorEntryCount(); i++)
     643             :             {
     644           3 :                 if (poCT->GetColorEntry(i)->c4 != 255)
     645             :                 {
     646           1 :                     bNeedsAlpha = true;
     647           1 :                     break;
     648             :                 }
     649             :             }
     650           2 :             if (!bNeedsAlpha)
     651             :             {
     652           1 :                 VSIFPrintfL(fp, "ratnames=%s\n", "ID:red:green:blue");
     653           1 :                 VSIFPrintfL(fp, "rattypes=%s\n",
     654             :                             "integer:integer:integer:integer");
     655             :             }
     656             :             else
     657             :             {
     658           1 :                 VSIFPrintfL(fp, "ratnames=%s\n", "ID:red:green:blue:alpha");
     659           1 :                 VSIFPrintfL(fp, "rattypes=%s\n",
     660             :                             "integer:integer:integer:integer:integer");
     661             :             }
     662             : 
     663           4 :             CPLString osRatID;
     664           4 :             CPLString osRatR;
     665           4 :             CPLString osRatG;
     666           4 :             CPLString osRatB;
     667           4 :             CPLString osRatA;
     668           6 :             for (int i = 0; i < poCT->GetColorEntryCount(); i++)
     669             :             {
     670           4 :                 const GDALColorEntry *psEntry = poCT->GetColorEntry(i);
     671           4 :                 if (i > 0)
     672             :                 {
     673           2 :                     osRatID += ":";
     674           2 :                     osRatR += ":";
     675           2 :                     osRatG += ":";
     676           2 :                     osRatB += ":";
     677           2 :                     osRatA += ":";
     678             :                 }
     679           4 :                 osRatID += CPLSPrintf("%d", i);
     680           4 :                 osRatR += CPLSPrintf("%d", psEntry->c1);
     681           4 :                 osRatG += CPLSPrintf("%d", psEntry->c2);
     682           4 :                 osRatB += CPLSPrintf("%d", psEntry->c3);
     683           4 :                 osRatA += CPLSPrintf("%d", psEntry->c4);
     684             :             }
     685           2 :             if (!bNeedsAlpha)
     686             :             {
     687           1 :                 VSIFPrintfL(fp, "ratvalues=%s:%s:%s:%s\n", osRatID.c_str(),
     688             :                             osRatR.c_str(), osRatG.c_str(), osRatB.c_str());
     689             :             }
     690             :             else
     691             :             {
     692           1 :                 VSIFPrintfL(fp, "ratvalues=%s:%s:%s:%s:%s\n", osRatID.c_str(),
     693             :                             osRatR.c_str(), osRatG.c_str(), osRatB.c_str(),
     694             :                             osRatA.c_str());
     695             :             }
     696             :         }
     697             :     }
     698             : 
     699          59 :     if (!m_osLegend.empty())
     700           0 :         VSIFPrintfL(fp, "[legend]\n%s", m_osLegend.c_str());
     701             : 
     702         118 :     CPLString osLayerName;
     703          59 :     bool bGotSignificantBandDesc = false;
     704         167 :     for (int i = 1; i <= nBands; i++)
     705             :     {
     706         108 :         GDALRasterBand *poBand = GetRasterBand(i);
     707         108 :         const char *pszDesc = poBand->GetDescription();
     708         108 :         if (EQUAL(pszDesc, ""))
     709             :         {
     710          88 :             GDALColorInterp eInterp = poBand->GetColorInterpretation();
     711          88 :             if (eInterp == GCI_RedBand)
     712             :             {
     713           1 :                 bGotSignificantBandDesc = true;
     714           1 :                 pszDesc = "red";
     715             :             }
     716          87 :             else if (eInterp == GCI_GreenBand)
     717             :             {
     718           1 :                 bGotSignificantBandDesc = true;
     719           1 :                 pszDesc = "green";
     720             :             }
     721          86 :             else if (eInterp == GCI_BlueBand)
     722             :             {
     723           1 :                 bGotSignificantBandDesc = true;
     724           1 :                 pszDesc = "blue";
     725             :             }
     726          85 :             else if (eInterp == GCI_AlphaBand)
     727             :             {
     728           1 :                 bGotSignificantBandDesc = true;
     729           1 :                 pszDesc = "alpha";
     730             :             }
     731             :             else
     732             :             {
     733          84 :                 pszDesc = CPLSPrintf("Band%d", i);
     734             :             }
     735             :         }
     736             :         else
     737             :         {
     738          20 :             bGotSignificantBandDesc = true;
     739             :         }
     740         108 :         if (i > 1)
     741          49 :             osLayerName += ":";
     742         108 :         osLayerName += CPLString(pszDesc).replaceAll(':', '.');
     743             :     }
     744          59 :     if (bGotSignificantBandDesc)
     745             :     {
     746           9 :         VSIFPrintfL(fp, "[description]\n");
     747           9 :         VSIFPrintfL(fp, "layername=%s\n", osLayerName.c_str());
     748             :     }
     749             : 
     750             :     // Put the [georeference] section at end. Otherwise the wkt= entry
     751             :     // could cause GDAL < 3.5 to be unable to open the file due to the
     752             :     // Identify() function not using enough bytes
     753          59 :     VSIFPrintfL(fp, "[georeference]\n");
     754          59 :     VSIFPrintfL(fp, "nrows=%d\n", nRasterYSize);
     755          59 :     VSIFPrintfL(fp, "ncols=%d\n", nRasterXSize);
     756             : 
     757          59 :     VSIFPrintfL(fp, "xmin=%.17g\n", m_adfGeoTransform[0]);
     758          59 :     VSIFPrintfL(fp, "ymin=%.17g\n",
     759          59 :                 m_adfGeoTransform[3] + nRasterYSize * m_adfGeoTransform[5]);
     760          59 :     VSIFPrintfL(fp, "xmax=%.17g\n",
     761          59 :                 m_adfGeoTransform[0] + nRasterXSize * m_adfGeoTransform[1]);
     762          59 :     VSIFPrintfL(fp, "ymax=%.17g\n", m_adfGeoTransform[3]);
     763             : 
     764          59 :     if (!m_oSRS.IsEmpty())
     765             :     {
     766          57 :         char *pszProj4 = nullptr;
     767          57 :         m_oSRS.exportToProj4(&pszProj4);
     768          57 :         if (pszProj4)
     769             :         {
     770          57 :             VSIFPrintfL(fp, "projection=%s\n", pszProj4);
     771          57 :             VSIFree(pszProj4);
     772             :         }
     773          57 :         char *pszWKT = nullptr;
     774          57 :         const char *const apszOptions[] = {"FORMAT=WKT2_2019", nullptr};
     775          57 :         m_oSRS.exportToWkt(&pszWKT, apszOptions);
     776          57 :         if (pszWKT)
     777             :         {
     778          57 :             VSIFPrintfL(fp, "wkt=%s\n", pszWKT);
     779          57 :             VSIFree(pszWKT);
     780             :         }
     781             :     }
     782             : 
     783          59 :     VSIFCloseL(fp);
     784             : }
     785             : 
     786             : /************************************************************************/
     787             : /*                            GetFileList()                             */
     788             : /************************************************************************/
     789             : 
     790          37 : char **RRASTERDataset::GetFileList()
     791             : 
     792             : {
     793          37 :     char **papszFileList = RawDataset::GetFileList();
     794             : 
     795          37 :     papszFileList = CSLAddString(papszFileList, m_osGriFilename);
     796             : 
     797          37 :     return papszFileList;
     798             : }
     799             : 
     800             : /************************************************************************/
     801             : /*                          GetGeoTransform()                           */
     802             : /************************************************************************/
     803             : 
     804         120 : CPLErr RRASTERDataset::GetGeoTransform(double *padfGeoTransform)
     805             : {
     806         120 :     if (m_bGeoTransformValid)
     807             :     {
     808         120 :         memcpy(padfGeoTransform, m_adfGeoTransform, 6 * sizeof(double));
     809         120 :         return CE_None;
     810             :     }
     811           0 :     return CE_Failure;
     812             : }
     813             : 
     814             : /************************************************************************/
     815             : /*                          SetGeoTransform()                           */
     816             : /************************************************************************/
     817             : 
     818          57 : CPLErr RRASTERDataset::SetGeoTransform(double *padfGeoTransform)
     819             : 
     820             : {
     821          57 :     if (GetAccess() != GA_Update)
     822             :     {
     823           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     824             :                  "Cannot set geotransform on a read-only dataset");
     825           0 :         return CE_Failure;
     826             :     }
     827             : 
     828             :     // We only support non-rotated images with info in the .HDR file.
     829          57 :     if (padfGeoTransform[2] != 0.0 || padfGeoTransform[4] != 0.0)
     830             :     {
     831           0 :         CPLError(CE_Warning, CPLE_NotSupported,
     832             :                  "Rotated / skewed images not supported");
     833           0 :         return GDALPamDataset::SetGeoTransform(padfGeoTransform);
     834             :     }
     835             : 
     836             :     // Record new geotransform.
     837          57 :     m_bGeoTransformValid = true;
     838          57 :     memcpy(m_adfGeoTransform, padfGeoTransform, sizeof(double) * 6);
     839          57 :     SetHeaderDirty();
     840             : 
     841          57 :     return CE_None;
     842             : }
     843             : 
     844             : /************************************************************************/
     845             : /*                           GetSpatialRef()                            */
     846             : /************************************************************************/
     847             : 
     848          35 : const OGRSpatialReference *RRASTERDataset::GetSpatialRef() const
     849             : {
     850          35 :     return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
     851             : }
     852             : 
     853             : /************************************************************************/
     854             : /*                           SetSpatialRef()                            */
     855             : /************************************************************************/
     856             : 
     857          57 : CPLErr RRASTERDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
     858             : {
     859          57 :     if (GetAccess() != GA_Update)
     860             :     {
     861           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     862             :                  "Cannot set projection on a read-only dataset");
     863           0 :         return CE_Failure;
     864             :     }
     865             : 
     866          57 :     m_oSRS.Clear();
     867          57 :     if (poSRS)
     868          57 :         m_oSRS = *poSRS;
     869          57 :     SetHeaderDirty();
     870             : 
     871          57 :     return CE_None;
     872             : }
     873             : 
     874             : /************************************************************************/
     875             : /*                            SetMetadata()                             */
     876             : /************************************************************************/
     877             : 
     878          30 : CPLErr RRASTERDataset::SetMetadata(char **papszMetadata, const char *pszDomain)
     879             : {
     880          30 :     if (pszDomain == nullptr || EQUAL(pszDomain, ""))
     881             :     {
     882          30 :         m_osCreator = CSLFetchNameValueDef(papszMetadata, "CREATOR", "");
     883          30 :         m_osCreated = CSLFetchNameValueDef(papszMetadata, "CREATED", "");
     884          30 :         SetHeaderDirty();
     885             :     }
     886          30 :     return GDALDataset::SetMetadata(papszMetadata, pszDomain);
     887             : }
     888             : 
     889             : /************************************************************************/
     890             : /*                          SetMetadataItem()                           */
     891             : /************************************************************************/
     892             : 
     893           2 : CPLErr RRASTERDataset::SetMetadataItem(const char *pszName,
     894             :                                        const char *pszValue,
     895             :                                        const char *pszDomain)
     896             : {
     897           2 :     if (pszDomain == nullptr || EQUAL(pszDomain, ""))
     898             :     {
     899           2 :         if (EQUAL(pszName, "CREATOR"))
     900             :         {
     901           1 :             m_osCreator = pszValue ? pszValue : "";
     902           1 :             SetHeaderDirty();
     903             :         }
     904           2 :         if (EQUAL(pszName, "CREATED"))
     905             :         {
     906           1 :             m_osCreated = pszValue ? pszValue : "";
     907           1 :             SetHeaderDirty();
     908             :         }
     909             :     }
     910           2 :     return GDALDataset::SetMetadataItem(pszName, pszValue, pszDomain);
     911             : }
     912             : 
     913             : /************************************************************************/
     914             : /*                            Identify()                                */
     915             : /************************************************************************/
     916             : 
     917       51481 : int RRASTERDataset::Identify(GDALOpenInfo *poOpenInfo)
     918             : 
     919             : {
     920       54860 :     if (poOpenInfo->nHeaderBytes < 40 || poOpenInfo->fpL == nullptr ||
     921        3379 :         !EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "grd"))
     922             :     {
     923       51285 :         return FALSE;
     924             :     }
     925             : 
     926             :     // We need to ingest enough bytes as the wkt= entry can be quite large
     927         196 :     if (poOpenInfo->nHeaderBytes <= 1024)
     928         147 :         poOpenInfo->TryToIngest(4096);
     929             : 
     930         190 :     if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
     931         171 :                "ncols") == nullptr ||
     932         171 :         strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
     933         171 :                "nrows") == nullptr ||
     934         171 :         strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
     935         171 :                "xmin") == nullptr ||
     936         171 :         strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
     937         171 :                "ymin") == nullptr ||
     938         171 :         strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
     939         171 :                "xmax") == nullptr ||
     940         171 :         strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
     941         171 :                "ymax") == nullptr ||
     942         171 :         strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
     943             :                "datatype") == nullptr)
     944             :     {
     945          19 :         return FALSE;
     946             :     }
     947             : 
     948         171 :     return TRUE;
     949             : }
     950             : 
     951             : /************************************************************************/
     952             : /*                          ComputeSpacing()                            */
     953             : /************************************************************************/
     954             : 
     955         145 : bool RRASTERDataset::ComputeSpacings(const CPLString &osBandOrder, int nCols,
     956             :                                      int nRows, int l_nBands, GDALDataType eDT,
     957             :                                      int &nPixelOffset, int &nLineOffset,
     958             :                                      vsi_l_offset &nBandOffset)
     959             : {
     960         145 :     nPixelOffset = 0;
     961         145 :     nLineOffset = 0;
     962         145 :     nBandOffset = 0;
     963         145 :     const int nPixelSize = GDALGetDataTypeSizeBytes(eDT);
     964         145 :     if (l_nBands == 1 || EQUAL(osBandOrder, "BIL"))
     965             :     {
     966         139 :         nPixelOffset = nPixelSize;
     967         139 :         if (l_nBands != 0 && nPixelSize != 0 &&
     968         139 :             nCols > INT_MAX / (l_nBands * nPixelSize))
     969             :         {
     970           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Too many columns");
     971           0 :             return false;
     972             :         }
     973         139 :         nLineOffset = nPixelSize * nCols * l_nBands;
     974         139 :         nBandOffset = static_cast<vsi_l_offset>(nPixelSize) * nCols;
     975             :     }
     976           6 :     else if (EQUAL(osBandOrder, "BIP"))
     977             :     {
     978           3 :         if (l_nBands != 0 && nPixelSize != 0 &&
     979           3 :             nCols > INT_MAX / (l_nBands * nPixelSize))
     980             :         {
     981           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Too many columns");
     982           0 :             return false;
     983             :         }
     984           3 :         nPixelOffset = nPixelSize * l_nBands;
     985           3 :         nLineOffset = nPixelSize * nCols * l_nBands;
     986           3 :         nBandOffset = nPixelSize;
     987             :     }
     988           3 :     else if (EQUAL(osBandOrder, "BSQ"))
     989             :     {
     990           3 :         if (nPixelSize != 0 && nCols > INT_MAX / nPixelSize)
     991             :         {
     992           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Too many columns");
     993           0 :             return false;
     994             :         }
     995           3 :         nPixelOffset = nPixelSize;
     996           3 :         nLineOffset = nPixelSize * nCols;
     997           3 :         nBandOffset = static_cast<vsi_l_offset>(nLineOffset) * nRows;
     998             :     }
     999           0 :     else if (l_nBands > 1)
    1000             :     {
    1001           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Unknown bandorder");
    1002           0 :         return false;
    1003             :     }
    1004         145 :     return true;
    1005             : }
    1006             : 
    1007             : /************************************************************************/
    1008             : /*                            CastToFloat()                             */
    1009             : /************************************************************************/
    1010             : 
    1011           0 : static float CastToFloat(double dfVal)
    1012             : {
    1013           0 :     if (std::isinf(dfVal) || std::isnan(dfVal) ||
    1014           0 :         (dfVal >= -std::numeric_limits<float>::max() &&
    1015           0 :          dfVal <= std::numeric_limits<float>::max()))
    1016             :     {
    1017           0 :         return static_cast<float>(dfVal);
    1018             :     }
    1019           0 :     return std::numeric_limits<float>::quiet_NaN();
    1020             : }
    1021             : 
    1022             : /************************************************************************/
    1023             : /*                                Open()                                */
    1024             : /************************************************************************/
    1025             : 
    1026          83 : GDALDataset *RRASTERDataset::Open(GDALOpenInfo *poOpenInfo)
    1027             : {
    1028          83 :     if (!Identify(poOpenInfo))
    1029           0 :         return nullptr;
    1030             : 
    1031         166 :     auto poDS = std::make_unique<RRASTERDataset>();
    1032             : 
    1033          83 :     const char *pszLine = nullptr;
    1034          83 :     int nRows = 0;
    1035          83 :     int nCols = 0;
    1036          83 :     double dfXMin = 0.0;
    1037          83 :     double dfYMin = 0.0;
    1038          83 :     double dfXMax = 0.0;
    1039          83 :     double dfYMax = 0.0;
    1040          83 :     int l_nBands = 1;
    1041         166 :     CPLString osDataType;
    1042         166 :     CPLString osProjection;
    1043         166 :     CPLString osWkt;
    1044         166 :     CPLString osByteOrder;
    1045         166 :     CPLString osNoDataValue("NA");
    1046         166 :     CPLString osMinValue;
    1047         166 :     CPLString osMaxValue;
    1048         166 :     CPLString osLayerName;
    1049         166 :     CPLString osRatNames;
    1050         166 :     CPLString osRatTypes;
    1051         166 :     CPLString osRatValues;
    1052          83 :     bool bInLegend = false;
    1053          83 :     VSIRewindL(poOpenInfo->fpL);
    1054        1574 :     while ((pszLine = CPLReadLine2L(poOpenInfo->fpL, 1024 * 1024, nullptr)) !=
    1055             :            nullptr)
    1056             :     {
    1057        1491 :         if (pszLine[0] == '[')
    1058             :         {
    1059         273 :             bInLegend = EQUAL(pszLine, "[legend]");
    1060         273 :             continue;
    1061             :         }
    1062        1218 :         if (bInLegend)
    1063             :         {
    1064           6 :             poDS->m_osLegend += pszLine;
    1065           6 :             poDS->m_osLegend += "\n";
    1066             :         }
    1067        1218 :         char *pszKey = nullptr;
    1068        1218 :         const char *pszValue = CPLParseNameValue(pszLine, &pszKey);
    1069        1218 :         if (pszKey && pszValue)
    1070             :         {
    1071        1218 :             if (EQUAL(pszKey, "creator"))
    1072          12 :                 poDS->m_osCreator = pszValue;
    1073        1218 :             if (EQUAL(pszKey, "created"))
    1074          12 :                 poDS->m_osCreated = pszValue;
    1075        1206 :             else if (EQUAL(pszKey, "ncols"))
    1076          83 :                 nCols = atoi(pszValue);
    1077        1123 :             else if (EQUAL(pszKey, "nrows"))
    1078          83 :                 nRows = atoi(pszValue);
    1079        1040 :             else if (EQUAL(pszKey, "xmin"))
    1080          83 :                 dfXMin = CPLAtof(pszValue);
    1081         957 :             else if (EQUAL(pszKey, "ymin"))
    1082          83 :                 dfYMin = CPLAtof(pszValue);
    1083         874 :             else if (EQUAL(pszKey, "xmax"))
    1084          83 :                 dfXMax = CPLAtof(pszValue);
    1085         791 :             else if (EQUAL(pszKey, "ymax"))
    1086          83 :                 dfYMax = CPLAtof(pszValue);
    1087         708 :             else if (EQUAL(pszKey, "projection"))
    1088          79 :                 osProjection = pszValue;
    1089         629 :             else if (EQUAL(pszKey, "wkt"))
    1090          66 :                 osWkt = pszValue;
    1091         563 :             else if (EQUAL(pszKey, "nbands"))
    1092          83 :                 l_nBands = atoi(pszValue);
    1093         480 :             else if (EQUAL(pszKey, "bandorder"))
    1094          34 :                 poDS->m_osBandOrder = pszValue;
    1095         446 :             else if (EQUAL(pszKey, "datatype"))
    1096          83 :                 osDataType = pszValue;
    1097         363 :             else if (EQUAL(pszKey, "byteorder"))
    1098          83 :                 osByteOrder = pszValue;
    1099         280 :             else if (EQUAL(pszKey, "nodatavalue"))
    1100          12 :                 osNoDataValue = pszValue;
    1101         268 :             else if (EQUAL(pszKey, "minvalue"))
    1102          49 :                 osMinValue = pszValue;
    1103         219 :             else if (EQUAL(pszKey, "maxvalue"))
    1104          49 :                 osMaxValue = pszValue;
    1105         170 :             else if (EQUAL(pszKey, "ratnames"))
    1106          12 :                 osRatNames = pszValue;
    1107         158 :             else if (EQUAL(pszKey, "rattypes"))
    1108          12 :                 osRatTypes = pszValue;
    1109         146 :             else if (EQUAL(pszKey, "ratvalues"))
    1110          12 :                 osRatValues = pszValue;
    1111         134 :             else if (EQUAL(pszKey, "layername"))
    1112          33 :                 osLayerName = pszValue;
    1113             :         }
    1114        1218 :         CPLFree(pszKey);
    1115             :     }
    1116          83 :     if (!GDALCheckDatasetDimensions(nCols, nRows))
    1117           0 :         return nullptr;
    1118          83 :     if (!GDALCheckBandCount(l_nBands, FALSE))
    1119           0 :         return nullptr;
    1120             : 
    1121          83 :     GDALDataType eDT = GDT_Unknown;
    1122          83 :     if (EQUAL(osDataType, "LOG1S"))
    1123           0 :         eDT = GDT_Byte;  // mapping TBC
    1124          83 :     else if (EQUAL(osDataType, "INT1S"))
    1125           6 :         eDT = GDT_Int8;
    1126          77 :     else if (EQUAL(osDataType, "INT2S"))
    1127           5 :         eDT = GDT_Int16;
    1128          72 :     else if (EQUAL(osDataType, "INT4S"))
    1129           5 :         eDT = GDT_Int32;
    1130             :     // else if( EQUAL(osDataType, "INT8S") )
    1131             :     //     eDT = GDT_UInt64; // unhandled
    1132          67 :     else if (EQUAL(osDataType, "INT1U"))
    1133          48 :         eDT = GDT_Byte;
    1134          19 :     else if (EQUAL(osDataType, "INT2U"))
    1135           5 :         eDT = GDT_UInt16;
    1136          14 :     else if (EQUAL(osDataType, "INT4U"))  // Not documented
    1137           5 :         eDT = GDT_UInt32;
    1138           9 :     else if (EQUAL(osDataType, "FLT4S"))
    1139           5 :         eDT = GDT_Float32;
    1140           4 :     else if (EQUAL(osDataType, "FLT8S"))
    1141           4 :         eDT = GDT_Float64;
    1142             :     else
    1143             :     {
    1144           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Unhandled datatype=%s",
    1145             :                  osDataType.c_str());
    1146           0 :         return nullptr;
    1147             :     }
    1148          83 :     if (l_nBands > 1 && poDS->m_osBandOrder.empty())
    1149             :     {
    1150           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Missing 'bandorder'");
    1151           0 :         return nullptr;
    1152             :     }
    1153             : 
    1154          83 :     bool bNativeOrder = true;
    1155          83 :     if (EQUAL(osByteOrder, "little"))
    1156             :     {
    1157          83 :         bNativeOrder = CPL_TO_BOOL(CPL_IS_LSB);
    1158             :     }
    1159           0 :     else if (EQUAL(osByteOrder, "big"))
    1160             :     {
    1161           0 :         bNativeOrder = CPL_TO_BOOL(!CPL_IS_LSB);
    1162             :     }
    1163           0 :     else if (!EQUAL(osByteOrder, ""))
    1164             :     {
    1165           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    1166             :                  "Unhandled byteorder=%s. Assuming native order",
    1167             :                  osByteOrder.c_str());
    1168             :     }
    1169             : 
    1170          83 :     int nPixelOffset = 0;
    1171          83 :     int nLineOffset = 0;
    1172          83 :     vsi_l_offset nBandOffset = 0;
    1173          83 :     if (!ComputeSpacings(poDS->m_osBandOrder, nCols, nRows, l_nBands, eDT,
    1174             :                          nPixelOffset, nLineOffset, nBandOffset))
    1175             :     {
    1176           0 :         return nullptr;
    1177             :     }
    1178             : 
    1179         166 :     CPLString osDirname(CPLGetDirname(poOpenInfo->pszFilename));
    1180         166 :     CPLString osBasename(CPLGetBasename(poOpenInfo->pszFilename));
    1181         166 :     CPLString osGRDExtension(CPLGetExtension(poOpenInfo->pszFilename));
    1182         166 :     CPLString osGRIExtension((osGRDExtension[0] == 'g') ? "gri" : "GRI");
    1183          83 :     char **papszSiblings = poOpenInfo->GetSiblingFiles();
    1184          83 :     if (papszSiblings)
    1185             :     {
    1186             :         int iFile =
    1187          83 :             CSLFindString(papszSiblings,
    1188             :                           CPLFormFilename(nullptr, osBasename, osGRIExtension));
    1189          83 :         if (iFile < 0)
    1190           0 :             return nullptr;
    1191          83 :         poDS->m_osGriFilename =
    1192         166 :             CPLFormFilename(osDirname, papszSiblings[iFile], nullptr);
    1193             :     }
    1194             :     else
    1195             :     {
    1196           0 :         poDS->m_osGriFilename =
    1197           0 :             CPLFormFilename(osDirname, osBasename, osGRIExtension);
    1198             :     }
    1199             : 
    1200             :     VSILFILE *fpImage =
    1201          83 :         VSIFOpenL(poDS->m_osGriFilename,
    1202          83 :                   (poOpenInfo->eAccess == GA_Update) ? "rb+" : "rb");
    1203          83 :     if (fpImage == nullptr)
    1204             :     {
    1205           0 :         CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s",
    1206           0 :                  poDS->m_osGriFilename.c_str());
    1207           0 :         return nullptr;
    1208             :     }
    1209             : 
    1210          83 :     if (!RAWDatasetCheckMemoryUsage(nCols, nRows, l_nBands,
    1211             :                                     GDALGetDataTypeSizeBytes(eDT), nPixelOffset,
    1212             :                                     nLineOffset, 0, nBandOffset, fpImage))
    1213             :     {
    1214           0 :         VSIFCloseL(fpImage);
    1215           0 :         return nullptr;
    1216             :     }
    1217             : 
    1218          83 :     poDS->eAccess = poOpenInfo->eAccess;
    1219          83 :     poDS->nRasterXSize = nCols;
    1220          83 :     poDS->nRasterYSize = nRows;
    1221          83 :     poDS->m_bGeoTransformValid = true;
    1222          83 :     poDS->m_adfGeoTransform[0] = dfXMin;
    1223          83 :     poDS->m_adfGeoTransform[1] = (dfXMax - dfXMin) / nCols;
    1224          83 :     poDS->m_adfGeoTransform[2] = 0.0;
    1225          83 :     poDS->m_adfGeoTransform[3] = dfYMax;
    1226          83 :     poDS->m_adfGeoTransform[4] = 0.0;
    1227          83 :     poDS->m_adfGeoTransform[5] = -(dfYMax - dfYMin) / nRows;
    1228          83 :     poDS->m_fpImage = fpImage;
    1229          83 :     poDS->m_bNativeOrder = bNativeOrder;
    1230             : 
    1231          83 :     if (osWkt.empty())
    1232             :     {
    1233          17 :         if (!osProjection.empty())
    1234             :         {
    1235          13 :             poDS->m_oSRS.importFromProj4(osProjection.c_str());
    1236             :         }
    1237             :     }
    1238             :     else
    1239             :     {
    1240          66 :         poDS->m_oSRS.importFromWkt(osWkt.c_str());
    1241             :     }
    1242             : 
    1243          83 :     if (!poDS->m_osCreator.empty())
    1244          12 :         poDS->GDALDataset::SetMetadataItem("CREATOR", poDS->m_osCreator);
    1245             : 
    1246          83 :     if (!poDS->m_osCreated.empty())
    1247          12 :         poDS->GDALDataset::SetMetadataItem("CREATED", poDS->m_osCreated);
    1248             : 
    1249             :     // Instantiate RAT
    1250          83 :     if (!osRatNames.empty() && !osRatTypes.empty() && !osRatValues.empty())
    1251             :     {
    1252          24 :         CPLStringList aosRatNames(CSLTokenizeString2(osRatNames, ":", 0));
    1253          24 :         CPLStringList aosRatTypes(CSLTokenizeString2(osRatTypes, ":", 0));
    1254          24 :         CPLStringList aosRatValues(CSLTokenizeString2(osRatValues, ":", 0));
    1255          12 :         if (aosRatNames.size() >= 1 &&
    1256          24 :             aosRatNames.size() == aosRatTypes.size() &&
    1257          12 :             (aosRatValues.size() % aosRatNames.size()) == 0)
    1258             :         {
    1259          12 :             bool bIsCompatibleOfCT = false;
    1260          12 :             const int nValues = aosRatValues.size() / aosRatNames.size();
    1261          20 :             if ((aosRatNames.size() == 4 || aosRatNames.size() == 5) &&
    1262           8 :                 EQUAL(aosRatNames[1], "red") &&
    1263           8 :                 EQUAL(aosRatNames[2], "green") &&
    1264           8 :                 EQUAL(aosRatNames[3], "blue") &&
    1265           8 :                 (aosRatNames.size() == 4 || EQUAL(aosRatNames[4], "alpha")) &&
    1266           8 :                 EQUAL(aosRatTypes[0], "integer") &&
    1267           8 :                 EQUAL(aosRatTypes[1], "integer") &&
    1268           8 :                 EQUAL(aosRatTypes[2], "integer") &&
    1269          32 :                 EQUAL(aosRatTypes[3], "integer") &&
    1270           8 :                 (aosRatTypes.size() == 4 || EQUAL(aosRatTypes[4], "integer")))
    1271             :             {
    1272           8 :                 bIsCompatibleOfCT = true;
    1273           8 :                 poDS->m_poCT.reset(new GDALColorTable());
    1274          24 :                 for (int i = 0; i < nValues; i++)
    1275             :                 {
    1276          16 :                     const int nIndex = atoi(aosRatValues[i]);
    1277          16 :                     if (nIndex >= 0 && nIndex < 65536)
    1278             :                     {
    1279          16 :                         const int nRed = atoi(aosRatValues[nValues + i]);
    1280          16 :                         const int nGreen = atoi(aosRatValues[2 * nValues + i]);
    1281          16 :                         const int nBlue = atoi(aosRatValues[3 * nValues + i]);
    1282             :                         const int nAlpha =
    1283          16 :                             aosRatTypes.size() == 4
    1284          16 :                                 ? 255
    1285           8 :                                 : atoi(aosRatValues[4 * nValues + i]);
    1286             :                         const GDALColorEntry oEntry = {
    1287             :                             static_cast<short>(nRed),
    1288             :                             static_cast<short>(nGreen),
    1289             :                             static_cast<short>(nBlue),
    1290          16 :                             static_cast<short>(nAlpha)};
    1291             : 
    1292          16 :                         poDS->m_poCT->SetColorEntry(nIndex, &oEntry);
    1293             :                     }
    1294             :                     else
    1295             :                     {
    1296           0 :                         bIsCompatibleOfCT = false;
    1297           0 :                         poDS->m_poCT.reset();
    1298           0 :                         break;
    1299             :                     }
    1300             :                 }
    1301             :             }
    1302             : 
    1303             :             // cppcheck-suppress knownConditionTrueFalse
    1304          12 :             if (!bIsCompatibleOfCT)
    1305             :             {
    1306           4 :                 poDS->m_poRAT.reset(new GDALDefaultRasterAttributeTable());
    1307          44 :                 for (int i = 0; i < aosRatNames.size(); i++)
    1308             :                 {
    1309         120 :                     poDS->m_poRAT->CreateColumn(
    1310          40 :                         aosRatNames[i],
    1311          40 :                         EQUAL(aosRatTypes[i], "integer")   ? GFT_Integer
    1312          12 :                         : EQUAL(aosRatTypes[i], "numeric") ? GFT_Real
    1313             :                                                            : GFT_String,
    1314          40 :                         EQUAL(aosRatNames[i], "red")          ? GFU_Red
    1315          68 :                         : EQUAL(aosRatNames[i], "green")      ? GFU_Green
    1316          60 :                         : EQUAL(aosRatNames[i], "blue")       ? GFU_Blue
    1317          52 :                         : EQUAL(aosRatNames[i], "alpha")      ? GFU_Alpha
    1318          44 :                         : EQUAL(aosRatNames[i], "name")       ? GFU_Name
    1319          20 :                         : EQUAL(aosRatNames[i], "pixelcount") ? GFU_PixelCount
    1320          40 :                                                               : GFU_Generic);
    1321             :                 }
    1322          12 :                 for (int i = 0; i < nValues; i++)
    1323             :                 {
    1324          88 :                     for (int j = 0; j < aosRatTypes.size(); j++)
    1325             :                     {
    1326          80 :                         if (poDS->m_poRAT->GetTypeOfCol(j) == GFT_Integer)
    1327             :                         {
    1328          56 :                             poDS->m_poRAT->SetValue(
    1329          56 :                                 i, j, atoi(aosRatValues[j * nValues + i]));
    1330             :                         }
    1331          24 :                         else if (poDS->m_poRAT->GetTypeOfCol(j) == GFT_Real)
    1332             :                         {
    1333          16 :                             poDS->m_poRAT->SetValue(
    1334           8 :                                 i, j, CPLAtof(aosRatValues[j * nValues + i]));
    1335             :                         }
    1336             :                         else
    1337             :                         {
    1338          16 :                             poDS->m_poRAT->SetValue(
    1339          16 :                                 i, j, aosRatValues[j * nValues + i]);
    1340             :                         }
    1341             :                     }
    1342             :                 }
    1343             :             }
    1344             :         }
    1345             :     }
    1346             : 
    1347         166 :     CPLStringList aosMinValues(CSLTokenizeString2(osMinValue, ":", 0));
    1348         166 :     CPLStringList aosMaxValues(CSLTokenizeString2(osMaxValue, ":", 0));
    1349             : 
    1350         166 :     CPLStringList aosLayerNames(CSLTokenizeString2(osLayerName, ":", 0));
    1351         235 :     for (int i = 1; i <= l_nBands; i++)
    1352             :     {
    1353             :         auto poBand = std::make_unique<RRASTERRasterBand>(
    1354         152 :             poDS.get(), i, fpImage, nBandOffset * (i - 1), nPixelOffset,
    1355         152 :             nLineOffset, eDT, bNativeOrder);
    1356         152 :         if (!poBand->IsValid())
    1357             :         {
    1358           0 :             return nullptr;
    1359             :         }
    1360         152 :         if (!osNoDataValue.empty() && !EQUAL(osNoDataValue, "NA"))
    1361             :         {
    1362          10 :             double dfNoDataValue = CPLAtof(osNoDataValue);
    1363          10 :             if (eDT == GDT_Float32)
    1364           0 :                 dfNoDataValue = CastToFloat(dfNoDataValue);
    1365          10 :             poBand->m_bHasNoDataValue = true;
    1366          10 :             poBand->m_dfNoDataValue = dfNoDataValue;
    1367             :         }
    1368         225 :         if (i - 1 < static_cast<int>(aosMinValues.size()) &&
    1369          73 :             i - 1 < static_cast<int>(aosMaxValues.size()))
    1370             :         {
    1371         146 :             poBand->SetMinMax(CPLAtof(aosMinValues[i - 1]),
    1372          73 :                               CPLAtof(aosMaxValues[i - 1]));
    1373             :         }
    1374         152 :         if (i - 1 < static_cast<int>(aosLayerNames.size()))
    1375             :         {
    1376         156 :             const CPLString osName(aosLayerNames[i - 1]);
    1377          78 :             poBand->GDALRasterBand::SetDescription(osName);
    1378          78 :             if (EQUAL(osName, "red"))
    1379          15 :                 poBand->SetColorInterpretation(GCI_RedBand);
    1380          63 :             else if (EQUAL(osName, "green"))
    1381          15 :                 poBand->SetColorInterpretation(GCI_GreenBand);
    1382          48 :             else if (EQUAL(osName, "blue"))
    1383          15 :                 poBand->SetColorInterpretation(GCI_BlueBand);
    1384          33 :             else if (EQUAL(osName, "alpha"))
    1385          15 :                 poBand->SetColorInterpretation(GCI_AlphaBand);
    1386             :         }
    1387         152 :         poBand->m_poRAT = poDS->m_poRAT;
    1388         152 :         poBand->m_poCT = poDS->m_poCT;
    1389         152 :         if (poBand->m_poCT)
    1390           8 :             poBand->SetColorInterpretation(GCI_PaletteIndex);
    1391         152 :         poDS->SetBand(i, std::move(poBand));
    1392             :     }
    1393             : 
    1394          83 :     return poDS.release();
    1395             : }
    1396             : 
    1397             : /************************************************************************/
    1398             : /*                               Create()                               */
    1399             : /************************************************************************/
    1400             : 
    1401          79 : GDALDataset *RRASTERDataset::Create(const char *pszFilename, int nXSize,
    1402             :                                     int nYSize, int nBandsIn,
    1403             :                                     GDALDataType eType, char **papszOptions)
    1404             : 
    1405             : {
    1406             :     // Verify input options.
    1407          79 :     if (nBandsIn <= 0)
    1408             :     {
    1409           1 :         CPLError(CE_Failure, CPLE_NotSupported,
    1410             :                  "RRASTER driver does not support %d bands.", nBandsIn);
    1411           1 :         return nullptr;
    1412             :     }
    1413             : 
    1414          78 :     if (eType != GDT_Byte && eType != GDT_Int8 && eType != GDT_UInt16 &&
    1415          32 :         eType != GDT_Int16 && eType != GDT_Int32 && eType != GDT_UInt32 &&
    1416          20 :         eType != GDT_Float32 && eType != GDT_Float64)
    1417             :     {
    1418          16 :         CPLError(CE_Failure, CPLE_NotSupported, "Unsupported data type (%s).",
    1419             :                  GDALGetDataTypeName(eType));
    1420          16 :         return nullptr;
    1421             :     }
    1422             : 
    1423         124 :     CPLString osGRDExtension(CPLGetExtension(pszFilename));
    1424          62 :     if (!EQUAL(osGRDExtension, "grd"))
    1425             :     {
    1426           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    1427             :                  "RRASTER driver only supports grd extension");
    1428           0 :         return nullptr;
    1429             :     }
    1430             : 
    1431          62 :     int nPixelOffset = 0;
    1432          62 :     int nLineOffset = 0;
    1433          62 :     vsi_l_offset nBandOffset = 0;
    1434             :     CPLString osBandOrder(
    1435         124 :         CSLFetchNameValueDef(papszOptions, "INTERLEAVE", "BIL"));
    1436          62 :     if (!ComputeSpacings(osBandOrder, nXSize, nYSize, nBandsIn, eType,
    1437             :                          nPixelOffset, nLineOffset, nBandOffset))
    1438             :     {
    1439           0 :         return nullptr;
    1440             :     }
    1441             : 
    1442          62 :     const std::string osGRIExtension((osGRDExtension[0] == 'g') ? "gri"
    1443         186 :                                                                 : "GRI");
    1444             :     const std::string osGriFilename(
    1445         124 :         CPLResetExtension(pszFilename, osGRIExtension.c_str()));
    1446             : 
    1447             :     // Try to create the file.
    1448          62 :     VSILFILE *fpImage = VSIFOpenL(osGriFilename.c_str(), "wb+");
    1449             : 
    1450          62 :     if (fpImage == nullptr)
    1451             :     {
    1452           3 :         CPLError(CE_Failure, CPLE_OpenFailed,
    1453             :                  "Attempt to create file `%s' failed.", osGriFilename.c_str());
    1454           3 :         return nullptr;
    1455             :     }
    1456             : 
    1457          59 :     RRASTERDataset *poDS = new RRASTERDataset;
    1458          59 :     poDS->eAccess = GA_Update;
    1459          59 :     poDS->m_bHeaderDirty = true;
    1460          59 :     poDS->m_osGriFilename = osGriFilename;
    1461          59 :     poDS->nRasterXSize = nXSize;
    1462          59 :     poDS->nRasterYSize = nYSize;
    1463          59 :     poDS->m_fpImage = fpImage;
    1464          59 :     poDS->m_bNativeOrder = true;
    1465          59 :     poDS->m_osBandOrder = osBandOrder.toupper();
    1466          59 :     poDS->m_bInitRaster = CPLFetchBool(papszOptions, "@INIT_RASTER", true);
    1467             : 
    1468          59 :     const char *pszPixelType = CSLFetchNameValue(papszOptions, "PIXELTYPE");
    1469          60 :     const bool bByteSigned = (eType == GDT_Byte && pszPixelType &&
    1470           1 :                               EQUAL(pszPixelType, "SIGNEDBYTE"));
    1471          59 :     if (bByteSigned)
    1472           1 :         poDS->m_bSignedByte = true;
    1473             : 
    1474         167 :     for (int i = 1; i <= nBandsIn; i++)
    1475             :     {
    1476             :         RRASTERRasterBand *poBand =
    1477         108 :             new RRASTERRasterBand(poDS, i, fpImage, nBandOffset * (i - 1),
    1478         108 :                                   nPixelOffset, nLineOffset, eType, true);
    1479         108 :         poDS->SetBand(i, poBand);
    1480             :     }
    1481             : 
    1482          59 :     return poDS;
    1483             : }
    1484             : 
    1485             : /************************************************************************/
    1486             : /*                             CreateCopy()                             */
    1487             : /************************************************************************/
    1488             : 
    1489          46 : GDALDataset *RRASTERDataset::CreateCopy(const char *pszFilename,
    1490             :                                         GDALDataset *poSrcDS, int bStrict,
    1491             :                                         char **papszOptions,
    1492             :                                         GDALProgressFunc pfnProgress,
    1493             :                                         void *pProgressData)
    1494             : 
    1495             : {
    1496             :     // Proceed with normal copying using the default createcopy  operators.
    1497             :     GDALDriver *poDriver =
    1498          46 :         reinterpret_cast<GDALDriver *>(GDALGetDriverByName("RRASTER"));
    1499             : 
    1500          46 :     char **papszAdjustedOptions = CSLDuplicate(papszOptions);
    1501             :     papszAdjustedOptions =
    1502          46 :         CSLSetNameValue(papszAdjustedOptions, "@INIT_RASTER", "NO");
    1503          46 :     GDALDataset *poOutDS = poDriver->DefaultCreateCopy(
    1504             :         pszFilename, poSrcDS, bStrict, papszAdjustedOptions, pfnProgress,
    1505             :         pProgressData);
    1506          46 :     CSLDestroy(papszAdjustedOptions);
    1507             : 
    1508          46 :     if (poOutDS != nullptr)
    1509          36 :         poOutDS->FlushCache(false);
    1510             : 
    1511          46 :     return poOutDS;
    1512             : }
    1513             : 
    1514             : /************************************************************************/
    1515             : /*                   GDALRegister_RRASTER()                             */
    1516             : /************************************************************************/
    1517             : 
    1518        1595 : void GDALRegister_RRASTER()
    1519             : 
    1520             : {
    1521        1595 :     if (GDALGetDriverByName("RRASTER") != nullptr)
    1522         302 :         return;
    1523             : 
    1524        1293 :     GDALDriver *poDriver = new GDALDriver();
    1525             : 
    1526        1293 :     poDriver->SetDescription("RRASTER");
    1527        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
    1528        1293 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "grd");
    1529        1293 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "R Raster");
    1530        1293 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
    1531        1293 :                               "drivers/raster/rraster.html");
    1532        1293 :     poDriver->SetMetadataItem(
    1533             :         GDAL_DMD_CREATIONDATATYPES,
    1534        1293 :         "Byte Int8 Int16 UInt16 Int32 UInt32 Float32 Float64");
    1535             : 
    1536        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
    1537             : 
    1538        1293 :     poDriver->SetMetadataItem(
    1539             :         GDAL_DMD_CREATIONOPTIONLIST,
    1540             :         "<CreationOptionList>"
    1541             :         "   <Option name='PIXELTYPE' type='string' description='(deprecated, "
    1542             :         "use Int8) "
    1543             :         "By setting this to SIGNEDBYTE, a new Byte file can be forced to be "
    1544             :         "written "
    1545             :         "as signed byte'/>"
    1546             :         "   <Option name='INTERLEAVE' type='string-select' default='BIL'>"
    1547             :         "       <Value>BIP</Value>"
    1548             :         "       <Value>BIL</Value>"
    1549             :         "       <Value>BSQ</Value>"
    1550             :         "   </Option>"
    1551        1293 :         "</CreationOptionList>");
    1552             : 
    1553        1293 :     poDriver->pfnOpen = RRASTERDataset::Open;
    1554        1293 :     poDriver->pfnIdentify = RRASTERDataset::Identify;
    1555        1293 :     poDriver->pfnCreate = RRASTERDataset::Create;
    1556        1293 :     poDriver->pfnCreateCopy = RRASTERDataset::CreateCopy;
    1557             : 
    1558        1293 :     GetGDALDriverManager()->RegisterDriver(poDriver);
    1559             : }

Generated by: LCOV version 1.14