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

Generated by: LCOV version 1.14