• 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

88.62
/frmts/srtmhgt/srtmhgtdataset.cpp
1
/******************************************************************************
2
 *
3
 * Project:  SRTM HGT Driver
4
 * Purpose:  SRTM HGT File Read Support.
5
 *           http://dds.cr.usgs.gov/srtm/version2_1/Documentation/SRTM_Topo.pdf
6
 *           http://www2.jpl.nasa.gov/srtm/faq.html
7
 *           http://dds.cr.usgs.gov/srtm/version2_1
8
 * Authors:  Michael Mazzella, Even Rouault
9
 *
10
 ******************************************************************************
11
 * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
12
 * Copyright (c) 2007-2011, Even Rouault <even dot rouault at spatialys.com>
13
 *
14
 * SPDX-License-Identifier: MIT
15
 ****************************************************************************/
16

17
#include "cpl_port.h"
18
#include "cpl_string.h"
19
#include "gdal_frmts.h"
20
#include "gdal_pam.h"
21
#include "ogr_spatialref.h"
22

23
#include <cmath>
24

25
constexpr GInt16 SRTMHG_NODATA_VALUE = -32768;
26

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

33
class SRTMHGTRasterBand;
34

35
class SRTMHGTDataset final : public GDALPamDataset
36
{
37
    friend class SRTMHGTRasterBand;
38

39
    VSILFILE *fpImage = nullptr;
40
    GDALGeoTransform m_gt{};
41
    GByte *pabyBuffer = nullptr;
42
    OGRSpatialReference m_oSRS{};
43

44
    static GDALPamDataset *OpenPAM(GDALOpenInfo *);
45

46
  public:
47
    SRTMHGTDataset();
48
    virtual ~SRTMHGTDataset();
49

50
    const OGRSpatialReference *GetSpatialRef() const override;
51
    virtual CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
52

53
    static int Identify(GDALOpenInfo *poOpenInfo);
54
    static GDALDataset *Open(GDALOpenInfo *);
55
    static GDALDataset *CreateCopy(const char *pszFilename,
56
                                   GDALDataset *poSrcDS, int bStrict,
57
                                   char **papszOptions,
58
                                   GDALProgressFunc pfnProgress,
59
                                   void *pProgressData);
60
};
61

62
/************************************************************************/
63
/* ==================================================================== */
64
/*                            SRTMHGTRasterBand                             */
65
/* ==================================================================== */
66
/************************************************************************/
67

68
class SRTMHGTRasterBand final : public GDALPamRasterBand
69
{
70
    friend class SRTMHGTDataset;
71

72
    int bNoDataSet;
73
    double dfNoDataValue;
74

75
  public:
76
    SRTMHGTRasterBand(SRTMHGTDataset *, int, GDALDataType);
77

78
    virtual CPLErr IReadBlock(int, int, void *) override;
79
    virtual CPLErr IWriteBlock(int nBlockXOff, int nBlockYOff,
80
                               void *pImage) override;
81

82
    virtual GDALColorInterp GetColorInterpretation() override;
83

84
    virtual double GetNoDataValue(int *pbSuccess = nullptr) override;
85

86
    virtual const char *GetUnitType() override;
87
};
88

89
/************************************************************************/
90
/*                         SRTMHGTRasterBand()                          */
91
/************************************************************************/
92

93
SRTMHGTRasterBand::SRTMHGTRasterBand(SRTMHGTDataset *poDSIn, int nBandIn,
24✔
94
                                     GDALDataType eDT)
24✔
95
    : bNoDataSet(TRUE), dfNoDataValue(SRTMHG_NODATA_VALUE)
24✔
96
{
97
    poDS = poDSIn;
24✔
98
    nBand = nBandIn;
24✔
99
    eDataType = eDT;
24✔
100
    nBlockXSize = poDSIn->nRasterXSize;
24✔
101
    nBlockYSize = 1;
24✔
102
}
24✔
103

104
/************************************************************************/
105
/*                             IReadBlock()                             */
106
/************************************************************************/
107

