• 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

71.82
/frmts/gsg/gsbgdataset.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  Implements the Golden Software Binary Grid Format.
5
 * Author:   Kevin Locke, kwl7@cornell.edu
6
 *           (Based largely on aaigriddataset.cpp by Frank Warmerdam)
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2006, Kevin Locke <kwl7@cornell.edu>
10
 * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14

15
#include "cpl_conv.h"
16

17
#include <assert.h>
18
#include <float.h>
19
#include <limits.h>
20
#include <limits>
21

22
#include "gdal_frmts.h"
23
#include "gdal_pam.h"
24

25
/************************************************************************/
26
/* ==================================================================== */
27
/*                              GSBGDataset                             */
28
/* ==================================================================== */
29
/************************************************************************/
30

31
class GSBGRasterBand;
32

33
class GSBGDataset final : public GDALPamDataset
34
{
35
    friend class GSBGRasterBand;
36

37
    static const float fNODATA_VALUE;
38
    static const size_t nHEADER_SIZE;
39

40
    static CPLErr WriteHeader(VSILFILE *fp, int nXSize, int nYSize,
41
                              double dfMinX, double dfMaxX, double dfMinY,
42
                              double dfMaxY, double dfMinZ, double dfMaxZ);
43

44
    VSILFILE *fp = nullptr;
45

46
  public:
47
    GSBGDataset() = default;
45✔
48

49
    ~GSBGDataset();
50

51
    static int Identify(GDALOpenInfo *);
52
    static GDALDataset *Open(GDALOpenInfo *);
53
    static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
54
                               int nBands, GDALDataType eType,
55
                               char **papszParamList);
56
    static GDALDataset *CreateCopy(const char *pszFilename,
57
                                   GDALDataset *poSrcDS, int bStrict,
58
                                   char **papszOptions,
59
                                   GDALProgressFunc pfnProgress,
60
                                   void *pProgressData);
61

62
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
63
    CPLErr SetGeoTransform(const GDALGeoTransform &gt) override;
64
};
65

66
/* NOTE:  This is not mentioned in the spec, but Surfer 8 uses this value */
67
/* 0x7effffee (Little Endian: eeffff7e) */
68
const float GSBGDataset::fNODATA_VALUE = 1.701410009187828e+38f;
69

70
const size_t GSBGDataset::nHEADER_SIZE = 56;
71

72
/************************************************************************/
73
/* ==================================================================== */
74
/*                            GSBGRasterBand                            */
75
/* ==================================================================== */
76
/************************************************************************/
77

78
class GSBGRasterBand final : public GDALPamRasterBand
79
{
80
    friend class GSBGDataset;
81

82
    double dfMinX;
83
    double dfMaxX;
84
    double dfMinY;
85
    double dfMaxY;
86
    double dfMinZ;
87
    double dfMaxZ;
88

89
    float *pafRowMinZ;
90
    float *pafRowMaxZ;
91
    int nMinZRow;
92
    int nMaxZRow;
93

94
    CPLErr ScanForMinMaxZ();
95

96
  public:
97
    GSBGRasterBand(GSBGDataset *, int);
98
    ~GSBGRasterBand();
99

100
    CPLErr IReadBlock(int, int, void *) override;
101
    CPLErr IWriteBlock(int, int, void *) override;
102

103
    double GetNoDataValue(int *pbSuccess = nullptr) override;
104
    double GetMinimum(int *pbSuccess = nullptr) override;
105
    double GetMaximum(int *pbSuccess = nullptr) override;
106
};
107

108
/************************************************************************/
109
/*                           GSBGRasterBand()                           */
110
/************************************************************************/
111

112
GSBGRasterBand::GSBGRasterBand(GSBGDataset *poDSIn, int nBandIn)
45✔
113
    : dfMinX(0.0), dfMaxX(0.0), dfMinY(0.0), dfMaxY(0.0), dfMinZ(0.0),
114
      dfMaxZ(0.0), pafRowMinZ(nullptr), pafRowMaxZ(nullptr), nMinZRow(-1),
115
      nMaxZRow(-1)
45✔
116
{
117
    this->poDS = poDSIn;
45✔
118
    this->nBand = nBandIn;
45✔
119

120
    eDataType = GDT_Float32;
45✔
121

122
    nBlockXSize = poDS->GetRasterXSize();
45✔
123
    nBlockYSize = 1;
45✔
124
}
45✔
125

126
/************************************************************************/
127
/*                           ~GSBGRasterBand()                          */
128
/************************************************************************/
129

130
GSBGRasterBand::~GSBGRasterBand()
90✔
131

132
{
133
    if (pafRowMinZ != nullptr)
45✔
134
        CPLFree(pafRowMinZ);
1✔
135
    if (pafRowMaxZ != nullptr)
45✔
136
        CPLFree(pafRowMaxZ);
1✔
137
}
90✔
138

139
/************************************************************************/
140
/*                          ScanForMinMaxZ()                            */
141
/************************************************************************/
142

143
CPLErr GSBGRasterBand::ScanForMinMaxZ()
1✔
144

