• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15885686134

25 Jun 2025 07:44PM UTC coverage: 71.084%. Remained the same
15885686134

push

github

rouault
gdal_priv.h: fix C++11 compatibility

573814 of 807237 relevant lines covered (71.08%)

250621.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.76
/frmts/raw/rrasterdataset.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  Implements R Raster Format.
5
 * Author:   Even Rouault, <even dot rouault at spatialys dot com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2016, Even Rouault, <even dot rouault at spatialys dot com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12

13
#include "cpl_port.h"
14

15
#include "gdal_frmts.h"
16
#include "gdal_rat.h"
17
#include "gdal_priv.h"
18

19
#include "rawdataset.h"
20
#include "ogr_spatialref.h"
21

22
#include <algorithm>
23
#include <cmath>
24
#include <limits>
25
#include <memory>
26

27
/************************************************************************/
28
/* ==================================================================== */
29
/*                           RRASTERDataset                             */
30
/* ==================================================================== */
31
/************************************************************************/
32

33
class RRASTERDataset final : public RawDataset
34
{
35
    bool m_bHeaderDirty = false;
36
    CPLString m_osGriFilename{};
37
    bool m_bGeoTransformValid = false;
38
    GDALGeoTransform m_gt{};
39
    VSILFILE *m_fpImage = nullptr;
40
    OGRSpatialReference m_oSRS{};
41
    std::shared_ptr<GDALRasterAttributeTable> m_poRAT{};
42
    std::shared_ptr<GDALColorTable> m_poCT{};
43
    bool m_bNativeOrder = true;
44
    CPLString m_osCreator{};
45
    CPLString m_osCreated{};
46
    CPLString m_osBandOrder{};
47
    CPLString m_osLegend{};
48
    bool m_bInitRaster = false;
49
    bool m_bSignedByte = false;
50

51
    static bool ComputeSpacings(const CPLString &osBandOrder, int nCols,
52
                                int nRows, int l_nBands, GDALDataType eDT,
53
                                int &nPixelOffset, int &nLineOffset,
54
                                vsi_l_offset &nBandOffset);
55
    void RewriteHeader();
56

57
    CPL_DISALLOW_COPY_ASSIGN(RRASTERDataset)
58

59
    CPLErr Close() override;
60

61
  public:
62
    RRASTERDataset();
63
    ~RRASTERDataset() override;
64

65
    char **GetFileList() override;
66

67
    static GDALDataset *Open(GDALOpenInfo *);
68
    static int Identify(GDALOpenInfo *);
69
    static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
70
                               int nBandsIn, GDALDataType eType,
71
                               char **papszOptions);
72
    static GDALDataset *CreateCopy(const char *pszFilename,
73
                                   GDALDataset *poSrcDS, int bStrict,
74
                                   char **papszOptions,
75
                                   GDALProgressFunc pfnProgress,
76
                                   void *pProgressData);
77

78
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
79
    CPLErr SetGeoTransform(const GDALGeoTransform &gt) override;
80
    const OGRSpatialReference *GetSpatialRef() const override;
81
    CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
82

83
    CPLErr SetMetadata(char **papszMetadata,
84
                       const char *pszDomain = "") override;
85
    CPLErr SetMetadataItem(const char *pszName, const char *pszValue,
86
                           const char *pszDomain = "") override;
87

88
    void SetHeaderDirty()
179✔
89
    {
90
        m_bHeaderDirty = true;
179✔
91
    }
179✔
92

93
    void InitImageIfNeeded();
94

95
    inline bool IsSignedByte() const
211✔
96
    {
97
        return m_bSignedByte;
211✔
98
    }
99
};
100

101
/************************************************************************/
102
/* ==================================================================== */
103
/*                         RRASTERRasterBand                            */
104
/* ==================================================================== */
105
/************************************************************************/
106

107
class RRASTERRasterBand final : public RawRasterBand
108
{
109
    friend class RRASTERDataset;
110

111
    bool m_bHasNoDataValue = false;
112
    double m_dfNoDataValue = 0.0;
113
    double m_dfMin = std::numeric_limits<double>::infinity();
114
    double m_dfMax = -std::numeric_limits<double>::infinity();
115
    std::shared_ptr<GDALRasterAttributeTable> m_poRAT{};
116
    std::shared_ptr<GDALColorTable> m_poCT{};
117

118
    CPL_DISALLOW_COPY_ASSIGN(RRASTERRasterBand)
119

120
  public:
121
    RRASTERRasterBand(GDALDataset *poDS, int nBand, VSILFILE *fpRaw,
122
                      vsi_l_offset nImgOffset, int nPixelOffset,
123
                      int nLineOffset, GDALDataType eDataType,
124
                      int bNativeOrder);
125

126
    void SetMinMax(double dfMin, double dfMax);
127
    double GetMinimum(int *pbSuccess = nullptr) override;
128
    double GetMaximum(int *pbSuccess = nullptr) override;
129

130
    double GetNoDataValue(int *pbSuccess = nullptr) override;
131
    CPLErr SetNoDataValue(double dfNoData) override;
132

133
    GDALColorTable *GetColorTable() override;
134
    CPLErr SetColorTable(GDALColorTable *poNewCT) override;
135

136
    GDALRasterAttributeTable *GetDefaultRAT() override;
137
    CPLErr SetDefaultRAT(const GDALRasterAttributeTable *poRAT) override;
138

139
    void SetDescription(const char *pszDesc) override;
140

141
  protected:
142
    CPLErr IWriteBlock(int, int, void *) override;
143
    CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
144
                     GDALDataType, GSpacing nPixelSpace, GSpacing nLineSpace,
145
                     GDALRasterIOExtraArg *psExtraArg) override;
146
};
147

148
/************************************************************************/
149
/*                           RRASTERDataset()                           */
150
/************************************************************************/
151

152
RRASTERRasterBand::RRASTERRasterBand(GDALDataset *poDSIn, int nBandIn,
262✔
153
                                     VSILFILE *fpRawIn,
154
                                     vsi_l_offset nImgOffsetIn,
155
                                     int nPixelOffsetIn, int nLineOffsetIn,
156
                                     GDALDataType eDataTypeIn,
157
                                     int bNativeOrderIn)
262✔
158
    : RawRasterBand(poDSIn, nBandIn, fpRawIn, nImgOffsetIn, nPixelOffsetIn,
159
                    nLineOffsetIn, eDataTypeIn, bNativeOrderIn,
160
                    RawRasterBand::OwnFP::NO)
262✔
161
{
162
}
262✔
163

164
/************************************************************************/
165
/*                             SetMinMax()                              */
166
/************************************************************************/
167

168
void RRASTERRasterBand::SetMinMax(double dfMin, double dfMax)
74✔
169
{
170
    m_dfMin = dfMin;
74✔
171
    m_dfMax = dfMax;
74✔
172
}
74✔
173

174
/************************************************************************/
175
/*                            GetMinimum()                              */
176
/************************************************************************/
177

178
double RRASTERRasterBand::GetMinimum(int *pbSuccess)
29✔
179
{
180
    if (m_dfMin <= m_dfMax)
29✔
181
    {
182
        if (pbSuccess)
22✔
183
            *pbSuccess = TRUE;
22✔
184
        return m_dfMin;
22✔
185
    }
186
    return RawRasterBand::GetMinimum(pbSuccess);
7✔
187
}
188

189
/************************************************************************/
190
/*                            GetMaximum()                              */
191
/************************************************************************/
192

193
double RRASTERRasterBand::GetMaximum(int *pbSuccess)
28✔
194
{
195
    if (m_dfMin <= m_dfMax)
28✔
196
    {
197
        if (pbSuccess)
21✔
198
            *pbSuccess = TRUE;
21✔
199
        return m_dfMax;
21✔
200
    }
201
    return RawRasterBand::GetMaximum(pbSuccess);
7✔
202
}
203

204
/************************************************************************/
205
/*                           GetColorTable()                            */
206
/************************************************************************/
207

208
GDALColorTable *RRASTERRasterBand::GetColorTable()
88✔
209
{
210
    return m_poCT.get();
88✔
211
}
212

213
/************************************************************************/
214
/*                           SetColorTable()                            */
215
/************************************************************************/
216

217
CPLErr RRASTERRasterBand::SetColorTable(GDALColorTable *poNewCT)
3✔
218
{
219
    RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS);
3✔
220
    if (poGDS->GetAccess() != GA_Update)
3✔
221
        return CE_Failure;
×
222

223
    if (poNewCT == nullptr)
3✔
224
        m_poCT.reset();
1✔
225
    else
226
        m_poCT.reset(poNewCT->Clone());
2✔
227

228
    poGDS->SetHeaderDirty();
3✔
229

230
    return CE_None;
3✔
231
}
232

233
/************************************************************************/
234
/*                           GetDefaultRAT()                            */
235
/************************************************************************/
236

237
GDALRasterAttributeTable *RRASTERRasterBand::GetDefaultRAT()
112✔
238
{
239
    return m_poRAT.get();
112✔
240
}
241