108
CPLErr SRTMHGTRasterBand::IReadBlock(int /*nBlockXOff*/, int nBlockYOff,
37,214✔
109
                                     void *pImage)
110
{
111
    SRTMHGTDataset *poGDS = reinterpret_cast<SRTMHGTDataset *>(poDS);
37,214✔
112

113
    /* -------------------------------------------------------------------- */
114
    /*      Load the desired data into the working buffer.                  */
115
    /* -------------------------------------------------------------------- */
116
    const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
37,214✔
117
    VSIFSeekL(poGDS->fpImage,
37,214✔
118
              static_cast<size_t>(nBlockYOff) * nBlockXSize * nDTSize,
37,214✔
119
              SEEK_SET);
120
    VSIFReadL((unsigned char *)pImage, nBlockXSize, nDTSize, poGDS->fpImage);
37,214✔
121
#ifdef CPL_LSB
122
    GDALSwapWords(pImage, nDTSize, nBlockXSize, nDTSize);
37,214✔
123
#endif
124

125
    return CE_None;
37,214✔
126
}
127

128
/************************************************************************/
129
/*                             IWriteBlock()                            */
130
/************************************************************************/
131

132
CPLErr SRTMHGTRasterBand::IWriteBlock(int /*nBlockXOff*/, int nBlockYOff,
1,201✔
133
                                      void *pImage)
134
{
135
    SRTMHGTDataset *poGDS = reinterpret_cast<SRTMHGTDataset *>(poDS);
1,201✔
136

137
    if (poGDS->eAccess != GA_Update)
1,201✔
138
        return CE_Failure;
×
139

140
    const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
1,201✔
141
    VSIFSeekL(poGDS->fpImage,
1,201✔
142
              static_cast<size_t>(nBlockYOff) * nBlockXSize * nDTSize,
1,201✔
143
              SEEK_SET);
144

145
#ifdef CPL_LSB
146
    if (nDTSize > 1)
1,201✔
147
    {
148
        memcpy(poGDS->pabyBuffer, pImage,
1,201✔
149
               static_cast<size_t>(nBlockXSize) * nDTSize);
1,201✔
150
        GDALSwapWords(poGDS->pabyBuffer, nDTSize, nBlockXSize, nDTSize);
1,201✔
151
        VSIFWriteL(reinterpret_cast<unsigned char *>(poGDS->pabyBuffer),
1,201✔
152
                   nBlockXSize, nDTSize, poGDS->fpImage);
1,201✔
153
    }
154
    else
155
#endif
156
    {
157
        VSIFWriteL(reinterpret_cast<unsigned char *>(pImage), nBlockXSize,
×
158
                   nDTSize, poGDS->fpImage);
159
    }
160

161
    return CE_None;
1,201✔
162
}
163

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

168
double SRTMHGTRasterBand::GetNoDataValue(int *pbSuccess)
41✔
169

170
{
171
    if (eDataType == GDT_Byte)
41✔
172
        return GDALPamRasterBand::GetNoDataValue(pbSuccess);
3✔
173

174
    if (pbSuccess)
38✔
175
        *pbSuccess = bNoDataSet;
30✔
176

177
    return dfNoDataValue;
38✔
178
}
179

180
/************************************************************************/
181
/*                             GetUnitType()                            */
182
/************************************************************************/
183

184
const char *SRTMHGTRasterBand::GetUnitType()
24✔
185
{
186
    const std::string osExt = CPLGetExtensionSafe(poDS->GetDescription());
48✔
187
    const char *pszExt = osExt.c_str();
24✔
188
    if (EQUAL(pszExt, "err") || EQUAL(pszExt, "img") || EQUAL(pszExt, "num") ||
24✔
189
        EQUAL(pszExt, "swb"))
24✔
190
    {
191
        return "";
×
192
    }
193
    return "m";
24✔
194
}
195

196
/************************************************************************/
197
/*                       GetColorInterpretation()                       */
198
/************************************************************************/
199

200
GDALColorInterp SRTMHGTRasterBand::GetColorInterpretation()
11✔
201
{
202
    return GCI_Undefined;
11✔
203
}
204