145
{
146
    float *pafRowVals = (float *)VSI_MALLOC2_VERBOSE(nRasterXSize, 4);
1✔
147

148
    if (pafRowVals == nullptr)
1✔
149
    {
150
        return CE_Failure;
×
151
    }
152

153
    double dfNewMinZ = std::numeric_limits<double>::max();
1✔
154
    double dfNewMaxZ = std::numeric_limits<double>::lowest();
1✔
155
    int nNewMinZRow = 0;
1✔
156
    int nNewMaxZRow = 0;
1✔
157

158
    /* Since we have to scan, lets calc. statistics too */
159
    double dfSum = 0.0;
1✔
160
    double dfSum2 = 0.0;
1✔
161
    unsigned long nValuesRead = 0;
1✔
162
    for (int iRow = 0; iRow < nRasterYSize; iRow++)
21✔
163
    {
164
        CPLErr eErr = IReadBlock(0, iRow, pafRowVals);
20✔
165
        if (eErr != CE_None)
20✔
166
        {
167
            VSIFree(pafRowVals);
×
168
            return CE_Failure;
×
169
        }
170

171
        pafRowMinZ[iRow] = std::numeric_limits<float>::max();
20✔
172
        pafRowMaxZ[iRow] = std::numeric_limits<float>::lowest();
20✔
173
        for (int iCol = 0; iCol < nRasterXSize; iCol++)
420✔
174
        {
175
            if (pafRowVals[iCol] == GSBGDataset::fNODATA_VALUE)
400✔
176
                continue;
400✔
177

178
            if (pafRowVals[iCol] < pafRowMinZ[iRow])
×
179
                pafRowMinZ[iRow] = pafRowVals[iCol];
×
180

181
            if (pafRowVals[iCol] > pafRowMinZ[iRow])
×
182
                pafRowMaxZ[iRow] = pafRowVals[iCol];
×
183

184
            dfSum += pafRowVals[iCol];
×
185
            dfSum2 += static_cast<double>(pafRowVals[iCol]) * pafRowVals[iCol];
×
186
            nValuesRead++;
×
187
        }
188

189
        if (pafRowMinZ[iRow] < dfNewMinZ)
20✔
190
        {
191
            dfNewMinZ = pafRowMinZ[iRow];
1✔
192
            nNewMinZRow = iRow;
1✔
193
        }
194

195
        if (pafRowMaxZ[iRow] > dfNewMaxZ)
20✔
196
        {
197
            dfNewMaxZ = pafRowMaxZ[iRow];
1✔
198
            nNewMaxZRow = iRow;
1✔
199
        }
200
    }
201

202
    VSIFree(pafRowVals);
1✔
203

204
    if (nValuesRead == 0)
1✔
205
    {
206
        dfMinZ = 0.0;
1✔
207
        dfMaxZ = 0.0;
1✔
208
        nMinZRow = 0;
1✔
209
        nMaxZRow = 0;
1✔
210
        return CE_None;
1✔
211
    }
212

213
    dfMinZ = dfNewMinZ;
×
214
    dfMaxZ = dfNewMaxZ;
×
215
    nMinZRow = nNewMinZRow;
×
216
    nMaxZRow = nNewMaxZRow;
×
217

218
    double dfMean = dfSum / nValuesRead;
×
219
    double dfStdDev = sqrt((dfSum2 / nValuesRead) - (dfMean * dfMean));
×
220
    SetStatistics(dfMinZ, dfMaxZ, dfMean, dfStdDev);
×
221

222
    return CE_None;
×
223
}
224

225
/************************************************************************/
226
/*                             IReadBlock()                             */
227
/************************************************************************/
228

229
CPLErr GSBGRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
140✔
230

231
{
232
    if (nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0)
140✔
233
        return CE_Failure;
×
234

235
    GSBGDataset *poGDS = reinterpret_cast<GSBGDataset *>(poDS);
140✔
236
    if (VSIFSeekL(poGDS->fp,
280✔
237
                  GSBGDataset::nHEADER_SIZE +
140✔
238
                      4 * static_cast<vsi_l_offset>(nRasterXSize) *
140✔
239
                          (nRasterYSize - nBlockYOff - 1),
140✔
240
                  SEEK_SET) != 0)
140✔
241
    {
242
        CPLError(CE_Failure, CPLE_FileIO,
×
243
                 "Unable to seek to beginning of grid row.\n");
244
        return CE_Failure;
×
245
    }
246

247
    if (VSIFReadL(pImage, sizeof(float), nBlockXSize, poGDS->fp) !=
140✔
248
        static_cast<unsigned>(nBlockXSize))
140✔
249
    {
250
        CPLError(CE_Failure, CPLE_FileIO,
×
251
                 "Unable to read block from grid file.\n");
252
        return CE_Failure;
×
253
    }
254

255
#ifdef CPL_MSB
256
    float *pfImage = (float *)pImage;
257
    for (int iPixel = 0; iPixel < nBlockXSize; iPixel++)
258
    {
259
        CPL_LSBPTR32(pfImage + iPixel);
260
    }
261
#endif
262

263
    return CE_None;
140✔
264
}
265

266
/************************************************************************/
267
/*                            IWriteBlock()                             */
268
/************************************************************************/
269

270
CPLErr GSBGRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, void *pImage)
20✔
271