242
/************************************************************************/
243
/*                            SetDefaultRAT()                           */
244
/************************************************************************/
245

246
CPLErr RRASTERRasterBand::SetDefaultRAT(const GDALRasterAttributeTable *poRAT)
2✔
247
{
248
    RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS);
2✔
249
    if (poGDS->GetAccess() != GA_Update)
2✔
250
        return CE_Failure;
×
251

252
    if (poRAT == nullptr)
2✔
253
        m_poRAT.reset();
1✔
254
    else
255
        m_poRAT.reset(poRAT->Clone());
1✔
256

257
    poGDS->SetHeaderDirty();
2✔
258

259
    return CE_None;
2✔
260
}
261

262
/************************************************************************/
263
/*                           SetDescription()                           */
264
/************************************************************************/
265

266
void RRASTERRasterBand::SetDescription(const char *pszDesc)
20✔
267
{
268
    RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS);
20✔
269
    if (poGDS->GetAccess() != GA_Update)
20✔
270
        return;
×
271

272
    GDALRasterBand::SetDescription(pszDesc);
20✔
273

274
    poGDS->SetHeaderDirty();
20✔
275
}
276

277
/************************************************************************/
278
/*                           GetNoDataValue()                           */
279
/************************************************************************/
280

281
double RRASTERRasterBand::GetNoDataValue(int *pbSuccess)
392✔
282
{
283
    if (pbSuccess)
392✔
284
        *pbSuccess = m_bHasNoDataValue;
392✔
285
    return m_dfNoDataValue;
392✔
286
}
287

288
/************************************************************************/
289
/*                           SetNoDataValue()                           */
290
/************************************************************************/
291

292
CPLErr RRASTERRasterBand::SetNoDataValue(double dfNoData)
3✔
293
{
294
    RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS);
3✔
295
    if (poGDS->GetAccess() != GA_Update)
3✔
296
        return CE_Failure;
×
297

298
    m_bHasNoDataValue = true;
3✔
299
    m_dfNoDataValue = dfNoData;
3✔
300
    poGDS->SetHeaderDirty();
3✔
301
    return CE_None;
3✔
302
}
303

304
/************************************************************************/
305
/*                             GetMinMax()                              */
306
/************************************************************************/
307

308
template <class T>
309
static void GetMinMax(const T *buffer, int nBufXSize, int nBufYSize,
211✔
310
                      GSpacing nPixelSpace, GSpacing nLineSpace,
311
                      double dfNoDataValue, double &dfMin, double &dfMax)
312
{
313
    for (int iY = 0; iY < nBufYSize; iY++)
1,091✔
314
    {
315
        for (int iX = 0; iX < nBufXSize; iX++)
42,541✔
316
        {
317
            const double dfVal = buffer[iY * nLineSpace + iX * nPixelSpace];
41,661✔
318
            if (dfVal != dfNoDataValue && !std::isnan(dfVal))
41,661✔
319
            {
320
                dfMin = std::min(dfMin, dfVal);
41,660✔
321
                dfMax = std::max(dfMax, dfVal);
41,660✔
322
            }
323
        }
324
    }
325
}
211✔
326

327
static void GetMinMax(const void *pBuffer, GDALDataType eDT, int nBufXSize,
211✔
328
                      int nBufYSize, GSpacing nPixelSpace, GSpacing nLineSpace,
329
                      double dfNoDataValue, double &dfMin, double &dfMax)
330
{
331
    switch (eDT)
211✔
332
    {
333
        case GDT_Byte:
197✔
334
            GetMinMax(static_cast<const GByte *>(pBuffer), nBufXSize, nBufYSize,
197✔
335
                      nPixelSpace, nLineSpace, dfNoDataValue, dfMin, dfMax);
336
            break;
197✔
337
        case GDT_Int8:
2✔
338
            GetMinMax(static_cast<const GInt8 *>(pBuffer), nBufXSize, nBufYSize,
2✔
339
                      nPixelSpace, nLineSpace, dfNoDataValue, dfMin, dfMax);
340
            break;
2✔
341
        case GDT_UInt16:
2✔
342
            GetMinMax(static_cast<const GUInt16 *>(pBuffer), nBufXSize,
2✔
343
                      nBufYSize, nPixelSpace, nLineSpace, dfNoDataValue, dfMin,
344
                      dfMax);
345
            break;
2✔
346
        case GDT_Int16:
2✔
347
            GetMinMax(static_cast<const GInt16 *>(pBuffer), nBufXSize,
2✔
348
                      nBufYSize, nPixelSpace, nLineSpace, dfNoDataValue, dfMin,
349
                      dfMax);
350
            break;
2✔
351
        case GDT_UInt32:
2✔
352
            GetMinMax(static_cast<const GUInt32 *>(pBuffer), nBufXSize,
2✔
353
                      nBufYSize, nPixelSpace, nLineSpace, dfNoDataValue, dfMin,
354
                      dfMax);
355
            break;
2✔
356
        case GDT_Int32:
2✔
357
            GetMinMax(static_cast<const GInt32 *>(pBuffer), nBufXSize,
2✔
358
                      nBufYSize, nPixelSpace, nLineSpace, dfNoDataValue, dfMin,
359
                      dfMax);
360
            break;
2✔
361
        case GDT_Float32:
2✔
362
            GetMinMax(static_cast<const float *>(pBuffer), nBufXSize, nBufYSize,
2✔
363
                      nPixelSpace, nLineSpace, dfNoDataValue, dfMin, dfMax);
364
            break;
2✔
365
        case GDT_Float64:
2✔
366
            GetMinMax(static_cast<const double *>(pBuffer), nBufXSize,
2✔
367
                      nBufYSize, nPixelSpace, nLineSpace, dfNoDataValue, dfMin,
368
                      dfMax);
369
            break;
2✔
370
        default:
×
371
            CPLAssert(false);
×
372
            break;
373
    }
374
}
211✔
375

376
/************************************************************************/
377
/*                            IWriteBlock()                             */
378
/************************************************************************/
379

380
CPLErr RRASTERRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
149✔
381
                                      void *pImage)
382
{
383
    RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS);
149✔
384
    poGDS->InitImageIfNeeded();
149✔
385

386
    int bGotNoDataValue = false;
149✔
387
    double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
149✔
388
    if (!bGotNoDataValue)
149✔
389
        dfNoDataValue = std::numeric_limits<double>::quiet_NaN();
148✔
390
    GetMinMax(pImage, poGDS->IsSignedByte() ? GDT_Int8 : eDataType, nBlockXSize,
149✔
391
              nBlockYSize, 1, nBlockXSize, dfNoDataValue, m_dfMin, m_dfMax);
149✔
392
    return RawRasterBand::IWriteBlock(nBlockXOff, nBlockYOff, pImage);
298✔
393
}
394

395
/************************************************************************/
396
/*                             IRasterIO()                              */
397
/************************************************************************/
398

399
CPLErr RRASTERRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
325✔
400
                                    int nXSize, int nYSize, void *pData,
401
                                    int nBufXSize, int nBufYSize,
402
                                    GDALDataType eBufType, GSpacing nPixelSpace,
403
                                    GSpacing nLineSpace,
404
                                    GDALRasterIOExtraArg *psExtraArg)
405

406
{
407
    if (eRWFlag == GF_Write)
325✔
408
    {
409
        RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS);
62✔
410
        poGDS->InitImageIfNeeded();
62✔
411

412
        const int nDTSize = std::max(1, GDALGetDataTypeSizeBytes(eDataType));
62✔
413
        int bGotNoDataValue = false;
62✔
414
        double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
62✔
415
        if (!bGotNoDataValue)
62✔
416
            dfNoDataValue = std::numeric_limits<double>::quiet_NaN();
61✔
417
        GetMinMax(pData, poGDS->IsSignedByte() ? GDT_Int8 : eDataType,
62✔
418
                  nBufXSize, nBufYSize, nPixelSpace / nDTSize,
62✔
419
                  nLineSpace / nDTSize, dfNoDataValue, m_dfMin, m_dfMax);
62✔
420
    }
421
    return RawRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
325✔
422
                                    pData, nBufXSize, nBufYSize, eBufType,
423
                                    nPixelSpace, nLineSpace, psExtraArg);
325✔
424
}
425

426
/************************************************************************/
427
/*                           RRASTERDataset()                           */
428
/************************************************************************/
429

430
RRASTERDataset::RRASTERDataset()
144✔
431
{
432
    m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
144✔
433
}
144✔
434

435
/************************************************************************/
436
/*                          ~RRASTERDataset()                           */
437
/************************************************************************/
438

439
RRASTERDataset::~RRASTERDataset()
288✔
440

441
{
442
    RRASTERDataset::Close();
144✔
443
}
288✔
444

445
/************************************************************************/
446
/*                              Close()                                 */
447
/************************************************************************/
448