205
/************************************************************************/
206
/* ==================================================================== */
207
/*                             SRTMHGTDataset                               */
208
/* ==================================================================== */
209
/************************************************************************/
210

211
/************************************************************************/
212
/*                            SRTMHGTDataset()                              */
213
/************************************************************************/
214

215
SRTMHGTDataset::SRTMHGTDataset()
24✔
216
{
217
    m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
24✔
218
    if (CPLTestBool(CPLGetConfigOption("REPORT_COMPD_CS", "NO")))
24✔
219
    {
220
        m_oSRS.importFromWkt(
×
221
            "COMPD_CS[\"WGS 84 + EGM96 geoid height\", GEOGCS[\"WGS 84\", "
222
            "DATUM[\"WGS_1984\", SPHEROID[\"WGS 84\",6378137,298.257223563, "
223
            "AUTHORITY[\"EPSG\",\"7030\"]], AUTHORITY[\"EPSG\",\"6326\"]], "
224
            "PRIMEM[\"Greenwich\",0, AUTHORITY[\"EPSG\",\"8901\"]], "
225
            "UNIT[\"degree\",0.0174532925199433, "
226
            "AUTHORITY[\"EPSG\",\"9122\"]], AUTHORITY[\"EPSG\",\"4326\"]], "
227
            "VERT_CS[\"EGM96 geoid height\", VERT_DATUM[\"EGM96 geoid\",2005, "
228
            "AUTHORITY[\"EPSG\",\"5171\"]], UNIT[\"metre\",1, "
229
            "AUTHORITY[\"EPSG\",\"9001\"]], AXIS[\"Up\",UP], "
230
            "AUTHORITY[\"EPSG\",\"5773\"]]]");
231
    }
232
    else
233
    {
234
        m_oSRS.importFromWkt(SRS_WKT_WGS84_LAT_LONG);
24✔
235
    }
236
}
24✔
237

238
/************************************************************************/
239
/*                           ~SRTMHGTDataset()                            */
240
/************************************************************************/
241

242
SRTMHGTDataset::~SRTMHGTDataset()
48✔
243
{
244
    FlushCache(true);
24✔
245
    if (fpImage != nullptr)
24✔
246
        VSIFCloseL(fpImage);
24✔
247
    CPLFree(pabyBuffer);
24✔
248
}
48✔
249

250
/************************************************************************/
251
/*                          GetGeoTransform()                           */
252
/************************************************************************/
253

254
CPLErr SRTMHGTDataset::GetGeoTransform(GDALGeoTransform &gt) const
33✔
255
{
256
    gt = m_gt;
33✔
257
    return CE_None;
33✔
258
}
259

260
/************************************************************************/
261
/*                          GetSpatialRef()                             */
262
/************************************************************************/
263

264
const OGRSpatialReference *SRTMHGTDataset::GetSpatialRef() const
27✔
265

266
{
267
    return &m_oSRS;
27✔
268
}
269

270
/************************************************************************/
271
/*                              Identify()                              */
272
/************************************************************************/
273

274
int SRTMHGTDataset::Identify(GDALOpenInfo *poOpenInfo)
60,831✔
275