272
{
273
    if (eAccess == GA_ReadOnly)
20✔
274
    {
275
        CPLError(CE_Failure, CPLE_NoWriteAccess,
×
276
                 "Unable to write block, dataset opened read only.\n");
277
        return CE_Failure;
×
278
    }
279

280
    if (nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0)
20✔
281
        return CE_Failure;
×
282

283
    GSBGDataset *poGDS = cpl::down_cast<GSBGDataset *>(poDS);
20✔
284

285
    if (pafRowMinZ == nullptr || pafRowMaxZ == nullptr || nMinZRow < 0 ||
20✔
286
        nMaxZRow < 0)
19✔
287
    {
288
        pafRowMinZ = (float *)VSI_MALLOC2_VERBOSE(nRasterYSize, sizeof(float));
1✔
289
        if (pafRowMinZ == nullptr)
1✔
290
        {
291
            return CE_Failure;
×
292
        }
293

294
        pafRowMaxZ = (float *)VSI_MALLOC2_VERBOSE(nRasterYSize, sizeof(float));
1✔
295
        if (pafRowMaxZ == nullptr)
1✔
296
        {
297
            VSIFree(pafRowMinZ);
×
298
            pafRowMinZ = nullptr;
×
299
            return CE_Failure;
×
300
        }
301

302
        CPLErr eErr = ScanForMinMaxZ();
1✔
303
        if (eErr != CE_None)
1✔
304
            return eErr;
×
305
    }
306

307
    if (VSIFSeekL(poGDS->fp,
40✔
308
                  GSBGDataset::nHEADER_SIZE +
20✔
309
                      static_cast<vsi_l_offset>(4) * nRasterXSize *
20✔
310
                          (nRasterYSize - nBlockYOff - 1),
20✔
311
                  SEEK_SET) != 0)
20✔
312
    {
313
        CPLError(CE_Failure, CPLE_FileIO,
×
314
                 "Unable to seek to beginning of grid row.\n");
315
        return CE_Failure;
×
316
    }
317

318
    float *pfImage = (float *)pImage;
20✔
319
    pafRowMinZ[nBlockYOff] = std::numeric_limits<float>::max();
20✔
320
    pafRowMaxZ[nBlockYOff] = std::numeric_limits<float>::lowest();
20✔
321
    for (int iPixel = 0; iPixel < nBlockXSize; iPixel++)
420✔
322
    {
323
        if (pfImage[iPixel] != GSBGDataset::fNODATA_VALUE)
400✔
324
        {
325
            if (pfImage[iPixel] < pafRowMinZ[nBlockYOff])
400✔
326
                pafRowMinZ[nBlockYOff] = pfImage[iPixel];
78✔
327

328
            if (pfImage[iPixel] > pafRowMaxZ[nBlockYOff])
400✔
329
                pafRowMaxZ[nBlockYOff] = pfImage[iPixel];
43✔
330
        }
331

332
        CPL_LSBPTR32(pfImage + iPixel);
400✔
333
    }
334

335
    if (VSIFWriteL(pImage, sizeof(float), nBlockXSize, poGDS->fp) !=
20✔
336
        static_cast<unsigned>(nBlockXSize))
20✔
337
    {
338
        CPLError(CE_Failure, CPLE_FileIO,
×
339
                 "Unable to write block to grid file.\n");
340
        return CE_Failure;
×
341
    }
342

343
    /* Update min/max Z values as appropriate */
344
    bool bHeaderNeedsUpdate = false;
20✔
345
    if (nMinZRow == nBlockYOff && pafRowMinZ[nBlockYOff] > dfMinZ)
20✔
346
    {
347
        double dfNewMinZ = std::numeric_limits<double>::max();
1✔
348
        for (int iRow = 0; iRow < nRasterYSize; iRow++)
21✔
349
        {
350
            if (pafRowMinZ[iRow] < dfNewMinZ)
20✔
351
            {
352
                dfNewMinZ = pafRowMinZ[iRow];
1✔
353
                nMinZRow = iRow;
1✔
354
            }
355
        }
356

357
        if (dfNewMinZ != dfMinZ)
1✔
358
        {
359
            dfMinZ = dfNewMinZ;
1✔
360
            bHeaderNeedsUpdate = true;
1✔
361
        }
362
    }
363

364
    if (nMaxZRow == nBlockYOff && pafRowMaxZ[nBlockYOff] < dfMaxZ)
20✔
365
    {
366
        double dfNewMaxZ = std::numeric_limits<double>::lowest();
×
367
        for (int iRow = 0; iRow < nRasterYSize; iRow++)
×
368
        {
369
            if (pafRowMaxZ[iRow] > dfNewMaxZ)
×
370
            {
371
                dfNewMaxZ = pafRowMaxZ[iRow];
×
372
                nMaxZRow = iRow;
×
373
            }
374
        }
375

376
        if (dfNewMaxZ != dfMaxZ)
×
377
        {
378
            dfMaxZ = dfNewMaxZ;
×
379
            bHeaderNeedsUpdate = true;
×
380
        }
381
    }
382

383
    if (pafRowMinZ[nBlockYOff] < dfMinZ || pafRowMaxZ[nBlockYOff] > dfMaxZ)
20✔
384
    {
385
        if (pafRowMinZ[nBlockYOff] < dfMinZ)
6✔
386
        {
387
            dfMinZ = pafRowMinZ[nBlockYOff];
3✔
388
            nMinZRow = nBlockYOff;
3✔
389
        }
390

391
        if (pafRowMaxZ[nBlockYOff] > dfMaxZ)
6✔
392
        {
393
            dfMaxZ = pafRowMaxZ[nBlockYOff];
4✔
394
            nMaxZRow = nBlockYOff;
4✔
395
        }
396

397
        bHeaderNeedsUpdate = true;
6✔
398
    }
399

400
    if (bHeaderNeedsUpdate && dfMaxZ > dfMinZ)
20✔
401
    {
402
        CPLErr eErr =
403
            poGDS->WriteHeader(poGDS->fp, nRasterXSize, nRasterYSize, dfMinX,
6✔
404
                               dfMaxX, dfMinY, dfMaxY, dfMinZ, dfMaxZ);
405
        return eErr;
6✔
406
    }
407

408
    return CE_None;
14✔
409
}
410