449
CPLErr RRASTERDataset::Close()
281✔
450
{
451
    CPLErr eErr = CE_None;
281✔
452
    if (nOpenFlags != OPEN_FLAGS_CLOSED)
281✔
453
    {
454
        if (m_fpImage)
144✔
455
        {
456
            InitImageIfNeeded();
144✔
457
            if (RRASTERDataset::FlushCache(true) != CE_None)
144✔
458
                eErr = CE_Failure;
2✔
459
            if (VSIFCloseL(m_fpImage) != CE_None)
144✔
460
                eErr = CE_Failure;
×
461
        }
462
        if (m_bHeaderDirty)
144✔
463
            RewriteHeader();
61✔
464

465
        if (GDALPamDataset::Close() != CE_None)
144✔
466
            eErr = CE_Failure;
×
467
    }
468
    return eErr;
281✔
469
}
470

471
/************************************************************************/
472
/*                        InitImageIfNeeded()                           */
473
/************************************************************************/
474

475
void RRASTERDataset::InitImageIfNeeded()
355✔
476
{
477
    CPLAssert(m_fpImage);
355✔
478
    if (!m_bInitRaster)
355✔
479
        return;
334✔
480
    m_bInitRaster = false;
21✔
481
    int bGotNoDataValue = false;
21✔
482
    double dfNoDataValue = GetRasterBand(1)->GetNoDataValue(&bGotNoDataValue);
21✔
483
    const GDALDataType eDT = GetRasterBand(1)->GetRasterDataType();
21✔
484
    const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
21✔
485
    if (dfNoDataValue == 0.0)
21✔
486
    {
487
        VSIFTruncateL(m_fpImage, static_cast<vsi_l_offset>(nRasterXSize) *
20✔
488
                                     nRasterYSize * nBands * nDTSize);
20✔
489
    }
490
    else
491
    {
492
        GByte abyNoDataValue[16];
493
        GDALCopyWords(&dfNoDataValue, GDT_Float64, 0, abyNoDataValue, eDT, 0,
1✔
494
                      1);
495
        for (GUIntBig i = 0;
2✔
496
             i < static_cast<GUIntBig>(nRasterXSize) * nRasterYSize * nBands;
2✔
497
             i++)
498
        {
499
            VSIFWriteL(abyNoDataValue, 1, nDTSize, m_fpImage);
1✔
500
        }
501
    }
502
}
503

504
/************************************************************************/
505
/*                           RewriteHeader()                            */
506
/************************************************************************/
507

