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

Generated by: LCOV version 1.14