411
/************************************************************************/
412
/*                           GetNoDataValue()                           */
413
/************************************************************************/
414

415
double GSBGRasterBand::GetNoDataValue(int *pbSuccess)
21✔
416
{
417
    if (pbSuccess)
21✔
418
        *pbSuccess = TRUE;
15✔
419

420
    return GSBGDataset::fNODATA_VALUE;
21✔
421
}
422

423
/************************************************************************/
424
/*                             GetMinimum()                             */
425
/************************************************************************/
426

427
double GSBGRasterBand::GetMinimum(int *pbSuccess)
×
428
{
429
    if (pbSuccess)
×
430
        *pbSuccess = TRUE;
×
431

432
    return dfMinZ;
×
433
}
434

435
/************************************************************************/
436
/*                             GetMaximum()                             */
437
/************************************************************************/
438

439
double GSBGRasterBand::GetMaximum(int *pbSuccess)
×
440
{
441
    if (pbSuccess)
×
442
        *pbSuccess = TRUE;
×
443

444
    return dfMaxZ;
×
445
}
446

447
/************************************************************************/
448
/* ==================================================================== */
449
/*                              GSBGDataset                             */
450
/* ==================================================================== */
451
/************************************************************************/
452

453
GSBGDataset::~GSBGDataset()
90✔
454

455
{
456
    FlushCache(true);
45✔
457
    if (fp != nullptr)
45✔
458
        VSIFCloseL(fp);
45✔
459
}
90✔
460

461
/************************************************************************/
462
/*                              Identify()                              */
463
/************************************************************************/
464

465
int GSBGDataset::Identify(GDALOpenInfo *poOpenInfo)
58,412✔
466

467
{
468
    /* Check for signature */
469
    if (poOpenInfo->nHeaderBytes < 4 ||
58,412✔
470
        !STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "DSBB"))
4,625✔
471
    {
472
        return FALSE;
58,322✔
473
    }
474

475
    return TRUE;
90✔
476
}
477

478
/************************************************************************/
479
/*                                Open()                                */
480
/************************************************************************/
481

482
GDALDataset *GSBGDataset::Open(GDALOpenInfo *poOpenInfo)
45✔
483

484
{
485
    if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
45✔
486
    {
487
        return nullptr;
×
488
    }
489

490
    /* -------------------------------------------------------------------- */
491
    /*      Create a corresponding GDALDataset.                             */
492
    /* -------------------------------------------------------------------- */
493
    auto poDS = std::make_unique<GSBGDataset>();
90✔
494

495
    poDS->eAccess = poOpenInfo->eAccess;
45✔
496
    poDS->fp = poOpenInfo->fpL;
45✔
497
    poOpenInfo->fpL = nullptr;
45✔
498

499
    /* -------------------------------------------------------------------- */
500
    /*      Read the header.                                                */
501
    /* -------------------------------------------------------------------- */
502
    if (VSIFSeekL(poDS->fp, 4, SEEK_SET) != 0)
45✔
503
    {
504
        CPLError(CE_Failure, CPLE_FileIO,
×
505
                 "Unable to seek to start of grid file header.\n");
506
        return nullptr;
×
507
    }
508

509
    /* Parse number of X axis grid rows */
510
    GInt16 nTemp;
511
    if (VSIFReadL((void *)&nTemp, 2, 1, poDS->fp) != 1)
45✔
512
    {
513
        CPLError(CE_Failure, CPLE_FileIO, "Unable to read raster X size.\n");
×
514
        return nullptr;
×
515
    }
516
    poDS->nRasterXSize = CPL_LSBWORD16(nTemp);
45✔
517

518
    if (VSIFReadL((void *)&nTemp, 2, 1, poDS->fp) != 1)
45✔
519
    {
520
        CPLError(CE_Failure, CPLE_FileIO, "Unable to read raster Y size.\n");
×
521
        return nullptr;
×
522
    }
523
    poDS->nRasterYSize = CPL_LSBWORD16(nTemp);
45✔
524

525
    if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
45✔
526
    {
527
        return nullptr;
×
528
    }
529

530
    /* -------------------------------------------------------------------- */
531
    /*      Create band information objects.                                */
532
    /* -------------------------------------------------------------------- */
533
    GSBGRasterBand *poBand = new GSBGRasterBand(poDS.get(), 1);
45✔
534
    poDS->SetBand(1, poBand);
45✔
535

536
    double dfTemp;
537
    if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1)
45✔
538
    {
539
        CPLError(CE_Failure, CPLE_FileIO, "Unable to read minimum X value.\n");
×
540
        return nullptr;
×
541
    }
542
    CPL_LSBPTR64(&dfTemp);
45✔
543
    poBand->dfMinX = dfTemp;
45✔
544

545
    if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1)
45✔
546
    {
547
        CPLError(CE_Failure, CPLE_FileIO, "Unable to read maximum X value.\n");
×
548
        return nullptr;
×
549
    }
550
    CPL_LSBPTR64(&dfTemp);