508
void RRASTERDataset::RewriteHeader()
61✔
509
{
510
    VSILFILE *fp = VSIFOpenL(GetDescription(), "wb");
61✔
511
    if (!fp)
61✔
512
        return;
×
513

514
    VSIFPrintfL(fp, "[general]\n");
61✔
515
    if (!m_osCreator.empty())
61✔
516
        VSIFPrintfL(fp, "creator=%s\n", m_osCreator.c_str());
4✔
517
    if (!m_osCreated.empty())
61✔
518
        VSIFPrintfL(fp, "created=%s\n", m_osCreated.c_str());
4✔
519

520
    VSIFPrintfL(fp, "[data]\n");
61✔
521
    GDALDataType eDT = GetRasterBand(1)->GetRasterDataType();
61✔
522
    VSIFPrintfL(fp, "datatype=%s\n",
119✔
523
                (eDT == GDT_Int8 || m_bSignedByte) ? "INT1S"
58✔
524
                : (eDT == GDT_Byte)                ? "INT1U"
525
                : (eDT == GDT_UInt16)              ? "INT2U"
526
                : (eDT == GDT_UInt32)              ? "INT4U"
527
                : (eDT == GDT_Int16)               ? "INT2S"
528
                : (eDT == GDT_Int32)               ? "INT4S"
529
                : (eDT == GDT_Float32)             ? "FLT4S"
530
                                                   :
531
                                       /*(eDT == GDT_Float64) ?*/ "FLT8S");
532

533
    int bGotNoDataValue = false;
61✔
534
    double dfNoDataValue = GetRasterBand(1)->GetNoDataValue(&bGotNoDataValue);
61✔
535
    if (bGotNoDataValue)
61✔
536
        VSIFPrintfL(fp, "nodatavalue=%.17g\n", dfNoDataValue);
3✔
537

538
#if CPL_IS_LSB
539
    VSIFPrintfL(fp, "byteorder=%s\n", m_bNativeOrder ? "little" : "big");
61✔
540
#else
541
    VSIFPrintfL(fp, "byteorder=%s\n", !m_bNativeOrder ? "little" : "big");
542
#endif
543
    VSIFPrintfL(fp, "nbands=%d\n", nBands);
61✔
544
    if (nBands > 1)
61✔
545
        VSIFPrintfL(fp, "bandorder=%s\n", m_osBandOrder.c_str());
20✔
546
    CPLString osMinValue, osMaxValue;
122✔
547
    for (int i = 1; i <= nBands; i++)
123✔
548
    {
549
        RRASTERRasterBand *poBand =
550
            static_cast<RRASTERRasterBand *>(GetRasterBand(i));
83✔
551
        if (i > 1)
83✔
552
        {
553
            osMinValue += ":";
22✔
554
            osMaxValue += ":";
22✔
555
        }
556
        if (poBand->m_dfMin > poBand->m_dfMax)
83✔
557
        {
558
            osMinValue.clear();
21✔
559
            break;
21✔
560
        }
561
        osMinValue += CPLSPrintf("%.17g", poBand->m_dfMin);
62✔
562
        osMaxValue += CPLSPrintf("%.17g", poBand->m_dfMax);
62✔
563
    }
564
    if (!osMinValue.empty())
61✔
565
    {
566
        VSIFPrintfL(fp, "minvalue=%s\n", osMinValue.c_str());
40✔
567
        VSIFPrintfL(fp, "maxvalue=%s\n", osMaxValue.c_str());
40✔
568
    }
569

570
    GDALColorTable *poCT = GetRasterBand(1)->GetColorTable();
61✔
571
    GDALRasterAttributeTable *poRAT = GetRasterBand(1)->GetDefaultRAT();
61✔
572
    if (poCT == nullptr && poRAT == nullptr)
61✔
573
    {
574
        VSIFPrintfL(fp, "categorical=FALSE\n");
58✔
575
    }
576
    else
577
    {
578
        VSIFPrintfL(fp, "categorical=TRUE\n");
3✔
579
        if (poCT && poRAT)
3✔
580
        {
581
            CPLError(CE_Warning, CPLE_AppDefined,
×
582
                     "Both color table and raster attribute table defined. "
583
                     "Writing only the later");
584
        }
585
        if (poRAT)
3✔
586
        {
587
            CPLString osRatNames;
2✔
588
            CPLString osRatTypes;
2✔
589
            for (int i = 0; i < poRAT->GetColumnCount(); i++)
11✔
590
            {
591
                if (!osRatNames.empty())
10✔
592
                {
593
                    osRatNames += ":";
9✔
594
                    osRatTypes += ":";
9✔
595
                }
596
                osRatNames +=
597
                    CPLString(poRAT->GetNameOfCol(i)).replaceAll(':', '.');
10✔
598
                GDALRATFieldType eColType = poRAT->GetTypeOfCol(i);
10✔
599
                if (eColType == GFT_Integer)
10✔
600
                    osRatTypes += "integer";
7✔
601
                else if (eColType == GFT_Real)
3✔
602
                    osRatTypes += "numeric";
1✔
603
                else
604
                    osRatTypes += "character";
2✔
605
            }
606
            VSIFPrintfL(fp, "ratnames=%s\n", osRatNames.c_str());
1✔
607
            VSIFPrintfL(fp, "rattypes=%s\n", osRatTypes.c_str());
1✔
608
            CPLString osRatValues;
2✔
609
            for (int i = 0; i < poRAT->GetColumnCount(); i++)
11✔
610
            {
611
                GDALRATFieldType eColType = poRAT->GetTypeOfCol(i);
10✔
612
                for (int j = 0; j < poRAT->GetRowCount(); j++)
30✔
613
                {
614
                    if (i != 0 || j != 0)
20✔
615
                        osRatValues += ":";
19✔
616
                    if (eColType == GFT_Integer)
20✔
617
                    {
618
                        osRatValues +=
619
                            CPLSPrintf("%d", poRAT->GetValueAsInt(j, i));
14✔
620
                    }
621
                    else if (eColType == GFT_Real)
6✔
622
                    {
623
                        osRatValues +=
624
                            CPLSPrintf("%.17g", poRAT->GetValueAsDouble(j, i));
2✔
625
                    }
626
                    else
627
                    {
628
                        const char *pszVal = poRAT->GetValueAsString(j, i);
4✔
629
                        if (pszVal)
4✔
630
                        {
631
                            osRatValues +=
632
                                CPLString(pszVal).replaceAll(':', '.');
4✔
633
                        }
634
                    }
635
                }
636
            }
637
            VSIFPrintfL(fp, "ratvalues=%s\n", osRatValues.c_str());
1✔
638
        }
639
        else
640
        {
641
            bool bNeedsAlpha = false;
2✔
642
            for (int i = 0; i < poCT->GetColorEntryCount(); i++)
4✔
643
            {
644
                if (poCT->GetColorEntry(i)->c4 != 255)
3✔
645
                {
646
                    bNeedsAlpha = true;
1✔
647
                    break;
1✔
648
                }
649
            }
650
            if (!bNeedsAlpha)
2✔
651
            {
652
                VSIFPrintfL(fp, "ratnames=%s\n", "ID:red:green:blue");
1✔
653
                VSIFPrintfL(fp, "rattypes=%s\n",
1✔
654
                            "integer:integer:integer:integer");
655
            }
656
            else
657
            {
658
                VSIFPrintfL(fp, "ratnames=%s\n", "ID:red:green:blue:alpha");
1✔
659
                VSIFPrintfL(fp, "rattypes=%s\n",
1✔
660
                            "integer:integer:integer:integer:integer");
661
            }
662

663
            CPLString osRatID;
4✔
664
            CPLString osRatR;
4✔
665
            CPLString osRatG;
4✔
666
            CPLString osRatB;
4✔
667
            CPLString osRatA;
4✔
668
            for (int i = 0; i < poCT->GetColorEntryCount(); i++)
6✔
669
            {
670
                const GDALColorEntry *psEntry = poCT->GetColorEntry(i);
4✔
671
                if (i > 0)
4✔
672
                {
673
                    osRatID += ":";
2✔
674
                    osRatR += ":";
2✔
675
                    osRatG += ":";
2✔
676
                    osRatB += ":";
2✔
677
                    osRatA += ":";
2✔
678
                }
679
                osRatID += CPLSPrintf("%d", i);
4✔
680
                osRatR += CPLSPrintf("%d", psEntry->c1);
4✔
681
                osRatG += CPLSPrintf("%d", psEntry->c2);
4✔
682
                osRatB += CPLSPrintf("%d", psEntry->c3);
4✔
683
                osRatA += CPLSPrintf("%d", psEntry->c4);
4✔
684
            }
685
            if (!bNeedsAlpha)
2✔
686
            {
687
                VSIFPrintfL(fp, "ratvalues=%s:%s:%s:%s\n", osRatID.c_str(),
1✔
688
                            osRatR.c_str(), osRatG.c_str(), osRatB.c_str());
689
            }
690
            else
691
            {
692
                VSIFPrintfL(fp, "ratvalues=%s:%s:%s:%s:%s\n", osRatID.c_str(),
1✔
693
                            osRatR.c_str(), osRatG.c_str(), osRatB.c_str(),
694
                            osRatA.c_str());
695
            }
696
        }
697
    }
698

699
    if (!m_osLegend.empty())
61✔
700
        VSIFPrintfL(fp, "[legend]\n%s", m_osLegend.c_str());
×
701

702
    CPLString osLayerName;
122✔
703
    bool bGotSignificantBandDesc = false;
61✔
704
    for (int i = 1; i <= nBands; i++)
171✔
705
    {
706
        GDALRasterBand *poBand = GetRasterBand(i);
110✔
707
        const char *pszDesc = poBand->GetDescription();
110✔
708
        if (EQUAL(pszDesc, ""))
110✔
709
        {
710
            GDALColorInterp eInterp = poBand->GetColorInterpretation();
90✔
711
            if (eInterp == GCI_RedBand)
90✔
712
            {
713
                bGotSignificantBandDesc = true;
1✔
714
                pszDesc = "red";
1✔
715
            }
716
            else if (eInterp == GCI_GreenBand)
89✔
717
            {
718
                bGotSignificantBandDesc = true;
1✔
719
                pszDesc = "green";
1✔
720
            }
721
            else if (eInterp == GCI_BlueBand)
88✔
722
            {
723
                bGotSignificantBandDesc = true;
1✔
724
                pszDesc = "blue";
1✔
725
            }
726
            else if (eInterp == GCI_AlphaBand)
87✔
727
            {
728
                bGotSignificantBandDesc = true;
1✔
729
                pszDesc = "alpha";
1✔
730
            }
731
            else
732
            {
733
                pszDesc = CPLSPrintf("Band%d", i);
86✔
734
            }
735
        }
736
        else
737
        {
738
            bGotSignificantBandDesc = true;
20✔
739
        }
740
        if (i > 1)
110✔
741
            osLayerName += ":";
49✔
742
        osLayerName += CPLString(pszDesc).replaceAll(':', '.');
110✔
743
    }
744
    if (bGotSignificantBandDesc)
61✔
745
    {
746
        VSIFPrintfL(fp, "[description]\n");
9✔
747
        VSIFPrintfL(fp, "layername=%s\n", osLayerName.c_str());
9✔
748
    }
749

750
    // Put the [georeference] section at end. Otherwise the wkt= entry
751
    // could cause GDAL < 3.5 to be unable to open the file due to the
752
    // Identify() function not using enough bytes
753
    VSIFPrintfL(fp, "[georeference]\n");
61✔
754
    VSIFPrintfL(fp, "nrows=%d\n", nRasterYSize);
61✔
755
    VSIFPrintfL(fp, "ncols=%d\n", nRasterXSize);
61✔
756

757
    VSIFPrintfL(fp, "xmin=%.17g\n", m_gt[0]);
61✔
758
    VSIFPrintfL(fp, "ymin=%.17g\n", m_gt[3] + nRasterYSize * m_gt[5]);
61✔
759
    VSIFPrintfL(fp, "xmax=%.17g\n", m_gt[0] + nRasterXSize * m_gt[1]);
61✔
760
    VSIFPrintfL(fp, "ymax=%.17g\n", m_gt[3]);
61✔
761

762
    if (!m_oSRS.IsEmpty())
61✔
763
    {
764
        char *pszProj4 = nullptr;
59✔
765
        m_oSRS.exportToProj4(&pszProj4);
59✔
766
        if (pszProj4)
59✔
767
        {
768
            VSIFPrintfL(fp, "projection=%s\n", pszProj4);
59✔
769
            VSIFree(pszProj4);
59✔
770
        }
771
        char *pszWKT = nullptr;
59✔
772
        const char *const apszOptions[] = {"FORMAT=WKT2_2019", nullptr};
59✔
773
        m_oSRS.exportToWkt(&pszWKT, apszOptions);
59✔
774
        if (pszWKT)
59✔
775
        {
776
            VSIFPrintfL(fp, "wkt=%s\n", pszWKT);
59✔
777
            VSIFree(pszWKT);
59✔
778
        }
779
    }
780

781
    VSIFCloseL(fp);
61✔
782
}
783

784
/************************************************************************/
785
/*                            GetFileList()                             */
786
/************************************************************************/
787

788
char **RRASTERDataset::GetFileList()
37✔
789

790
{
791
    char **papszFileList = RawDataset::GetFileList();
37✔
792

793
    papszFileList = CSLAddString(papszFileList, m_osGriFilename);
37✔
794

795
    return papszFileList;
37✔
796
}
797

798
/************************************************************************/
799
/*                          GetGeoTransform()                           */
800
/************************************************************************/
801

802
CPLErr RRASTERDataset::GetGeoTransform(GDALGeoTransform &gt) const
120✔
803
{
804
    if (m_bGeoTransformValid)
120✔
805
    {
806
        gt = m_gt;
120✔
807
        return CE_None;
120✔
808
    }
809
    return CE_Failure;
×
810
}
811

812
/************************************************************************/
813
/*                          SetGeoTransform()                           */
814
/************************************************************************/
815

816
CPLErr RRASTERDataset::SetGeoTransform(const GDALGeoTransform &gt)
59✔
817

818
{
819
    if (GetAccess() != GA_Update)
59✔
820
    {
821
        CPLError(CE_Failure, CPLE_NotSupported,
×
822
                 "Cannot set geotransform on a read-only dataset");
823
        return CE_Failure;
×
824
    }
825

826
    // We only support non-rotated images with info in the .HDR file.
827
    if (gt[2] != 0.0 || gt[4] != 0.0)
59✔
828
    {
829
        CPLError(CE_Warning, CPLE_NotSupported,
×
830
                 "Rotated / skewed images not supported");
831
        return GDALPamDataset::SetGeoTransform(gt);
×
832
    }
833

834
    // Record new geotransform.
835
    m_bGeoTransformValid = true;
59✔
836
    m_gt = gt;
59✔
837
    SetHeaderDirty();
59✔
838

839
    return CE_None;
59✔
840
}
841

842
/************************************************************************/
843
/*                           GetSpatialRef()                            */
844
/************************************************************************/
845

846
const OGRSpatialReference *RRASTERDataset::GetSpatialRef() const
35✔
847
{
848
    return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
35✔
849
}
850

851
/************************************************************************/
852
/*                           SetSpatialRef()                            */
853
/************************************************************************/
854