276
{
277
    const char *fileName = CPLGetFilename(poOpenInfo->pszFilename);
60,831✔
278
    if (strlen(fileName) < 11 || fileName[7] != '.')
60,832✔
279
        return FALSE;
57,384✔
280
    CPLString osLCFilename(CPLString(fileName).tolower());
6,896✔
281
    if ((osLCFilename[0] != 'n' && osLCFilename[0] != 's') ||
3,929✔
282
        (osLCFilename[3] != 'e' && osLCFilename[3] != 'w'))
481✔
283
        return FALSE;
3,318✔
284
    if (!STARTS_WITH(fileName, "/vsizip/") && osLCFilename.endsWith(".hgt.zip"))
130✔
285
    {
286
        CPLString osNewName("/vsizip/");
4✔
287
        osNewName += poOpenInfo->pszFilename;
2✔
288
        osNewName += "/";
2✔
289
        osNewName += CPLString(fileName).substr(0, 7);
2✔
290
        osNewName += ".hgt";
2✔
291
        GDALOpenInfo oOpenInfo(osNewName, GA_ReadOnly);
4✔
292
        return Identify(&oOpenInfo);
2✔
293
    }
294

295
    if (!STARTS_WITH(fileName, "/vsizip/") &&
256✔
296
        osLCFilename.endsWith(".srtmswbd.raw.zip"))
256✔
297
    {
298
        CPLString osNewName("/vsizip/");
4✔
299
        osNewName += poOpenInfo->pszFilename;
2✔
300
        osNewName += "/";
2✔
301
        osNewName += CPLString(fileName).substr(0, 7);
2✔
302
        osNewName += ".raw";
2✔
303
        GDALOpenInfo oOpenInfo(osNewName, GA_ReadOnly);
4✔
304
        return Identify(&oOpenInfo);
2✔
305
    }
306

307
    // .hgts and .err files from
308
    // https://e4ftl01.cr.usgs.gov/MEASURES/NASADEM_SHHP.001/2000.02.11/ .img
309
    // and .img.num files from
310
    // https://e4ftl01.cr.usgs.gov/MEASURES/NASADEM_SIM.001/2000.02.11/
311
    if (!osLCFilename.endsWith(".hgt") && !osLCFilename.endsWith(".hgts") &&
257✔
312
        !osLCFilename.endsWith(".err") && !osLCFilename.endsWith(".img") &&
129✔
313
        !osLCFilename.endsWith(".num") &&  // .img.num or .num
129✔
314
        !osLCFilename.endsWith(".raw") &&
129✔
315
        !osLCFilename.endsWith(
126✔
316
            ".swb") &&  // https://e4ftl01.cr.usgs.gov/MEASURES/NASADEM_HGT.001/2000.02.11/
257✔
317
        !osLCFilename.endsWith(".hgt.gz"))
126✔
318
        return FALSE;
×
319

320
    /* -------------------------------------------------------------------- */
321
    /*      We check the file size to see if it is                          */
322
    /*      SRTM1 (below or above lat 50) or SRTM 3                         */
323
    /* -------------------------------------------------------------------- */
324
    VSIStatBufL fileStat;
325

326
    if (VSIStatL(poOpenInfo->pszFilename, &fileStat) != 0)
126✔
327
        return FALSE;
87✔
328
    if (fileStat.st_size != 1201 * 1201 * 2 &&
39✔
329
        fileStat.st_size != 1801 * 3601 * 2 &&
20✔
330
        fileStat.st_size != 3601 * 3601 &&
17✔
331
        fileStat.st_size != 3601 * 3601 * 2 &&
12✔
332
        fileStat.st_size != 3601 * 3601 * 4 &&  // .hgts
7✔
333
        fileStat.st_size != 7201 * 7201 * 2)
3✔
334
        return FALSE;
×
335

336
    return TRUE;
39✔
337
}
338

339
/************************************************************************/
340
/*                                Open()                                */
341
/************************************************************************/
342

343
GDALDataset *SRTMHGTDataset::Open(GDALOpenInfo *poOpenInfo)
13✔
344
{
345
    return OpenPAM(poOpenInfo);
13✔
346
}
347

348
/************************************************************************/
349
/*                              OpenPAM()                               */
350
/************************************************************************/
351