45✔
551
    poBand->dfMaxX = dfTemp;
45✔
552

553
    if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1)
45✔
554
    {
555
        CPLError(CE_Failure, CPLE_FileIO, "Unable to read minimum Y value.\n");
×
556
        return nullptr;
×
557
    }
558
    CPL_LSBPTR64(&dfTemp);
45✔
559
    poBand->dfMinY = dfTemp;
45✔
560

561
    if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1)
45✔
562
    {
563
        CPLError(CE_Failure, CPLE_FileIO, "Unable to read maximum Y value.\n");
×
564
        return nullptr;
×
565
    }
566
    CPL_LSBPTR64(&dfTemp);
45✔
567
    poBand->dfMaxY = dfTemp;
45✔
568

569
    if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1)
45✔
570
    {
571
        CPLError(CE_Failure, CPLE_FileIO, "Unable to read minimum Z value.\n");
×
572
        return nullptr;
×
573
    }
574
    CPL_LSBPTR64(&dfTemp);
45✔
575
    poBand->dfMinZ = dfTemp;
45✔
576

577
    if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1)
45✔
578
    {
579
        CPLError(CE_Failure, CPLE_FileIO, "Unable to read maximum Z value.\n");
×
580
        return nullptr;
×
581
    }
582
    CPL_LSBPTR64(&dfTemp);
45✔
583
    poBand->dfMaxZ = dfTemp;
45✔
584

585
    /* -------------------------------------------------------------------- */
586
    /*      Initialize any PAM information.                                 */
587
    /* -------------------------------------------------------------------- */
588
    poDS->SetDescription(poOpenInfo->pszFilename);
45✔
589
    poDS->TryLoadXML();
45✔
590

591
    /* -------------------------------------------------------------------- */
592
    /*      Check for external overviews.                                   */
593
    /* -------------------------------------------------------------------- */
594
    poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename,
90✔
595
                                poOpenInfo->GetSiblingFiles());
45✔
596

597
    return poDS.release();
45✔
598
}
599

600
/************************************************************************/
601
/*                          GetGeoTransform()                           */
602
/************************************************************************/
603

604
CPLErr GSBGDataset::GetGeoTransform(GDALGeoTransform &gt) const
29✔
605
{
606
    const GSBGRasterBand *poGRB =
607
        cpl::down_cast<const GSBGRasterBand *>(GetRasterBand(1));
29✔
608

609
    /* check if we have a PAM GeoTransform stored */
610
    CPLPushErrorHandler(CPLQuietErrorHandler);
29✔
611
    CPLErr eErr = GDALPamDataset::GetGeoTransform(gt);
29✔
612
    CPLPopErrorHandler();
29✔
613

614
    if (eErr == CE_None)
29✔
615
        return CE_None;
×
616

617
    if (nRasterXSize == 1 || nRasterYSize == 1)
29✔
618
        return CE_Failure;
×
619

620
    /* calculate pixel size first */
621
    gt[1] = (poGRB->dfMaxX - poGRB->dfMinX) / (nRasterXSize - 1);
29✔
622
    gt[5] = (poGRB->dfMinY - poGRB->dfMaxY) / (nRasterYSize - 1);
29✔
623

624
    /* then calculate image origin */
625
    gt[0] = poGRB->dfMinX - gt[1] / 2;
29✔
626
    gt[3] = poGRB->dfMaxY - gt[5] / 2;
29✔
627

628
    /* tilt/rotation does not supported by the GS grids */
629
    gt[4] = 0.0;
29✔
630
    gt[2] = 0.0;
29✔
631

632
    return CE_None;
29✔
633
}
634

635
/************************************************************************/
636
/*                          SetGeoTransform()                           */
637
/************************************************************************/
638

639
CPLErr GSBGDataset::SetGeoTransform(const GDALGeoTransform &gt)
12✔
640
{
641
    if (eAccess == GA_ReadOnly)
12✔
642
    {
643
        CPLError(CE_Failure, CPLE_NoWriteAccess,
×
644
                 "Unable to set GeoTransform, dataset opened read only.\n");
645
        return CE_Failure;
×
646
    }
647

648
    GSBGRasterBand *poGRB = cpl::down_cast<GSBGRasterBand *>(GetRasterBand(1));
12✔
649

650
    /* non-zero transform 2 or 4 or negative 1 or 5 not supported natively */
651
    // CPLErr eErr = CE_None;
652
    /*if( gt[2] != 0.0 || gt[4] != 0.0
653
        || gt[1] < 0.0 || gt[5] < 0.0 )
654
        eErr = GDALPamDataset::SetGeoTransform( gt );
655

656
    if( eErr != CE_None )
657
        return eErr;*/
658

659
    double dfMinX = gt[0] + gt[1] / 2;
12✔
660
    double dfMaxX = gt[1] * (nRasterXSize - 0.5) + gt[0];
12✔
661
    double dfMinY = gt[5] * (nRasterYSize - 0.5) + gt[3];
12✔
662
    double dfMaxY = gt[3] + gt[5] / 2;
12✔
663

664
    CPLErr eErr =
665
        WriteHeader(fp, poGRB->nRasterXSize, poGRB->nRasterYSize, dfMinX,
12✔
666
                    dfMaxX, dfMinY, dfMaxY, poGRB->dfMinZ, poGRB->dfMaxZ);
667

668
    if (eErr == CE_None)
12✔
669
    {
670
        poGRB->dfMinX = dfMinX;
12✔
671
        poGRB->dfMaxX = dfMaxX;
12✔
672
        poGRB->dfMinY = dfMinY;
12✔
673
        poGRB->dfMaxY = dfMaxY;
12✔
674
    }
675

676
    return eErr;
12✔
677
}
678