855
CPLErr RRASTERDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
59✔
856
{
857
    if (GetAccess() != GA_Update)
59✔
858
    {
859
        CPLError(CE_Failure, CPLE_NotSupported,
×
860
                 "Cannot set projection on a read-only dataset");
861
        return CE_Failure;
×
862
    }
863

864
    m_oSRS.Clear();
59✔
865
    if (poSRS)
59✔
866
        m_oSRS = *poSRS;
59✔
867
    SetHeaderDirty();
59✔
868

869
    return CE_None;
59✔
870
}
871

872
/************************************************************************/
873
/*                            SetMetadata()                             */
874
/************************************************************************/
875

876
CPLErr RRASTERDataset::SetMetadata(char **papszMetadata, const char *pszDomain)
31✔
877
{
878
    if (pszDomain == nullptr || EQUAL(pszDomain, ""))
31✔
879
    {
880
        m_osCreator = CSLFetchNameValueDef(papszMetadata, "CREATOR", "");
31✔
881
        m_osCreated = CSLFetchNameValueDef(papszMetadata, "CREATED", "");
31✔
882
        SetHeaderDirty();
31✔
883
    }
884
    return GDALDataset::SetMetadata(papszMetadata, pszDomain);
31✔
885
}
886

887
/************************************************************************/
888
/*                          SetMetadataItem()                           */
889
/************************************************************************/
890

891
CPLErr RRASTERDataset::SetMetadataItem(const char *pszName,
2✔
892
                                       const char *pszValue,
893
                                       const char *pszDomain)
894
{
895
    if (pszDomain == nullptr || EQUAL(pszDomain, ""))
2✔
896
    {
897
        if (EQUAL(pszName, "CREATOR"))
2✔
898
        {
899
            m_osCreator = pszValue ? pszValue : "";
1✔
900
            SetHeaderDirty();
1✔
901
        }
902
        if (EQUAL(pszName, "CREATED"))
2✔
903
        {
904
            m_osCreated = pszValue ? pszValue : "";
1✔
905
            SetHeaderDirty();
1✔
906
        }
907
    }
908
    return GDALDataset::SetMetadataItem(pszName, pszValue, pszDomain);
2✔
909
}
910

911
/************************************************************************/
912
/*                            Identify()                                */
913
/************************************************************************/
914

915
int RRASTERDataset::Identify(GDALOpenInfo *poOpenInfo)
57,146✔
916

917
{
918
    if (poOpenInfo->nHeaderBytes < 40 || poOpenInfo->fpL == nullptr ||
60,703✔
919
        !poOpenInfo->IsExtensionEqualToCI("grd"))
3,557✔
920
    {
921
        return FALSE;
56,954✔
922
    }
923

924
    // We need to ingest enough bytes as the wkt= entry can be quite large
925
    if (poOpenInfo->nHeaderBytes <= 1024)
192✔
926
        poOpenInfo->TryToIngest(4096);
148✔
927

928
    if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
191✔
929
               "ncols") == nullptr ||
173✔
930
        strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
173✔
931
               "nrows") == nullptr ||
173✔
932
        strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
173✔
933
               "xmin") == nullptr ||
173✔
934
        strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
173✔
935
               "ymin") == nullptr ||
173✔
936
        strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
173✔
937
               "xmax") == nullptr ||
173✔
938
        strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
173✔
939
               "ymax") == nullptr ||
173✔
940
        strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
173✔
941
               "datatype") == nullptr)
942
    {
943
        return FALSE;
18✔
944
    }
945

946
    return TRUE;
173✔
947
}
948

949
/************************************************************************/
950
/*                          ComputeSpacing()                            */
951
/************************************************************************/
952

953
bool RRASTERDataset::ComputeSpacings(const CPLString &osBandOrder, int nCols,
147✔
954
                                     int nRows, int l_nBands, GDALDataType eDT,
955
                                     int &nPixelOffset, int &nLineOffset,
956
                                     vsi_l_offset &nBandOffset)
957
{
958
    nPixelOffset = 0;
147✔
959
    nLineOffset = 0;
147✔
960
    nBandOffset = 0;
147✔
961
    const int nPixelSize = GDALGetDataTypeSizeBytes(eDT);
147✔
962
    if (l_nBands == 1 || EQUAL(osBandOrder, "BIL"))
147✔
963
    {
964
        nPixelOffset = nPixelSize;
137✔
965
        if (l_nBands != 0 && nPixelSize != 0 &&
137✔
966
            nCols > INT_MAX / (l_nBands * nPixelSize))
137✔
967
        {
968
            CPLError(CE_Failure, CPLE_AppDefined, "Too many columns");
×
969
            return false;
×
970
        }
971
        nLineOffset = nPixelSize * nCols * l_nBands;
137✔
972
        nBandOffset = static_cast<vsi_l_offset>(nPixelSize) * nCols;
137✔
973
    }
974
    else if (EQUAL(osBandOrder, "BIP"))
10✔
975
    {
976
        if (l_nBands != 0 && nPixelSize != 0 &&
3✔
977
            nCols > INT_MAX / (l_nBands * nPixelSize))
3✔
978
        {
979
            CPLError(CE_Failure, CPLE_AppDefined, "Too many columns");
×
980
            return false;
×
981
        }
982
        nPixelOffset = nPixelSize * l_nBands;
3✔
983
        nLineOffset = nPixelSize * nCols * l_nBands;
3✔
984
        nBandOffset = nPixelSize;
3✔
985
    }
986
    else if (EQUAL(osBandOrder, "BSQ"))
7✔
987
    {
988
        if (nPixelSize != 0 && nCols > INT_MAX / nPixelSize)
7✔
989
        {
990
            CPLError(CE_Failure, CPLE_AppDefined, "Too many columns");
×
991
            return false;
×
992
        }
993
        nPixelOffset = nPixelSize;
7✔
994
        nLineOffset = nPixelSize * nCols;
7✔
995
        nBandOffset = static_cast<vsi_l_offset>(nLineOffset) * nRows;
7✔
996
    }
997
    else if (l_nBands > 1)
×
998
    {
999
        CPLError(CE_Failure, CPLE_AppDefined, "Unknown bandorder");
×
1000
        return false;
×
1001
    }
1002
    return true;
147✔
1003
}
1004

1005
/************************************************************************/
1006
/*                            CastToFloat()                             */
1007
/************************************************************************/
1008

1009
static float CastToFloat(double dfVal)
×
1010
{
1011
    if (std::isinf(dfVal) || std::isnan(dfVal) ||
×
1012
        (dfVal >= -std::numeric_limits<float>::max() &&
×
1013
         dfVal <= std::numeric_limits<float>::max()))
×
1014
    {
1015
        return static_cast<float>(dfVal);
×
1016
    }
1017
    return std::numeric_limits<float>::quiet_NaN();
×
1018
}
1019

1020
/************************************************************************/
1021
/*                                Open()                                */
1022
/************************************************************************/
1023