352
GDALPamDataset *SRTMHGTDataset::OpenPAM(GDALOpenInfo *poOpenInfo)
26✔
353
{
354
    if (!Identify(poOpenInfo))
26✔
355
        return nullptr;
×
356

357
    const char *fileName = CPLGetFilename(poOpenInfo->pszFilename);
26✔
358
    CPLString osLCFilename(CPLString(fileName).tolower());
52✔
359
    if (!STARTS_WITH(fileName, "/vsizip/") && osLCFilename.endsWith(".hgt.zip"))
26✔
360
    {
361
        CPLString osFilename("/vsizip/");
2✔
362
        osFilename += poOpenInfo->pszFilename;
1✔
363
        osFilename += "/";
1✔
364
        osFilename += CPLString(fileName).substr(0, 7);
1✔
365
        osFilename += ".hgt";
1✔
366
        GDALOpenInfo oOpenInfo(osFilename, poOpenInfo->eAccess);
1✔
367
        auto poDS = OpenPAM(&oOpenInfo);
1✔
368
        if (poDS != nullptr)
1✔
369
        {
370
            // override description with the main one
371
            poDS->SetDescription(poOpenInfo->pszFilename);
1✔
372
        }
373
        return poDS;
1✔
374
    }
375

376
    if (!STARTS_WITH(fileName, "/vsizip/") &&
50✔
377
        osLCFilename.endsWith(".srtmswbd.raw.zip"))
50✔
378
    {
379
        CPLString osFilename("/vsizip/");
2✔
380
        osFilename += poOpenInfo->pszFilename;
1✔
381
        osFilename += "/";
1✔
382
        osFilename += CPLString(fileName).substr(0, 7);
1✔
383
        osFilename += ".raw";
1✔
384
        GDALOpenInfo oOpenInfo(osFilename, poOpenInfo->eAccess);
1✔
385
        auto poDS = OpenPAM(&oOpenInfo);
1✔
386
        if (poDS != nullptr)
1✔
387
        {
388
            // override description with the main one
389
            poDS->SetDescription(poOpenInfo->pszFilename);
1✔
390
        }
391
        return poDS;
1✔
392
    }
393

394
    char latLonValueString[4];
395
    memset(latLonValueString, 0, 4);
24✔
396
    strncpy(latLonValueString, &fileName[1], 2);
24✔
397
    int southWestLat = atoi(latLonValueString);
24✔
398
    memset(latLonValueString, 0, 4);
24✔
399
    // cppcheck-suppress redundantCopy
400
    strncpy(latLonValueString, &fileName[4], 3);
24✔
401
    int southWestLon = atoi(latLonValueString);
24✔
402

403
    if (fileName[0] == 'N' || fileName[0] == 'n')
24✔
404
        /*southWestLat = southWestLat */;
405
    else if (fileName[0] == 'S' || fileName[0] == 's')
×
406
        southWestLat = southWestLat * -1;
×
407
    else
408
        return nullptr;
×
409

410
    if (fileName[3] == 'E' || fileName[3] == 'e')
24✔
411
        /*southWestLon = southWestLon */;
412
    else if (fileName[3] == 'W' || fileName[3] == 'w')
11✔
413
        southWestLon = southWestLon * -1;
11✔
414
    else
415
        return nullptr;
×
416

417
    /* -------------------------------------------------------------------- */
418
    /*      Create a corresponding GDALDataset.                             */
419
    /* -------------------------------------------------------------------- */
420
    auto poDS = std::make_unique<SRTMHGTDataset>();
48✔
421

422
    poDS->fpImage = poOpenInfo->fpL;
24✔
423
    poOpenInfo->fpL = nullptr;
24✔
424

425
    VSIStatBufL fileStat;
426
    if (VSIStatL(poOpenInfo->pszFilename, &fileStat) != 0)
24✔
427
    {
428
        return nullptr;
×
429
    }
430

431
    int numPixels_x, numPixels_y;
432

433
    GDALDataType eDT = GDT_Int16;
24✔
434
    switch (fileStat.st_size)
24✔
435
    {
436
        case 1201 * 1201 * 2:
12✔
437
            numPixels_x = numPixels_y = 1201;
12✔
438
            break;
12✔
439
        case 1801 * 3601 * 2:
2✔
440
            numPixels_x = 1801;
2✔
441
            numPixels_y = 3601;
2✔
442
            break;
2✔
443
        case 3601 * 3601:
2✔
444
            numPixels_x = numPixels_y = 3601;
2✔
445
            eDT = GDT_Byte;
2✔
446
            break;
2✔
447
        case 3601 * 3601 * 2:
4✔
448
            numPixels_x = numPixels_y = 3601;
4✔
449
            break;
4✔
450
        case 3601 * 3601 * 4:  // .hgts
2✔
451
            numPixels_x = numPixels_y = 3601;
2✔
452
            eDT = GDT_Float32;
2✔
453
            break;
2✔
454
        case 7201 * 7201 * 2:
2✔
455
            numPixels_x = numPixels_y = 7201;
2✔
456
            break;
2✔
457
        default:
×
458
            numPixels_x = numPixels_y = 0;
×
459
            break;
×
460
    }
461

462
    poDS->eAccess = poOpenInfo->eAccess;
24✔
463
#ifdef CPL_LSB
464
    if (poDS->eAccess == GA_Update && eDT != GDT_Byte)
24✔
465
    {
466
        poDS->pabyBuffer =
1✔
467
            static_cast<GByte *>(CPLMalloc(numPixels_x * sizeof(eDT)));
1✔
468
    }
469
#endif
470

471
    /* -------------------------------------------------------------------- */
472
    /*      Capture some information from the file that is of interest.     */
473
    /* -------------------------------------------------------------------- */
474
    poDS->nRasterXSize = numPixels_x;
24✔
475
    poDS->nRasterYSize = numPixels_y;
24✔
476
    poDS->nBands = 1;
24✔
477

478
    poDS->m_gt[0] = southWestLon - 0.5 / (numPixels_x - 1);
24✔
479
    poDS->m_gt[1] = 1.0 / (numPixels_x - 1);
24✔
480
    poDS->m_gt[2] = 0.0;
24✔
481
    poDS->m_gt[3] = southWestLat + 1 + 0.5 / (numPixels_y - 1);
24✔
482
    poDS->m_gt[4] = 0.0;
24✔
483
    poDS->m_gt[5] = -1.0 / (numPixels_y - 1);
24✔
484

485
    poDS->SetMetadataItem(GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT);
24✔
486

487
    /* -------------------------------------------------------------------- */
488
    /*      Create band information object.                                 */
489
    /* -------------------------------------------------------------------- */
490
    SRTMHGTRasterBand *tmpBand = new SRTMHGTRasterBand(poDS.get(), 1, eDT);
24✔
491
    poDS->SetBand(1, tmpBand);
24✔
492

493
    /* -------------------------------------------------------------------- */
494
    /*      Initialize any PAM information.                                 */
495
    /* -------------------------------------------------------------------- */
496
    poDS->SetDescription(poOpenInfo->pszFilename);
24✔
497
    poDS->TryLoadXML();
24✔
498

499
    /* -------------------------------------------------------------------- */
500
    /*      Support overviews.                                              */
501
    /* -------------------------------------------------------------------- */
502
    poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
24✔
503

504
    return poDS.release();
24✔
505
}
506