679
/************************************************************************/
680
/*                             WriteHeader()                            */
681
/************************************************************************/
682

683
CPLErr GSBGDataset::WriteHeader(VSILFILE *fp, int nXSize, int nYSize,
65✔
684
                                double dfMinX, double dfMaxX, double dfMinY,
685
                                double dfMaxY, double dfMinZ, double dfMaxZ)
686

687
{
688
    if (VSIFSeekL(fp, 0, SEEK_SET) != 0)
65✔
689
    {
690
        CPLError(CE_Failure, CPLE_FileIO,
×
691
                 "Unable to seek to start of grid file.\n");
692
        return CE_Failure;
×
693
    }
694

695
    if (VSIFWriteL((void *)"DSBB", 1, 4, fp) != 4)
65✔
696
    {
697
        CPLError(CE_Failure, CPLE_FileIO,
1✔
698
                 "Unable to write signature to grid file.\n");
699
        return CE_Failure;
1✔
700
    }
701

702
    assert(nXSize >= 0 && nXSize <= std::numeric_limits<int16_t>::max());
64✔
703
    GInt16 nTemp = CPL_LSBWORD16(static_cast<int16_t>(nXSize));
64✔
704
    if (VSIFWriteL((void *)&nTemp, 2, 1, fp) != 1)
64✔
705
    {
706
        CPLError(CE_Failure, CPLE_FileIO,
×
707
                 "Unable to write raster X size to grid file.\n");
708
        return CE_Failure;
×
709
    }
710

711
    assert(nYSize >= 0 && nYSize <= std::numeric_limits<int16_t>::max());
64✔
712
    nTemp = CPL_LSBWORD16(static_cast<int16_t>(nYSize));
64✔
713
    if (VSIFWriteL((void *)&nTemp, 2, 1, fp) != 1)
64✔
714
    {
715
        CPLError(CE_Failure, CPLE_FileIO,
×
716
                 "Unable to write raster Y size to grid file.\n");
717
        return CE_Failure;
×
718
    }
719

720
    double dfTemp = dfMinX;
64✔
721
    CPL_LSBPTR64(&dfTemp);
64✔
722
    if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1)
64✔
723
    {
724
        CPLError(CE_Failure, CPLE_FileIO,
×
725
                 "Unable to write minimum X value to grid file.\n");
726
        return CE_Failure;
×
727
    }
728

729
    dfTemp = dfMaxX;
64✔
730
    CPL_LSBPTR64(&dfTemp);
64✔
731
    if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1)
64✔
732
    {
733
        CPLError(CE_Failure, CPLE_FileIO,
×
734
                 "Unable to write maximum X value to grid file.\n");
735
        return CE_Failure;
×
736
    }
737

738
    dfTemp = dfMinY;
64✔
739
    CPL_LSBPTR64(&dfTemp);
64✔
740
    if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1)
64✔
741
    {
742
        CPLError(CE_Failure, CPLE_FileIO,
×
743
                 "Unable to write minimum Y value to grid file.\n");
744
        return CE_Failure;
×
745
    }
746

747
    dfTemp = dfMaxY;
64✔
748
    CPL_LSBPTR64(&dfTemp);
64✔
749
    if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1)
64✔
750
    {
751
        CPLError(CE_Failure, CPLE_FileIO,
×
752
                 "Unable to write maximum Y value to grid file.\n");
753
        return CE_Failure;
×
754
    }
755

756
    dfTemp = dfMinZ;
64✔
757
    CPL_LSBPTR64(&dfTemp);
64✔
758
    if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1)
64✔
759
    {
760
        CPLError(CE_Failure, CPLE_FileIO,
1✔
761
                 "Unable to write minimum Z value to grid file.\n");
762
        return CE_Failure;
1✔
763
    }
764

765
    dfTemp = dfMaxZ;
63✔
766
    CPL_LSBPTR64(&dfTemp);
63✔
767
    if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1)
63✔
768
    {
769
        CPLError(CE_Failure, CPLE_FileIO,
×
770
                 "Unable to write maximum Z value to grid file.\n");
771
        return CE_Failure;
×
772
    }
773

774
    return CE_None;
63✔
775
}
776

777
/************************************************************************/
778
/*                               Create()                               */
779
/************************************************************************/
780

781
GDALDataset *GSBGDataset::Create(const char *pszFilename, int nXSize,
33✔
782
                                 int nYSize, int /* nBands */,
783
                                 GDALDataType eType,
784
                                 CPL_UNUSED char **papszParamList)
785
{
786
    if (nXSize <= 0 || nYSize <= 0)
33✔
787
    {
788
        CPLError(CE_Failure, CPLE_IllegalArg,
×
789
                 "Unable to create grid, both X and Y size must be "
790
                 "non-negative.\n");
791

792
        return nullptr;
×
793
    }
794
    else if (nXSize > std::numeric_limits<short>::max() ||
66✔
795
             nYSize > std::numeric_limits<short>::max())
33✔
796
    {
797
        CPLError(CE_Failure, CPLE_IllegalArg,
×
798
                 "Unable to create grid, Golden Software Binary Grid format "
799
                 "only supports sizes up to %dx%d.  %dx%d not supported.\n",
800
                 std::numeric_limits<short>::max(),
×
801
                 std::numeric_limits<short>::max(), nXSize, nYSize);
×
802

803
        return nullptr;
×
804
    }
805

806
    if (eType != GDT_Byte && eType != GDT_Float32 && eType != GDT_UInt16 &&
33✔
807
        eType != GDT_Int16)
808
    {
809
        CPLError(CE_Failure, CPLE_AppDefined,
20✔
810
                 "Golden Software Binary Grid only supports Byte, Int16, "
811
                 "Uint16, and Float32 datatypes.  Unable to create with "
812
                 "type %s.\n",
813
                 GDALGetDataTypeName(eType));
814

815
        return nullptr;
20✔
816
    }
817

818
    VSILFILE *fp = VSIFOpenL(pszFilename, "w+b");
13✔
819

820
    if (fp == nullptr)
13✔
821
    {
822
        CPLError(CE_Failure, CPLE_OpenFailed,
×
823
                 "Attempt to create file '%s' failed.\n", pszFilename);
824
        return nullptr;
×
825
    }
826

827
    CPLErr eErr =
828
        WriteHeader(fp, nXSize, nYSize, 0.0, nXSize, 0.0, nYSize, 0.0, 0.0);
13✔
829
    if (eErr != CE_None)
13✔
830
    {
831
        VSIFCloseL(fp);
×
832
        return nullptr;
×
833
    }
834

835
    float fVal = fNODATA_VALUE;
13✔
836
    CPL_LSBPTR32(&fVal);
13✔
837
    for (int iRow = 0; iRow < nYSize; iRow++)
1,233✔
838
    {
839
        for (int iCol = 0; iCol < nXSize; iCol++)
121,620✔
840
        {
841
            if (VSIFWriteL((void *)&fVal, 4, 1, fp) != 1)
120,400✔
842
            {
843
                VSIFCloseL(fp);
×
844
                CPLError(CE_Failure, CPLE_FileIO,
×
845
                         "Unable to write grid cell.  Disk full?\n");
846
                return nullptr;
×
847
            }
848
        }
849
    }
850

851
    VSIFCloseL(fp);
13✔
852

853
    return (GDALDataset *)GDALOpen(pszFilename, GA_Update);
13✔
854
}
855

856
/************************************************************************/
857
/*                             CreateCopy()                             */
858
/************************************************************************/
859

860
GDALDataset *GSBGDataset::CreateCopy(const char *pszFilename,
30✔
861
                                     GDALDataset *poSrcDS, int bStrict,
862
                                     CPL_UNUSED char **papszOptions,
863
                                     GDALProgressFunc pfnProgress,
864
                                     void *pProgressData)
865
{
866
    if (pfnProgress == nullptr)
30✔
867
        pfnProgress = GDALDummyProgress;
×
868

869
    int nBands = poSrcDS->GetRasterCount();
30✔
870
    if (nBands == 0)
30✔
871
    {
872
        CPLError(
1✔
873
            CE_Failure, CPLE_NotSupported,
874
            "GSBG driver does not support source dataset with zero band.\n");
875
        return nullptr;
1✔
876
    }
877
    else if (nBands > 1)
29✔
878
    {
879
        if (bStrict)
4✔
880
        {
881
            CPLError(CE_Failure, CPLE_NotSupported,
4✔
882
                     "Unable to create copy, Golden Software Binary Grid "
883
                     "format only supports one raster band.\n");
884
            return nullptr;
4✔
885
        }
886
        else
887
            CPLError(CE_Warning, CPLE_NotSupported,
×
888
                     "Golden Software Binary Grid format only supports one "
889
                     "raster band, first band will be copied.\n");
890
    }
891

892
    GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
25✔
893
    if (poSrcBand->GetXSize() > std::numeric_limits<short>::max() ||
50✔
894
        poSrcBand->GetYSize() > std::numeric_limits<short>::max())
25✔
895
    {
896
        CPLError(CE_Failure, CPLE_IllegalArg,
×
897
                 "Unable to create grid, Golden Software Binary Grid format "
898
                 "only supports sizes up to %dx%d.  %dx%d not supported.\n",
899
                 std::numeric_limits<short>::max(),
×
900
                 std::numeric_limits<short>::max(), poSrcBand->GetXSize(),
×
901
                 poSrcBand->GetYSize());
902

903
        return nullptr;
×
904
    }
905

906
    if (!pfnProgress(0.0, nullptr, pProgressData))
25✔
907
    {
908
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated\n");
×
909
        return nullptr;
×
910
    }
911

912
    VSILFILE *fp = VSIFOpenL(pszFilename, "w+b");
25✔
913

914
    if (fp == nullptr)
25✔
915
    {
916
        CPLError(CE_Failure, CPLE_OpenFailed,
3✔
917
                 "Attempt to create file '%s' failed.\n", pszFilename);
918
        return nullptr;
3✔
919
    }
920

921
    const int nXSize = poSrcBand->GetXSize();
22✔
922
    const int nYSize = poSrcBand->GetYSize();
22✔
923
    GDALGeoTransform gt;
22✔
924
    poSrcDS->GetGeoTransform(gt);
22✔
925

926
    double dfMinX = gt[0] + gt[1] / 2;
22✔
927
    double dfMaxX = gt[1] * (nXSize - 0.5) + gt[0];
22✔
928
    double dfMinY = gt[5] * (nYSize - 0.5) + gt[3];
22✔
929
    double dfMaxY = gt[3] + gt[5] / 2;
22✔
930
    CPLErr eErr = WriteHeader(fp, nXSize, nYSize, dfMinX, dfMaxX, dfMinY,
22✔
931
                              dfMaxY, 0.0, 0.0);
932

933
    if (eErr != CE_None)
22✔
934
    {
935
        VSIFCloseL(fp);
2✔
936
        return nullptr;
2✔
937
    }
938

939
    /* -------------------------------------------------------------------- */
940
    /*      Copy band data.                                                 */
941
    /* -------------------------------------------------------------------- */
942
    float *pfData = (float *)VSI_MALLOC2_VERBOSE(nXSize, sizeof(float));
20✔
943
    if (pfData == nullptr)
20✔
944
    {
945
        VSIFCloseL(fp);
×
946
        return nullptr;
×
947
    }
948

949
    int bSrcHasNDValue;
950
    float fSrcNoDataValue = (float)poSrcBand->GetNoDataValue(&bSrcHasNDValue);
20✔
951
    double dfMinZ = std::numeric_limits<double>::max();
20✔
952
    double dfMaxZ = std::numeric_limits<double>::lowest();
20✔
953
    for (int iRow = nYSize - 1; iRow >= 0; iRow--)
185✔
954
    {
955
        eErr = poSrcBand->RasterIO(GF_Read, 0, iRow, nXSize, 1, pfData, nXSize,
173✔
956
                                   1, GDT_Float32, 0, 0, nullptr);
957

958
        if (eErr != CE_None)
173✔
959
        {
960
            VSIFCloseL(fp);
×
961
            VSIFree(pfData);
×
962
            return nullptr;
×
963
        }
964

965
        for (int iCol = 0; iCol < nXSize; iCol++)
2,103✔
966
        {
967
            if (bSrcHasNDValue && pfData[iCol] == fSrcNoDataValue)
1,930✔
968
            {
969
                pfData[iCol] = fNODATA_VALUE;
×
970
            }
971
            else
972
            {
973
                if (pfData[iCol] > dfMaxZ)
1,930✔
974
                    dfMaxZ = pfData[iCol];
22✔
975

976
                if (pfData[iCol] < dfMinZ)
1,930✔
977
                    dfMinZ = pfData[iCol];
27✔
978
            }
979

980
            CPL_LSBPTR32(pfData + iCol);
1,930✔
981
        }
982

983
        if (VSIFWriteL((void *)pfData, 4, nXSize, fp) !=
173✔
984
            static_cast<unsigned>(nXSize))
173✔
985
        {
986
            VSIFCloseL(fp);
8✔
987
            VSIFree(pfData);
8✔
988
            CPLError(CE_Failure, CPLE_FileIO,
8✔
989
                     "Unable to write grid row. Disk full?\n");
990
            return nullptr;
8✔
991
        }
992

993
        if (!pfnProgress(static_cast<double>(nYSize - iRow) / nYSize, nullptr,
165✔
994
                         pProgressData))
995
        {
996
            VSIFCloseL(fp);
×
997
            VSIFree(pfData);
×
998
            CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
×
999
            return nullptr;
×
1000
        }
1001
    }
1002

1003
    VSIFree(pfData);
12✔
1004

1005
    /* write out the min and max values */
1006
    eErr = WriteHeader(fp, nXSize, nYSize, dfMinX, dfMaxX, dfMinY, dfMaxY,
12✔
1007
                       dfMinZ, dfMaxZ);
1008

1009
    if (eErr != CE_None)
12✔
1010
    {
1011
        VSIFCloseL(fp);
×
1012
        return nullptr;
×
1013
    }
1014

1015
    VSIFCloseL(fp);
12✔
1016

1017
    GDALPamDataset *poDS = (GDALPamDataset *)GDALOpen(pszFilename, GA_Update);
12✔
1018
    if (poDS)
12✔
1019
    {
1020
        poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
12✔
1021
    }
1022
    return poDS;
12✔
1023
}
1024

1025
/************************************************************************/
1026
/*                          GDALRegister_GSBG()                         */
1027
/************************************************************************/
1028

1029
void GDALRegister_GSBG()
1,911✔
1030

1031
{
1032
    if (GDALGetDriverByName("GSBG") != nullptr)
1,911✔
1033
        return;
282✔
1034

1035
    GDALDriver *poDriver = new GDALDriver();
1,629✔
1036

1037
    poDriver->SetDescription("GSBG");
1,629✔
1038
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1,629✔
1039
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
1,629✔
1040
                              "Golden Software Binary Grid (.grd)");
1,629✔
1041
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gsbg.html");
1,629✔
1042
    poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "grd");
1,629✔
1043
    poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
1,629✔
1044
                              "Byte Int16 UInt16 Float32");
1,629✔
1045
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1,629✔
1046

1047
    poDriver->pfnIdentify = GSBGDataset::Identify;
1,629✔
1048
    poDriver->pfnOpen = GSBGDataset::Open;
1,629✔
1049
    poDriver->pfnCreate = GSBGDataset::Create;
1,629✔
1050
    poDriver->pfnCreateCopy = GSBGDataset::CreateCopy;
1,629✔
1051

1052
    GetGDALDriverManager()->RegisterDriver(poDriver);
1,629✔
1053
}
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