1024
GDALDataset *RRASTERDataset::Open(GDALOpenInfo *poOpenInfo)
84✔
1025
{
1026
    if (!Identify(poOpenInfo))
84✔
1027
        return nullptr;
×
1028

1029
    auto poDS = std::make_unique<RRASTERDataset>();
168✔
1030

1031
    const char *pszLine = nullptr;
84✔
1032
    int nRows = 0;
84✔
1033
    int nCols = 0;
84✔
1034
    double dfXMin = 0.0;
84✔
1035
    double dfYMin = 0.0;
84✔
1036
    double dfXMax = 0.0;
84✔
1037
    double dfYMax = 0.0;
84✔
1038
    int l_nBands = 1;
84✔
1039
    CPLString osDataType;
168✔
1040
    CPLString osProjection;
168✔
1041
    CPLString osWkt;
168✔
1042
    CPLString osByteOrder;
168✔
1043
    CPLString osNoDataValue("NA");
168✔
1044
    CPLString osMinValue;
168✔
1045
    CPLString osMaxValue;
168✔
1046
    CPLString osLayerName;
168✔
1047
    CPLString osRatNames;
168✔
1048
    CPLString osRatTypes;
168✔
1049
    CPLString osRatValues;
168✔
1050
    bool bInLegend = false;
84✔
1051
    VSIRewindL(poOpenInfo->fpL);
84✔
1052
    while ((pszLine = CPLReadLine2L(poOpenInfo->fpL, 1024 * 1024, nullptr)) !=
1,592✔
1053
           nullptr)
1054
    {
1055
        if (pszLine[0] == '[')
1,508✔
1056
        {
1057
            bInLegend = EQUAL(pszLine, "[legend]");
276✔
1058
            continue;
276✔
1059
        }
1060
        if (bInLegend)
1,232✔
1061
        {
1062
            poDS->m_osLegend += pszLine;
6✔
1063
            poDS->m_osLegend += "\n";
6✔
1064
        }
1065
        char *pszKey = nullptr;
1,232✔
1066
        const char *pszValue = CPLParseNameValue(pszLine, &pszKey);
1,232✔
1067
        if (pszKey && pszValue)
1,232✔
1068
        {
1069
            if (EQUAL(pszKey, "creator"))
1,232✔
1070
                poDS->m_osCreator = pszValue;
12✔
1071
            if (EQUAL(pszKey, "created"))
1,232✔
1072
                poDS->m_osCreated = pszValue;
12✔
1073
            else if (EQUAL(pszKey, "ncols"))
1,220✔
1074
                nCols = atoi(pszValue);
84✔
1075
            else if (EQUAL(pszKey, "nrows"))
1,136✔
1076
                nRows = atoi(pszValue);
84✔
1077
            else if (EQUAL(pszKey, "xmin"))
1,052✔
1078
                dfXMin = CPLAtof(pszValue);
84✔
1079
            else if (EQUAL(pszKey, "ymin"))
968✔
1080
                dfYMin = CPLAtof(pszValue);
84✔
1081
            else if (EQUAL(pszKey, "xmax"))
884✔
1082
                dfXMax = CPLAtof(pszValue);
84✔
1083
            else if (EQUAL(pszKey, "ymax"))
800✔
1084
                dfYMax = CPLAtof(pszValue);
84✔
1085
            else if (EQUAL(pszKey, "projection"))
716✔
1086
                osProjection = pszValue;
80✔
1087
            else if (EQUAL(pszKey, "wkt"))
636✔
1088
                osWkt = pszValue;
67✔
1089
            else if (EQUAL(pszKey, "nbands"))
569✔
1090
                l_nBands = atoi(pszValue);
84✔
1091
            else if (EQUAL(pszKey, "bandorder"))
485✔
1092
                poDS->m_osBandOrder = pszValue;
34✔
1093
            else if (EQUAL(pszKey, "datatype"))
451✔
1094
                osDataType = pszValue;
84✔
1095
            else if (EQUAL(pszKey, "byteorder"))
367✔
1096
                osByteOrder = pszValue;
84✔
1097
            else if (EQUAL(pszKey, "nodatavalue"))
283✔
1098
                osNoDataValue = pszValue;
12✔
1099
            else if (EQUAL(pszKey, "minvalue"))
271✔
1100
                osMinValue = pszValue;
50✔
1101
            else if (EQUAL(pszKey, "maxvalue"))
221✔
1102
                osMaxValue = pszValue;
50✔
1103
            else if (EQUAL(pszKey, "ratnames"))
171✔
1104
                osRatNames = pszValue;
12✔
1105
            else if (EQUAL(pszKey, "rattypes"))
159✔
1106
                osRatTypes = pszValue;
12✔
1107
            else if (EQUAL(pszKey, "ratvalues"))
147✔
1108
                osRatValues = pszValue;
12✔
1109
            else if (EQUAL(pszKey, "layername"))
135✔
1110
                osLayerName = pszValue;
33✔
1111
        }
1112
        CPLFree(pszKey);
1,232✔
1113
    }
1114
    if (!GDALCheckDatasetDimensions(nCols, nRows))
84✔
1115
        return nullptr;
×
1116
    if (!GDALCheckBandCount(l_nBands, FALSE))
84✔
1117
        return nullptr;
×
1118

1119
    GDALDataType eDT = GDT_Unknown;
84✔
1120
    if (EQUAL(osDataType, "LOG1S"))
84✔
1121
        eDT = GDT_Byte;  // mapping TBC
×
1122
    else if (EQUAL(osDataType, "INT1S"))
84✔
1123
        eDT = GDT_Int8;
6✔
1124
    else if (EQUAL(osDataType, "INT2S"))
78✔
1125
        eDT = GDT_Int16;
5✔
1126
    else if (EQUAL(osDataType, "INT4S"))
73✔
1127
        eDT = GDT_Int32;
5✔
1128
    // else if( EQUAL(osDataType, "INT8S") )
1129
    //     eDT = GDT_UInt64; // unhandled
1130
    else if (EQUAL(osDataType, "INT1U"))
68✔
1131
        eDT = GDT_Byte;
49✔
1132
    else if (EQUAL(osDataType, "INT2U"))
19✔
1133
        eDT = GDT_UInt16;
5✔
1134
    else if (EQUAL(osDataType, "INT4U"))  // Not documented
14✔
1135
        eDT = GDT_UInt32;
5✔
1136
    else if (EQUAL(osDataType, "FLT4S"))
9✔
1137
        eDT = GDT_Float32;
5✔
1138
    else if (EQUAL(osDataType, "FLT8S"))
4✔
1139
        eDT = GDT_Float64;
4✔
1140
    else
1141
    {
1142
        CPLError(CE_Failure, CPLE_AppDefined, "Unhandled datatype=%s",
×
1143
                 osDataType.c_str());
1144
        return nullptr;
×
1145
    }
1146
    if (l_nBands > 1 && poDS->m_osBandOrder.empty())
84✔
1147
    {
1148
        CPLError(CE_Failure, CPLE_AppDefined, "Missing 'bandorder'");
×
1149
        return nullptr;
×
1150
    }
1151

1152
    bool bNativeOrder = true;
84✔
1153
    if (EQUAL(osByteOrder, "little"))
84✔
1154
    {
1155
        bNativeOrder = CPL_TO_BOOL(CPL_IS_LSB);
84✔
1156
    }
1157
    else if (EQUAL(osByteOrder, "big"))
×
1158
    {
1159
        bNativeOrder = CPL_TO_BOOL(!CPL_IS_LSB);
×
1160
    }
1161
    else if (!EQUAL(osByteOrder, ""))
×
1162
    {
1163
        CPLError(CE_Warning, CPLE_AppDefined,
×
1164
                 "Unhandled byteorder=%s. Assuming native order",
1165
                 osByteOrder.c_str());
1166
    }
1167

1168
    int nPixelOffset = 0;
84✔
1169
    int nLineOffset = 0;
84✔
1170
    vsi_l_offset nBandOffset = 0;
84✔
1171
    if (!ComputeSpacings(poDS->m_osBandOrder, nCols, nRows, l_nBands, eDT,
84✔
1172
                         nPixelOffset, nLineOffset, nBandOffset))
1173
    {
1174
        return nullptr;
×
1175
    }
1176

1177
    CPLString osDirname(CPLGetDirnameSafe(poOpenInfo->pszFilename));
168✔
1178
    CPLString osBasename(CPLGetBasenameSafe(poOpenInfo->pszFilename));
168✔
1179
    CPLString osGRDExtension(poOpenInfo->osExtension);
168✔
1180
    CPLString osGRIExtension((osGRDExtension[0] == 'g') ? "gri" : "GRI");
168✔
1181
    char **papszSiblings = poOpenInfo->GetSiblingFiles();
84✔
1182
    if (papszSiblings)
84✔
1183
    {
1184
        int iFile = CSLFindString(
84✔
1185
            papszSiblings,
1186
            CPLFormFilenameSafe(nullptr, osBasename, osGRIExtension).c_str());
168✔
1187
        if (iFile < 0)
84✔
1188
            return nullptr;
×
1189
        poDS->m_osGriFilename =
84✔
1190
            CPLFormFilenameSafe(osDirname, papszSiblings[iFile], nullptr);
168✔
1191
    }
1192
    else
1193
    {
1194
        poDS->m_osGriFilename =
×
1195
            CPLFormFilenameSafe(osDirname, osBasename, osGRIExtension);
×
1196
    }
1197

1198
    VSILFILE *fpImage =
1199
        VSIFOpenL(poDS->m_osGriFilename,
84✔
1200
                  (poOpenInfo->eAccess == GA_Update) ? "rb+" : "rb");
84✔
1201
    if (fpImage == nullptr)
84✔
1202
    {
1203
        CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s",
×
1204
                 poDS->m_osGriFilename.c_str());
×
1205
        return nullptr;
×
1206
    }
1207

1208
    if (!RAWDatasetCheckMemoryUsage(nCols, nRows, l_nBands,
84✔
1209
                                    GDALGetDataTypeSizeBytes(eDT), nPixelOffset,
1210
                                    nLineOffset, 0, nBandOffset, fpImage))
1211
    {
1212
        VSIFCloseL(fpImage);
×
1213
        return nullptr;
×
1214
    }
1215

1216
    poDS->eAccess = poOpenInfo->eAccess;
84✔
1217
    poDS->nRasterXSize = nCols;
84✔
1218
    poDS->nRasterYSize = nRows;
84✔
1219
    poDS->m_bGeoTransformValid = true;
84✔
1220
    poDS->m_gt[0] = dfXMin;
84✔
1221
    poDS->m_gt[1] = (dfXMax - dfXMin) / nCols;
84✔
1222
    poDS->m_gt[2] = 0.0;
84✔
1223
    poDS->m_gt[3] = dfYMax;
84✔
1224
    poDS->m_gt[4] = 0.0;
84✔
1225
    poDS->m_gt[5] = -(dfYMax - dfYMin) / nRows;