507
/************************************************************************/
508
/*                              CreateCopy()                            */
509
/************************************************************************/
510

511
GDALDataset *SRTMHGTDataset::CreateCopy(const char *pszFilename,
29✔
512
                                        GDALDataset *poSrcDS, int bStrict,
513
                                        char ** /* papszOptions*/,
514
                                        GDALProgressFunc pfnProgress,
515
                                        void *pProgressData)
516
{
517
    /* -------------------------------------------------------------------- */
518
    /*      Some some rudimentary checks                                    */
519
    /* -------------------------------------------------------------------- */
520
    const int nBands = poSrcDS->GetRasterCount();
29✔
521
    if (nBands == 0)
29✔
522
    {
523
        CPLError(
1✔
524
            CE_Failure, CPLE_NotSupported,
525
            "SRTMHGT driver does not support source dataset with zero band.\n");
526
        return nullptr;
1✔
527
    }
528
    else if (nBands != 1)
28✔
529
    {
530
        CPLError((bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
4✔
531
                 "SRTMHGT driver only uses the first band of the dataset.\n");
532
        if (bStrict)
4✔
533
            return nullptr;
4✔
534
    }
535

536
    /* -------------------------------------------------------------------- */
537
    /*      Checks the input SRS                                            */
538
    /* -------------------------------------------------------------------- */
539
    OGRSpatialReference ogrsr_input;
48✔
540
    ogrsr_input.importFromWkt(poSrcDS->GetProjectionRef());
24✔
541

542
    OGRSpatialReference ogrsr_wgs84;
48✔
543
    ogrsr_wgs84.SetWellKnownGeogCS("WGS84");
24✔
544

545
    if (ogrsr_input.IsSameGeogCS(&ogrsr_wgs84) == FALSE)
24✔
546
    {
547
        CPLError(CE_Warning, CPLE_AppDefined,
×
548
                 "The source projection coordinate system is %s. Only WGS 84 "
549
                 "is supported.\nThe SRTMHGT driver will generate a file as "
550
                 "if the source was WGS 84 projection coordinate system.",
551
                 poSrcDS->GetProjectionRef());
552
    }
553

554
    /* -------------------------------------------------------------------- */
555
    /*      Work out the LL origin.                                         */
556
    /* -------------------------------------------------------------------- */
557
    GDALGeoTransform gt;
24✔
558
    if (poSrcDS->GetGeoTransform(gt) != CE_None)
24✔
559
    {
560
        CPLError(CE_Failure, CPLE_AppDefined,
×
561
                 "Source image must have a geo transform matrix.");
562
        return nullptr;
×
563
    }
564

565
    const int nLLOriginLat = static_cast<int>(
566
        std::floor(gt[3] + poSrcDS->GetRasterYSize() * gt[5] + 0.5));
24✔
567

568
    int nLLOriginLong = static_cast<int>(std::floor(gt[0] + 0.5));
24✔
569

570
    if (std::abs(nLLOriginLat -
72✔
571
                 (gt[3] + (poSrcDS->GetRasterYSize() - 0.5) * gt[5])) > 1e-10 ||
35✔
572
        std::abs(nLLOriginLong - (gt[0] + 0.5 * gt[1])) > 1e-10)
11✔
573
    {
574
        CPLError(CE_Warning, CPLE_AppDefined,
13✔
575
                 "The corner coordinates of the source are not properly "
576
                 "aligned on plain latitude/longitude boundaries.");
577
    }
578

579
    /* -------------------------------------------------------------------- */
580
    /*      Check image dimensions.                                         */
581
    /* -------------------------------------------------------------------- */
582
    const int nXSize = poSrcDS->GetRasterXSize();
24✔
583
    const int nYSize = poSrcDS->GetRasterYSize();
24✔
584

585
    if (!((nXSize == 1201 && nYSize == 1201) ||
36✔
586
          (nXSize == 1801 && nYSize == 3601) ||
16✔
587
          (nXSize == 3601 && nYSize == 3601) ||
3✔
588
          (nXSize == 7201 && nYSize == 7201)))
1✔
589
    {
590
        CPLError(CE_Failure, CPLE_AppDefined,
11✔
591
                 "Image dimensions should be 1201x1201, 1801x3601, 3601x3601 "
592
                 "or 7201x7201.");
593
        return nullptr;
11✔
594
    }
595

596
    /* -------------------------------------------------------------------- */
597
    /*      Check filename.                                                 */
598
    /* -------------------------------------------------------------------- */
599
    char expectedFileName[12];
600

601
    CPLsnprintf(expectedFileName, sizeof(expectedFileName), "%c%02d%c%03d.HGT",
26✔
602
                (nLLOriginLat >= 0) ? 'N' : 'S',
603
                (nLLOriginLat >= 0) ? nLLOriginLat : -nLLOriginLat,
13✔
604
                (nLLOriginLong >= 0) ? 'E' : 'W',
605
                (nLLOriginLong >= 0) ? nLLOriginLong : -nLLOriginLong);
606

607
    if (!EQUAL(expectedFileName, CPLGetFilename(pszFilename)))
13✔
608
    {
609
        CPLError(CE_Warning, CPLE_AppDefined, "Expected output filename is %s.",
×
610
                 expectedFileName);
611
    }
612

613
    /* -------------------------------------------------------------------- */
614
    /*      Write output file.                                              */
615
    /* -------------------------------------------------------------------- */
616
    VSILFILE *fp = VSIFOpenL(pszFilename, "wb");
13✔
617
    if (fp == nullptr)
13✔
618
    {
619
        CPLError(CE_Failure, CPLE_FileIO, "Cannot create file %s", pszFilename);
2✔
620
        return nullptr;
2✔
621
    }
622

623
    GInt16 *panData =
624
        reinterpret_cast<GInt16 *>(CPLMalloc(sizeof(GInt16) * nXSize));
11✔
625
    GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
11✔
626

627
    int bSrcBandHasNoData;
628
    double srcBandNoData = poSrcBand->GetNoDataValue(&bSrcBandHasNoData);
11✔
629

630
    for (int iY = 0; iY < nYSize; iY++)
28,822✔
631
    {
632
        if (poSrcBand->RasterIO(GF_Read, 0, iY, nXSize, 1,
28,811✔
633
                                reinterpret_cast<void *>(panData), nXSize, 1,
634
                                GDT_Int16, 0, 0, nullptr) != CE_None)
28,811✔
635
        {
636
            VSIFCloseL(fp);
×
637
            CPLFree(panData);
×
638
            return nullptr;
×
639
        }
640

641
        /* Translate nodata values */
642
        if (bSrcBandHasNoData && srcBandNoData != SRTMHG_NODATA_VALUE)
28,811✔
643
        {
644
            for (int iX = 0; iX < nXSize; iX++)
×
645
            {
646
                if (panData[iX] == srcBandNoData)
×
647
                    panData[iX] = SRTMHG_NODATA_VALUE;
×
648
            }
649
        }
650

651
#ifdef CPL_LSB
652
        GDALSwapWords(panData, 2, nXSize, 2);
28,811✔
653
#endif
654

655
        if (VSIFWriteL(panData, sizeof(GInt16) * nXSize, 1, fp) != 1)
28,811✔
656
        {
657
            CPLError(CE_Failure, CPLE_FileIO,
×
658
                     "Failed to write line %d in SRTMHGT dataset.\n", iY);
659
            VSIFCloseL(fp);
×
660
            CPLFree(panData);
×
661
            return nullptr;
×
662
        }
663

664
        if (pfnProgress && !pfnProgress((iY + 1) / static_cast<double>(nYSize),
28,811✔
665
                                        nullptr, pProgressData))
666
        {
667
            CPLError(CE_Failure, CPLE_UserInterrupt,
×
668
                     "User terminated CreateCopy()");
669
            VSIFCloseL(fp);
×
670
            CPLFree(panData);
×
671
            return nullptr;
×
672
        }
673
    }
674

675
    CPLFree(panData);
11✔
676
    VSIFCloseL(fp);
11✔
677

678
    /* -------------------------------------------------------------------- */
679
    /*      Reopen and copy missing information into a PAM file.            */
680
    /* -------------------------------------------------------------------- */
681
    GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
11✔
682
    auto poDS = OpenPAM(&oOpenInfo);
11✔
683

684
    if (poDS)
11✔
685
        poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
11✔
686

687
    return poDS;
11✔
688
}
689

690
/************************************************************************/
691
/*                         GDALRegister_SRTMHGT()                       */
692
/************************************************************************/
693
void GDALRegister_SRTMHGT()
1,911✔
694
{
695
    if (GDALGetDriverByName("SRTMHGT") != nullptr)
1,911✔
696
        return;
282✔
697

698
    GDALDriver *poDriver = new GDALDriver();
1,629✔
699

700
    poDriver->SetDescription("SRTMHGT");
1,629✔
701
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1,629✔
702
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "SRTMHGT File Format");
1,629✔
703
    poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "hgt");
1,629✔
704
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
1,629✔
705
                              "drivers/raster/srtmhgt.html");
1,629✔
706
    poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte Int16 UInt16");
1,629✔
707
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1,629✔
708

709
    poDriver->pfnIdentify = SRTMHGTDataset::Identify;
1,629✔
710
    poDriver->pfnOpen = SRTMHGTDataset::Open;
1,629✔
711
    poDriver->pfnCreateCopy = SRTMHGTDataset::CreateCopy;
1,629✔
712

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