84✔
1226
    poDS->m_fpImage = fpImage;
84✔
1227
    poDS->m_bNativeOrder = bNativeOrder;
84✔
1228

1229
    if (osWkt.empty())
84✔
1230
    {
1231
        if (!osProjection.empty())
17✔
1232
        {
1233
            poDS->m_oSRS.importFromProj4(osProjection.c_str());
13✔
1234
        }
1235
    }
1236
    else
1237
    {
1238
        poDS->m_oSRS.importFromWkt(osWkt.c_str());
67✔
1239
    }
1240

1241
    if (!poDS->m_osCreator.empty())
84✔
1242
        poDS->GDALDataset::SetMetadataItem("CREATOR", poDS->m_osCreator);
12✔
1243

1244
    if (!poDS->m_osCreated.empty())
84✔
1245
        poDS->GDALDataset::SetMetadataItem("CREATED", poDS->m_osCreated);
12✔
1246

1247
    // Instantiate RAT
1248
    if (!osRatNames.empty() && !osRatTypes.empty() && !osRatValues.empty())
84✔
1249
    {
1250
        CPLStringList aosRatNames(CSLTokenizeString2(osRatNames, ":", 0));
24✔
1251
        CPLStringList aosRatTypes(CSLTokenizeString2(osRatTypes, ":", 0));
24✔
1252
        CPLStringList aosRatValues(CSLTokenizeString2(osRatValues, ":", 0));
24✔
1253
        if (aosRatNames.size() >= 1 &&
12✔
1254
            aosRatNames.size() == aosRatTypes.size() &&
24✔
1255
            (aosRatValues.size() % aosRatNames.size()) == 0)
12✔
1256
        {
1257
            bool bIsCompatibleOfCT = false;
12✔
1258
            const int nValues = aosRatValues.size() / aosRatNames.size();
12✔
1259
            if ((aosRatNames.size() == 4 || aosRatNames.size() == 5) &&
20✔
1260
                EQUAL(aosRatNames[1], "red") &&
8✔
1261
                EQUAL(aosRatNames[2], "green") &&
8✔
1262
                EQUAL(aosRatNames[3], "blue") &&
8✔
1263
                (aosRatNames.size() == 4 || EQUAL(aosRatNames[4], "alpha")) &&
8✔
1264
                EQUAL(aosRatTypes[0], "integer") &&
8✔
1265
                EQUAL(aosRatTypes[1], "integer") &&
8✔
1266
                EQUAL(aosRatTypes[2], "integer") &&
8✔
1267
                EQUAL(aosRatTypes[3], "integer") &&
32✔
1268
                (aosRatTypes.size() == 4 || EQUAL(aosRatTypes[4], "integer")))
8✔
1269
            {
1270
                bIsCompatibleOfCT = true;
8✔
1271
                poDS->m_poCT.reset(new GDALColorTable());
8✔
1272
                for (int i = 0; i < nValues; i++)
24✔
1273
                {
1274
                    const int nIndex = atoi(aosRatValues[i]);
16✔
1275
                    if (nIndex >= 0 && nIndex < 65536)
16✔
1276
                    {
1277
                        const int nRed = atoi(aosRatValues[nValues + i]);
16✔
1278
                        const int nGreen = atoi(aosRatValues[2 * nValues + i]);
16✔
1279
                        const int nBlue = atoi(aosRatValues[3 * nValues + i]);
16✔
1280
                        const int nAlpha =
1281
                            aosRatTypes.size() == 4
16✔
1282
                                ? 255
16✔
1283
                                : atoi(aosRatValues[4 * nValues + i]);
8✔
1284
                        const GDALColorEntry oEntry = {
1285
                            static_cast<short>(nRed),
1286
                            static_cast<short>(nGreen),
1287
                            static_cast<short>(nBlue),
1288
                            static_cast<short>(nAlpha)};
16✔
1289

1290
                        poDS->m_poCT->SetColorEntry(nIndex, &oEntry);
16✔
1291
                    }
1292
                    else
1293
                    {
1294
                        bIsCompatibleOfCT = false;
×
1295
                        poDS->m_poCT.reset();
×
1296
                        break;
×
1297
                    }
1298
                }
1299
            }
1300

1301
            // cppcheck-suppress knownConditionTrueFalse
1302
            if (!bIsCompatibleOfCT)
12✔
1303
            {
1304
                poDS->m_poRAT.reset(new GDALDefaultRasterAttributeTable());
4✔
1305
                for (int i = 0; i < aosRatNames.size(); i++)
44✔
1306
                {
1307
                    poDS->m_poRAT->CreateColumn(
120✔
1308
                        aosRatNames[i],
40✔
1309
                        EQUAL(aosRatTypes[i], "integer")   ? GFT_Integer
40✔
1310
                        : EQUAL(aosRatTypes[i], "numeric") ? GFT_Real
12✔
1311
                                                           : GFT_String,
1312
                        EQUAL(aosRatNames[i], "red")          ? GFU_Red
40✔
1313
                        : EQUAL(aosRatNames[i], "green")      ? GFU_Green
68✔
1314
                        : EQUAL(aosRatNames[i], "blue")       ? GFU_Blue
60✔
1315
                        : EQUAL(aosRatNames[i], "alpha")      ? GFU_Alpha
52✔
1316
                        : EQUAL(aosRatNames[i], "name")       ? GFU_Name
44✔
1317
                        : EQUAL(aosRatNames[i], "pixelcount") ? GFU_PixelCount
20✔
1318
                                                              : GFU_Generic);
40✔
1319
                }
1320
                for (int i = 0; i < nValues; i++)
12✔
1321
                {
1322
                    for (int j = 0; j < aosRatTypes.size(); j++)
88✔
1323
                    {
1324
                        if (poDS->m_poRAT->GetTypeOfCol(j) == GFT_Integer)
80✔
1325
                        {
1326
                            poDS->m_poRAT->SetValue(
56✔
1327
                                i, j, atoi(aosRatValues[j * nValues + i]));
56✔
1328
                        }
1329
                        else if (poDS->m_poRAT->GetTypeOfCol(j) == GFT_Real)
24✔
1330
                        {
1331
                            poDS->m_poRAT->SetValue(
16✔
1332
                                i, j, CPLAtof(aosRatValues[j * nValues + i]));
8✔
1333
                        }
1334
                        else
1335
                        {
1336
                            poDS->m_poRAT->SetValue(
16✔
1337
                                i, j, aosRatValues[j * nValues + i]);
16✔
1338
                        }
1339
                    }
1340
                }
1341
            }
1342
        }
1343
    }
1344

1345
    CPLStringList aosMinValues(CSLTokenizeString2(osMinValue, ":", 0));
168✔
1346
    CPLStringList aosMaxValues(CSLTokenizeString2(osMaxValue, ":", 0));
168✔
1347

1348
    CPLStringList aosLayerNames(CSLTokenizeString2(osLayerName, ":", 0));
168✔
1349
    for (int i = 1; i <= l_nBands; i++)
237✔
1350
    {
1351
        auto poBand = std::make_unique<RRASTERRasterBand>(
1352
            poDS.get(), i, fpImage, nBandOffset * (i - 1), nPixelOffset,
153✔
1353
            nLineOffset, eDT, bNativeOrder);
153✔
1354
        if (!poBand->IsValid())
153✔
1355
        {
1356
            return nullptr;
×
1357
        }
1358
        if (!osNoDataValue.empty() && !EQUAL(osNoDataValue, "NA"))
153✔
1359
        {
1360
            double dfNoDataValue = CPLAtof(osNoDataValue);
10✔
1361
            if (eDT == GDT_Float32)
10✔
1362
                dfNoDataValue = CastToFloat(dfNoDataValue);
×
1363
            poBand->m_bHasNoDataValue = true;
10✔
1364
            poBand->m_dfNoDataValue = dfNoDataValue;
10✔
1365
        }
1366
        if (i - 1 < static_cast<int>(aosMinValues.size()) &&
227✔
1367
            i - 1 < static_cast<int>(aosMaxValues.size()))
74✔
1368
        {
1369
            poBand->SetMinMax(CPLAtof(aosMinValues[i - 1]),
148✔
1370
                              CPLAtof(aosMaxValues[i - 1]));
74✔
1371
        }
1372
        if (i - 1 < static_cast<int>(aosLayerNames.size()))
153✔
1373
        {
1374
            const CPLString osName(aosLayerNames[i - 1]);
156✔
1375
            poBand->GDALRasterBand::SetDescription(osName);
78✔
1376
            if (EQUAL(osName, "red"))
78✔
1377
                poBand->SetColorInterpretation(GCI_RedBand);
15✔
1378
            else if (EQUAL(osName, "green"))
63✔
1379
                poBand->SetColorInterpretation(GCI_GreenBand);
15✔
1380
            else if (EQUAL(osName, "blue"))
48✔
1381
                poBand->SetColorInterpretation(GCI_BlueBand);
15✔
1382
            else if (EQUAL(osName, "alpha"))
33✔
1383
                poBand->SetColorInterpretation(GCI_AlphaBand);
15✔
1384
        }
1385
        poBand->m_poRAT = poDS->m_poRAT;
153✔
1386
        poBand->m_poCT = poDS->m_poCT;
153✔
1387
        if (poBand->m_poCT)
153✔
1388
            poBand->SetColorInterpretation(GCI_PaletteIndex);
8✔
1389
        poDS->SetBand(i, std::move(poBand));
153✔
1390
    }
1391

1392
    return poDS.release();
84✔
1393
}
1394

1395
/************************************************************************/
1396
/*                               Create()                               */
1397
/************************************************************************/
1398

1399
GDALDataset *RRASTERDataset::Create(const char *pszFilename, int nXSize,
80✔
1400
                                    int nYSize, int nBandsIn,
1401
                                    GDALDataType eType, char **papszOptions)
1402

1403
{
1404
    // Verify input options.
1405
    if (nBandsIn <= 0)
80✔
1406
    {
1407
        CPLError(CE_Failure, CPLE_NotSupported,
1✔
1408
                 "RRASTER driver does not support %d bands.", nBandsIn);
1409
        return nullptr;
1✔
1410
    }
1411

1412
    if (eType != GDT_Byte && eType != GDT_Int8 && eType != GDT_UInt16 &&
79✔
1413
        eType != GDT_Int16 && eType != GDT_Int32 && eType != GDT_UInt32 &&
32✔
1414
        eType != GDT_Float32 && eType != GDT_Float64)
20✔
1415
    {
1416
        CPLError(CE_Failure, CPLE_NotSupported, "Unsupported data type (%s).",
16✔
1417
                 GDALGetDataTypeName(eType));
1418
        return nullptr;
16✔
1419
    }
1420

1421
    CPLString osGRDExtension(CPLGetExtensionSafe(pszFilename));
126✔
1422
    if (!EQUAL(osGRDExtension, "grd"))
63✔
1423
    {
1424
        CPLError(CE_Failure, CPLE_NotSupported,
×
1425
                 "RRASTER driver only supports grd extension");
1426
        return nullptr;
×
1427
    }
1428

1429
    int nPixelOffset = 0;
63✔
1430
    int nLineOffset = 0;
63✔
1431
    vsi_l_offset nBandOffset = 0;
63✔
1432
    CPLString osBandOrder(
1433
        CSLFetchNameValueDef(papszOptions, "INTERLEAVE", "BIL"));
126✔
1434
    if (!ComputeSpacings(osBandOrder, nXSize, nYSize, nBandsIn, eType,
63✔
1435
                         nPixelOffset, nLineOffset, nBandOffset))
1436
    {
1437
        return nullptr;
×
1438
    }
1439

1440
    const std::string osGRIExtension((osGRDExtension[0] == 'g') ? "gri"
63✔
1441
                                                                : "GRI");
189✔
1442
    const std::string osGriFilename(
1443
        CPLResetExtensionSafe(pszFilename, osGRIExtension.c_str()));
126✔
1444

1445
    // Try to create the file.
1446
    VSILFILE *fpImage = VSIFOpenL(osGriFilename.c_str(), "wb+");
63✔
1447

1448
    if (fpImage == nullptr)
63✔
1449
    {
1450
        CPLError(CE_Failure, CPLE_OpenFailed,
3✔
1451
                 "Attempt to create file `%s' failed.", osGriFilename.c_str());
1452
        return nullptr;
3✔
1453
    }
1454

1455
    RRASTERDataset *poDS = new RRASTERDataset;
60✔
1456
    poDS->eAccess = GA_Update;
60✔
1457
    poDS->m_bHeaderDirty = true;
60✔
1458
    poDS->m_osGriFilename = osGriFilename;
60✔
1459
    poDS->nRasterXSize = nXSize;
60✔
1460
    poDS->nRasterYSize = nYSize;
60✔
1461
    poDS->m_fpImage = fpImage;
60✔
1462
    poDS->m_bNativeOrder = true;
60✔
1463
    poDS->m_osBandOrder = osBandOrder.toupper();
60✔
1464
    poDS->m_bInitRaster = CPLFetchBool(papszOptions, "@INIT_RASTER", true);
60✔
1465

1466
    const char *pszPixelType = CSLFetchNameValue(papszOptions, "PIXELTYPE");
60✔
1467
    const bool bByteSigned = (eType == GDT_Byte && pszPixelType &&
61✔
1468
                              EQUAL(pszPixelType, "SIGNEDBYTE"));
1✔
1469
    if (bByteSigned)
60✔
1470
        poDS->m_bSignedByte = true;
1✔
1471

1472
    for (int i = 1; i <= nBandsIn; i++)
169✔
1473
    {
1474
        RRASTERRasterBand *poBand =
1475
            new RRASTERRasterBand(poDS, i, fpImage, nBandOffset * (i - 1),
109✔
1476
                                  nPixelOffset, nLineOffset, eType, true);
109✔
1477
        poDS->SetBand(i, poBand);
109✔
1478
    }
1479

1480
    return poDS;
60✔
1481
}
1482

1483
/************************************************************************/
1484
/*                             CreateCopy()                             */
1485
/************************************************************************/
1486

1487
GDALDataset *RRASTERDataset::CreateCopy(const char *pszFilename,
47✔
1488
                                        GDALDataset *poSrcDS, int bStrict,
1489
                                        char **papszOptions,
1490
                                        GDALProgressFunc pfnProgress,
1491
                                        void *pProgressData)
1492

1493
{
1494
    // Proceed with normal copying using the default createcopy  operators.
1495
    GDALDriver *poDriver =
1496
        reinterpret_cast<GDALDriver *>(GDALGetDriverByName("RRASTER"));
47✔
1497

1498
    char **papszAdjustedOptions = CSLDuplicate(papszOptions);
47✔
1499
    papszAdjustedOptions =
1500
        CSLSetNameValue(papszAdjustedOptions, "@INIT_RASTER", "NO");
47✔
1501
    GDALDataset *poOutDS = poDriver->DefaultCreateCopy(
47✔
1502
        pszFilename, poSrcDS, bStrict, papszAdjustedOptions, pfnProgress,
1503
        pProgressData);
1504
    CSLDestroy(papszAdjustedOptions);
47✔
1505

1506
    if (poOutDS != nullptr)
47✔
1507
        poOutDS->FlushCache(false);
37✔
1508

1509
    return poOutDS;
47✔
1510
}
1511

1512
/************************************************************************/
1513
/*                   GDALRegister_RRASTER()                             */
1514
/************************************************************************/
1515

1516
void GDALRegister_RRASTER()
1,911✔
1517

1518
{
1519
    if (GDALGetDriverByName("RRASTER") != nullptr)
1,911✔
1520
        return;
282✔
1521

1522
    GDALDriver *poDriver = new GDALDriver();
1,629✔
1523

1524
    poDriver->SetDescription("RRASTER");
1,629✔
1525
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1,629✔
1526
    poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "grd");
1,629✔
1527
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "R Raster");
1,629✔
1528
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
1,629✔
1529
                              "drivers/raster/rraster.html");
1,629✔
1530
    poDriver->SetMetadataItem(
1,629✔
1531
        GDAL_DMD_CREATIONDATATYPES,
1532
        "Byte Int8 Int16 UInt16 Int32 UInt32 Float32 Float64");
1,629✔
1533

1534
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1,629✔
1535

1536
    poDriver->SetMetadataItem(
1,629✔
1537
        GDAL_DMD_CREATIONOPTIONLIST,
1538
        "<CreationOptionList>"
1539
        "   <Option name='PIXELTYPE' type='string' description='(deprecated, "
1540
        "use Int8) "
1541
        "By setting this to SIGNEDBYTE, a new Byte file can be forced to be "
1542
        "written "
1543
        "as signed byte'/>"
1544
        "   <Option name='INTERLEAVE' type='string-select' default='BIL'>"
1545
        "       <Value>BIP</Value>"
1546
        "       <Value>BIL</Value>"
1547
        "       <Value>BSQ</Value>"
1548
        "   </Option>"
1549
        "</CreationOptionList>");
1,629✔
1550

1551
    poDriver->pfnOpen = RRASTERDataset::Open;
1,629✔
1552
    poDriver->pfnIdentify = RRASTERDataset::Identify;
1,629✔
1553
    poDriver->pfnCreate = RRASTERDataset::Create;
1,629✔
1554
    poDriver->pfnCreateCopy = RRASTERDataset::CreateCopy;
1,629✔
1555

1556
    poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES");
1,629✔
1557
    poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS, "GeoTransform SRS NoData "
1,629✔
1558
                                                     "RasterValues "
1559
                                                     "DatasetMetadata");
1,629✔
1560

1561
    GetGDALDriverManager()->RegisterDriver(poDriver);
1,629✔
1562
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc