• 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

72.51
/frmts/raw/hkvdataset.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GView
4
 * Purpose:  Implementation of Atlantis HKV labelled blob support
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2000, Frank Warmerdam
9
 * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13

14
#include <ctype.h>
15

16
#include "atlsci_spheroid.h"
17
#include "cpl_string.h"
18
#include "gdal_frmts.h"
19
#include "ogr_spatialref.h"
20
#include "rawdataset.h"
21

22
#include <cmath>
23

24
#include <algorithm>
25

26
/************************************************************************/
27
/* ==================================================================== */
28
/*                            HKVRasterBand                             */
29
/* ==================================================================== */
30
/************************************************************************/
31

32
class HKVDataset;
33

34
class HKVRasterBand final : public RawRasterBand
2✔
35
{
36
    friend class HKVDataset;
37

38
  public:
39
    HKVRasterBand(HKVDataset *poDS, int nBand, VSILFILE *fpRaw,
40
                  unsigned int nImgOffset, int nPixelOffset, int nLineOffset,
41
                  GDALDataType eDataType, int bNativeOrder);
42

43
    ~HKVRasterBand() override;
44
};
45

46
HKVRasterBand::~HKVRasterBand() = default;
47

48
/************************************************************************/
49
/*                      HKV Spheroids                                   */
50
/************************************************************************/
51

52
class HKVSpheroidList : public SpheroidList
53
{
54
  public:
55
    HKVSpheroidList();
56

57
    ~HKVSpheroidList()
1✔
58
    {
1✔
59
    }
1✔
60
};
61

62
HKVSpheroidList ::HKVSpheroidList()
1✔
63
{
64
    num_spheroids = 58;
1✔
65
    epsilonR = 0.1;
1✔
66
    epsilonI = 0.000001;
1✔
67

68
    spheroids[0].SetValuesByEqRadiusAndInvFlattening("airy-1830", 6377563.396,
1✔
69
                                                     299.3249646);
70
    spheroids[1].SetValuesByEqRadiusAndInvFlattening("modified-airy",
1✔
71
                                                     6377340.189, 299.3249646);
72
    spheroids[2].SetValuesByEqRadiusAndInvFlattening("australian-national",
1✔
73
                                                     6378160, 298.25);
74
    spheroids[3].SetValuesByEqRadiusAndInvFlattening("bessel-1841-namibia",
1✔
75
                                                     6377483.865, 299.1528128);
76
    spheroids[4].SetValuesByEqRadiusAndInvFlattening("bessel-1841", 6377397.155,
1✔
77
                                                     299.1528128);
78
    spheroids[5].SetValuesByEqRadiusAndInvFlattening("clarke-1858", 6378294.0,
1✔
79
                                                     294.297);
80
    spheroids[6].SetValuesByEqRadiusAndInvFlattening("clarke-1866", 6378206.4,
1✔
81
                                                     294.9786982);
82
    spheroids[7].SetValuesByEqRadiusAndInvFlattening("clarke-1880", 6378249.145,
1✔
83
                                                     293.465);
84
    spheroids[8].SetValuesByEqRadiusAndInvFlattening("everest-india-1830",
1✔
85
                                                     6377276.345, 300.8017);
86
    spheroids[9].SetValuesByEqRadiusAndInvFlattening("everest-sabah-sarawak",
1✔
87
                                                     6377298.556, 300.8017);
88
    spheroids[10].SetValuesByEqRadiusAndInvFlattening("everest-india-1956",
1✔
89
                                                      6377301.243, 300.8017);
90
    spheroids[11].SetValuesByEqRadiusAndInvFlattening("everest-malaysia-1969",
1✔
91
                                                      6377295.664, 300.8017);
92
    spheroids[12].SetValuesByEqRadiusAndInvFlattening("everest-malay-sing",
1✔
93
                                                      6377304.063, 300.8017);
94
    spheroids[13].SetValuesByEqRadiusAndInvFlattening("everest-pakistan",
1✔
95
                                                      6377309.613, 300.8017);
96
    spheroids[14].SetValuesByEqRadiusAndInvFlattening("modified-fisher-1960",
1✔
97
                                                      6378155, 298.3);
98
    spheroids[15].SetValuesByEqRadiusAndInvFlattening("helmert-1906", 6378200,
1✔
99
                                                      298.3);
100
    spheroids[16].SetValuesByEqRadiusAndInvFlattening("hough-1960", 6378270,
1✔
101
                                                      297);
102
    spheroids[17].SetValuesByEqRadiusAndInvFlattening("hughes", 6378273.0,
1✔
103
                                                      298.279);
104
    spheroids[18].SetValuesByEqRadiusAndInvFlattening("indonesian-1974",
1✔
105
                                                      6378160, 298.247);
106
    spheroids[19].SetValuesByEqRadiusAndInvFlattening("international-1924",
1✔
107
                                                      6378388, 297);
108
    spheroids[20].SetValuesByEqRadiusAndInvFlattening("iugc-67", 6378160.0,
1✔
109
                                                      298.254);
110
    spheroids[21].SetValuesByEqRadiusAndInvFlattening("iugc-75", 6378140.0,
1✔
111
                                                      298.25298);
112
    spheroids[22].SetValuesByEqRadiusAndInvFlattening("krassovsky-1940",
1✔
113
                                                      6378245, 298.3);
114
    spheroids[23].SetValuesByEqRadiusAndInvFlattening("kaula", 6378165.0,
1✔
115
                                                      292.308);
116
    spheroids[24].SetValuesByEqRadiusAndInvFlattening("grs-80", 6378137,
1✔
117
                                                      298.257222101);
118
    spheroids[25].SetValuesByEqRadiusAndInvFlattening("south-american-1969",
1✔
119
                                                      6378160, 298.25);
120
    spheroids[26].SetValuesByEqRadiusAndInvFlattening("wgs-72", 6378135,
1✔
121
                                                      298.26);
122
    spheroids[27].SetValuesByEqRadiusAndInvFlattening("wgs-84", 6378137,
1✔
123
                                                      298.257223563);
124
    spheroids[28].SetValuesByEqRadiusAndInvFlattening("ev-wgs-84", 6378137.0,
1✔
125
                                                      298.252841);
126
    spheroids[29].SetValuesByEqRadiusAndInvFlattening("ev-bessel", 6377397.0,
1✔
127
                                                      299.1976073);
128

129
    spheroids[30].SetValuesByEqRadiusAndInvFlattening("airy_1830", 6377563.396,
1✔
130
                                                      299.3249646);
131
    spheroids[31].SetValuesByEqRadiusAndInvFlattening("modified_airy",
1✔
132
                                                      6377340.189, 299.3249646);
133
    spheroids[32].SetValuesByEqRadiusAndInvFlattening("australian_national",
1✔
134
                                                      6378160, 298.25);
135
    spheroids[33].SetValuesByEqRadiusAndInvFlattening("bessel_1841_namibia",
1✔
136
                                                      6377483.865, 299.1528128);
137
    spheroids[34].SetValuesByEqRadiusAndInvFlattening("bessel_1841",
1✔
138
                                                      6377397.155, 299.1528128);
139
    spheroids[35].SetValuesByEqRadiusAndInvFlattening("clarke_1858", 6378294.0,
1✔
140
                                                      294.297);
141
    spheroids[36].SetValuesByEqRadiusAndInvFlattening("clarke_1866", 6378206.4,
1✔
142
                                                      294.9786982);
143
    spheroids[37].SetValuesByEqRadiusAndInvFlattening("clarke_1880",
1✔
144
                                                      6378249.145, 293.465);
145
    spheroids[38].SetValuesByEqRadiusAndInvFlattening("everest_india_1830",
1✔
146
                                                      6377276.345, 300.8017);
147
    spheroids[39].SetValuesByEqRadiusAndInvFlattening("everest_sabah_sarawak",
1✔
148
                                                      6377298.556, 300.8017);
149
    spheroids[40].SetValuesByEqRadiusAndInvFlattening("everest_india_1956",
1✔
150
                                                      6377301.243, 300.8017);
151
    spheroids[41].SetValuesByEqRadiusAndInvFlattening("everest_malaysia_1969",
1✔
152
                                                      6377295.664, 300.8017);
153
    spheroids[42].SetValuesByEqRadiusAndInvFlattening("everest_malay_sing",
1✔
154
                                                      6377304.063, 300.8017);
155
    spheroids[43].SetValuesByEqRadiusAndInvFlattening("everest_pakistan",
1✔
156
                                                      6377309.613, 300.8017);
157
    spheroids[44].SetValuesByEqRadiusAndInvFlattening("modified_fisher_1960",
1✔
158
                                                      6378155, 298.3);
159
    spheroids[45].SetValuesByEqRadiusAndInvFlattening("helmert_1906", 6378200,
1✔
160
                                                      298.3);
161
    spheroids[46].SetValuesByEqRadiusAndInvFlattening("hough_1960", 6378270,
1✔
162
                                                      297);
163
    spheroids[47].SetValuesByEqRadiusAndInvFlattening("indonesian_1974",
1✔
164
                                                      6378160, 298.247);
165
    spheroids[48].SetValuesByEqRadiusAndInvFlattening("international_1924",
1✔
166
                                                      6378388, 297);
167
    spheroids[49].SetValuesByEqRadiusAndInvFlattening("iugc_67", 6378160.0,
1✔
168
                                                      298.254);
169
    spheroids[50].SetValuesByEqRadiusAndInvFlattening("iugc_75", 6378140.0,
1✔
170
                                                      298.25298);
171
    spheroids[51].SetValuesByEqRadiusAndInvFlattening("krassovsky_1940",
1✔
172
                                                      6378245, 298.3);
173
    spheroids[52].SetValuesByEqRadiusAndInvFlattening("grs_80", 6378137,
1✔
174
                                                      298.257222101);
175
    spheroids[53].SetValuesByEqRadiusAndInvFlattening("south_american_1969",
1✔
176
                                                      6378160, 298.25);
177
    spheroids[54].SetValuesByEqRadiusAndInvFlattening("wgs_72", 6378135,
1✔
178
                                                      298.26);
179
    spheroids[55].SetValuesByEqRadiusAndInvFlattening("wgs_84", 6378137,
1✔
180
                                                      298.257223563);
181
    spheroids[56].SetValuesByEqRadiusAndInvFlattening("ev_wgs_84", 6378137.0,
1✔
182
                                                      298.252841);
183
    spheroids[57].SetValuesByEqRadiusAndInvFlattening("ev_bessel", 6377397.0,
1✔
184
                                                      299.1976073);
185
}
1✔
186

187
/************************************************************************/
188
/* ==================================================================== */
189
/*                              HKVDataset                              */
190
/* ==================================================================== */
191
/************************************************************************/
192

193
class HKVDataset final : public RawDataset
194
{
195
    friend class HKVRasterBand;
196

197
    char *pszPath;
198
    VSILFILE *fpBlob;
199

200
    int nGCPCount;
201
    GDAL_GCP *pasGCPList;
202

203
    void ProcessGeoref(const char *);
204
    void ProcessGeorefGCP(char **, const char *, double, double);
205

206
    void SetVersion(float version_number)
1✔
207
    {
208
        // Update stored info.
209
        MFF2version = version_number;
1✔
210
    }
1✔
211

212
    float MFF2version;
213

214
    GDALDataType eRasterType;
215

216
    void SetNoDataValue(double);
217

218
    OGRSpatialReference m_oSRS{};
219
    OGRSpatialReference m_oGCPSRS{};
220
    GDALGeoTransform m_gt{};
221

222
    char **papszAttrib;
223

224
    char **papszGeoref;
225

226
    // NOTE: The MFF2 format goes against GDAL's API in that nodata values are
227
    // set per-dataset rather than per-band.  To compromise, for writing out,
228
    // the dataset's nodata value will be set to the last value set on any of
229
    // the raster bands.
230

231
    bool bNoDataSet;
232
    double dfNoDataValue;
233

234
    CPL_DISALLOW_COPY_ASSIGN(HKVDataset)
235

236
    CPLErr Close() override;
237

238
  public:
239
    HKVDataset();
240
    ~HKVDataset() override;
241

242
    int GetGCPCount() override /* const */
×
243
    {
244
        return nGCPCount;
×
245
    }
246

247
    const OGRSpatialReference *GetGCPSpatialRef() const override
×
248
    {
249
        return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
×
250
    }
251

252
    const GDAL_GCP *GetGCPs() override;
253

254
    const OGRSpatialReference *GetSpatialRef() const override
×
255
    {
256
        return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
×
257
    }
258

259
    CPLErr GetGeoTransform(GDALGeoTransform &) const override;
260

261
    static GDALDataset *Open(GDALOpenInfo *);
262
};
263

264
/************************************************************************/
265
/* ==================================================================== */
266
/*                            HKVRasterBand                             */
267
/* ==================================================================== */
268
/************************************************************************/
269

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

274
HKVRasterBand::HKVRasterBand(HKVDataset *poDSIn, int nBandIn, VSILFILE *fpRawIn,
1✔
275
                             unsigned int nImgOffsetIn, int nPixelOffsetIn,
276
                             int nLineOffsetIn, GDALDataType eDataTypeIn,
277
                             int bNativeOrderIn)
1✔
278
    : RawRasterBand(GDALDataset::FromHandle(poDSIn), nBandIn, fpRawIn,
279
                    nImgOffsetIn, nPixelOffsetIn, nLineOffsetIn, eDataTypeIn,
280
                    bNativeOrderIn, RawRasterBand::OwnFP::NO)
1✔
281

282
{
283
    poDS = poDSIn;
1✔
284
    nBand = nBandIn;
1✔
285

286
    nBlockXSize = poDS->GetRasterXSize();
1✔
287
    nBlockYSize = 1;
1✔
288
}
1✔
289

290
/************************************************************************/
291
/* ==================================================================== */
292
/*                              HKVDataset                              */
293
/* ==================================================================== */
294
/************************************************************************/
295

296
/************************************************************************/
297
/*                            HKVDataset()                             */
298
/************************************************************************/
299

300
HKVDataset::HKVDataset()
1✔
301
    : pszPath(nullptr), fpBlob(nullptr), nGCPCount(0), pasGCPList(nullptr),
302
      // Initialize datasets to new version; change if necessary.
303
      MFF2version(1.1f), eRasterType(GDT_Unknown), papszAttrib(nullptr),
304
      papszGeoref(nullptr), bNoDataSet(false), dfNoDataValue(0.0)
1✔
305
{
306
    m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1✔
307
    m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1✔
308
}
1✔
309

310
/************************************************************************/
311
/*                            ~HKVDataset()                            */
312
/************************************************************************/
313

314
HKVDataset::~HKVDataset()
2✔
315

316
{
317
    HKVDataset::Close();
1✔
318
}
2✔
319

320
/************************************************************************/
321
/*                              Close()                                 */
322
/************************************************************************/
323

324
CPLErr HKVDataset::Close()
2✔
325
{
326
    CPLErr eErr = CE_None;
2✔
327
    if (nOpenFlags != OPEN_FLAGS_CLOSED)
2✔
328
    {
329
        if (HKVDataset::FlushCache(true) != CE_None)
1✔
330
            eErr = CE_Failure;
×
331

332
        if (fpBlob)
1✔
333
        {
334
            if (VSIFCloseL(fpBlob) != 0)
1✔
335
            {
336
                eErr = CE_Failure;
×
337
                CPLError(CE_Failure, CPLE_FileIO, "I/O error");
×
338
            }
339
        }
340

341
        if (nGCPCount > 0)
1✔
342
        {
343
            GDALDeinitGCPs(nGCPCount, pasGCPList);
1✔
344
            CPLFree(pasGCPList);
1✔
345
        }
346

347
        CPLFree(pszPath);
1✔
348
        CSLDestroy(papszGeoref);
1✔
349
        CSLDestroy(papszAttrib);
1✔
350

351
        if (GDALPamDataset::Close() != CE_None)
1✔
352
            eErr = CE_Failure;
×
353
    }
354
    return eErr;
2✔
355
}
356

357
/************************************************************************/
358
/*                          GetGeoTransform()                           */
359
/************************************************************************/
360

361
CPLErr HKVDataset::GetGeoTransform(GDALGeoTransform &gt) const
×
362

363
{
364
    gt = m_gt;
×
365
    return CE_None;
×
366
}
367

368
/************************************************************************/
369
/*                               GetGCP()                               */
370
/************************************************************************/
371

372
const GDAL_GCP *HKVDataset::GetGCPs()
×
373

374
{
375
    return pasGCPList;
×
376
}
377

378
/************************************************************************/
379
/*                          ProcessGeorefGCP()                          */
380
/************************************************************************/
381

382
void HKVDataset::ProcessGeorefGCP(char **papszGeorefIn, const char *pszBase,
5✔
383
                                  double dfRasterX, double dfRasterY)
384

385
{
386
    /* -------------------------------------------------------------------- */
387
    /*      Fetch the GCP from the string list.                             */
388
    /* -------------------------------------------------------------------- */
389
    char szFieldName[128] = {'\0'};
5✔
390
    snprintf(szFieldName, sizeof(szFieldName), "%s.latitude", pszBase);
5✔
391
    double dfLat = 0.0;
5✔
392
    if (CSLFetchNameValue(papszGeorefIn, szFieldName) == nullptr)
5✔
393
        return;
×
394
    else
395
        dfLat = CPLAtof(CSLFetchNameValue(papszGeorefIn, szFieldName));
5✔
396

397
    snprintf(szFieldName, sizeof(szFieldName), "%s.longitude", pszBase);
5✔
398
    double dfLong = 0.0;
5✔
399
    if (CSLFetchNameValue(papszGeorefIn, szFieldName) == nullptr)
5✔
400
        return;
×
401
    else
402
        dfLong = CPLAtof(CSLFetchNameValue(papszGeorefIn, szFieldName));
5✔
403

404
    /* -------------------------------------------------------------------- */
405
    /*      Add the gcp to the internal list.                               */
406
    /* -------------------------------------------------------------------- */
407
    GDALInitGCPs(1, pasGCPList + nGCPCount);
5✔
408

409
    CPLFree(pasGCPList[nGCPCount].pszId);
5✔
410

411
    pasGCPList[nGCPCount].pszId = CPLStrdup(pszBase);
5✔
412

413
    pasGCPList[nGCPCount].dfGCPX = dfLong;
5✔
414
    pasGCPList[nGCPCount].dfGCPY = dfLat;
5✔
415
    pasGCPList[nGCPCount].dfGCPZ = 0.0;
5✔
416

417
    pasGCPList[nGCPCount].dfGCPPixel = dfRasterX;
5✔
418
    pasGCPList[nGCPCount].dfGCPLine = dfRasterY;
5✔
419

420
    nGCPCount++;
5✔
421
}
422

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

427
void HKVDataset::ProcessGeoref(const char *pszFilename)
1✔
428

429
{
430
    /* -------------------------------------------------------------------- */
431
    /*      Load the georef file, and boil white space away from around     */
432
    /*      the equal sign.                                                 */
433
    /* -------------------------------------------------------------------- */
434
    CSLDestroy(papszGeoref);
1✔
435
    papszGeoref = CSLLoad(pszFilename);
1✔
436
    if (papszGeoref == nullptr)
1✔
437
        return;
×
438

439
    HKVSpheroidList *hkvEllipsoids = new HKVSpheroidList;
1✔
440

441
    for (int i = 0; papszGeoref[i] != nullptr; i++)
14✔
442
    {
443
        int iDst = 0;
13✔
444
        char *pszLine = papszGeoref[i];
13✔
445

446
        for (int iSrc = 0; pszLine[iSrc] != '\0'; iSrc++)
433✔
447
        {
448
            if (pszLine[iSrc] != ' ')
420✔
449
            {
450
                pszLine[iDst++] = pszLine[iSrc];
420✔
451
            }
452
        }
453
        pszLine[iDst] = '\0';
13✔
454
    }
455

456
    /* -------------------------------------------------------------------- */
457
    /*      Try to get GCPs, in lat/longs                     .             */
458
    /* -------------------------------------------------------------------- */
459
    nGCPCount = 0;
1✔
460
    pasGCPList = reinterpret_cast<GDAL_GCP *>(CPLCalloc(sizeof(GDAL_GCP), 5));
1✔
461

462
    if (MFF2version > 1.0)
1✔
463
    {
464
        ProcessGeorefGCP(papszGeoref, "top_left", 0, 0);
1✔
465
        ProcessGeorefGCP(papszGeoref, "top_right", GetRasterXSize(), 0);
1✔
466
        ProcessGeorefGCP(papszGeoref, "bottom_left", 0, GetRasterYSize());
1✔
467
        ProcessGeorefGCP(papszGeoref, "bottom_right", GetRasterXSize(),
1✔
468
                         GetRasterYSize());
1✔
469
        ProcessGeorefGCP(papszGeoref, "centre", GetRasterXSize() / 2.0,
1✔
470
                         GetRasterYSize() / 2.0);
1✔
471
    }
472
    else
473
    {
474
        ProcessGeorefGCP(papszGeoref, "top_left", 0.5, 0.5);
×
475
        ProcessGeorefGCP(papszGeoref, "top_right", GetRasterXSize() - 0.5, 0.5);
×
476
        ProcessGeorefGCP(papszGeoref, "bottom_left", 0.5,
×
477
                         GetRasterYSize() - 0.5);
×
478
        ProcessGeorefGCP(papszGeoref, "bottom_right", GetRasterXSize() - 0.5,
×
479
                         GetRasterYSize() - 0.5);
×
480
        ProcessGeorefGCP(papszGeoref, "centre", GetRasterXSize() / 2.0,
×
481
                         GetRasterYSize() / 2.0);
×
482
    }
483

484
    if (nGCPCount == 0)
1✔
485
    {
486
        CPLFree(pasGCPList);
×
487
        pasGCPList = nullptr;
×
488
    }
489

490
    /* -------------------------------------------------------------------- */
491
    /*      Do we have a recognised projection?                             */
492
    /* -------------------------------------------------------------------- */
493
    const char *pszProjName = CSLFetchNameValue(papszGeoref, "projection.name");
1✔
494
    const char *pszOriginLong =
495
        CSLFetchNameValue(papszGeoref, "projection.origin_longitude");
1✔
496
    const char *pszSpheroidName =
497
        CSLFetchNameValue(papszGeoref, "spheroid.name");
1✔
498

499
    if (pszSpheroidName != nullptr &&
2✔
500
        hkvEllipsoids->SpheroidInList(pszSpheroidName))
1✔
501
    {
502
#if 0
503
      // TODO(schwehr): Enable in trunk after 2.1 branch and fix.
504
      // Breaks tests on some platforms.
505
      CPLError( CE_Failure, CPLE_AppDefined,
506
                "Unrecognized ellipsoid.  Not handled.  "
507
                "Spheroid name not in spheroid list: '%s'",
508
                pszSpheroidName );
509
#endif
510
        // Why were eq_radius and inv_flattening never used?
511
        // eq_radius = hkvEllipsoids->GetSpheroidEqRadius(pszSpheroidName);
512
        // inv_flattening =
513
        //     hkvEllipsoids->GetSpheroidInverseFlattening(pszSpheroidName);
514
    }
515
    else if (pszProjName != nullptr)
×
516
    {
517
        CPLError(CE_Warning, CPLE_AppDefined,
×
518
                 "Unrecognized ellipsoid.  Not handled.");
519
        // TODO(schwehr): This error is was never what was happening.
520
        // CPLError( CE_Warning, CPLE_AppDefined,
521
        //           "Unrecognized ellipsoid.  Using wgs-84 parameters.");
522
        // eq_radius=hkvEllipsoids->GetSpheroidEqRadius("wgs-84"); */
523
        // inv_flattening=hkvEllipsoids->GetSpheroidInverseFlattening("wgs-84");
524
    }
525

526
    if (pszProjName != nullptr && EQUAL(pszProjName, "utm") && nGCPCount == 5)
1✔
527
    {
528
        // int nZone = (int)((CPLAtof(pszOriginLong)+184.5) / 6.0);
529
        int nZone = 31;  // TODO(schwehr): Where does 31 come from?
1✔
530

531
        if (pszOriginLong == nullptr)
1✔
532
        {
533
            // If origin not specified, assume 0.0.
534
            CPLError(
×
535
                CE_Warning, CPLE_AppDefined,
536
                "No projection origin longitude specified.  Assuming 0.0.");
537
        }
538
        else
539
        {
540
            nZone = 31 + static_cast<int>(floor(CPLAtof(pszOriginLong) / 6.0));
1✔
541
        }
542

543
        OGRSpatialReference oUTM;
2✔
544

545
        if (pasGCPList[4].dfGCPY < 0)
1✔
546
            oUTM.SetUTM(nZone, 0);
×
547
        else
548
            oUTM.SetUTM(nZone, 1);
1✔
549

550
        OGRSpatialReference oLL;
2✔
551
        oLL.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1✔
552
        if (pszOriginLong != nullptr)
1✔
553
        {
554
            oUTM.SetProjParm(SRS_PP_CENTRAL_MERIDIAN, CPLAtof(pszOriginLong));
1✔
555
            oLL.SetProjParm(SRS_PP_LONGITUDE_OF_ORIGIN, CPLAtof(pszOriginLong));
1✔
556
        }
557

558
        if ((pszSpheroidName == nullptr) ||
1✔
559
            (EQUAL(pszSpheroidName, "wgs-84")) ||
1✔
560
            (EQUAL(pszSpheroidName, "wgs_84")))
1✔
561
        {
562
            oUTM.SetWellKnownGeogCS("WGS84");
×
563
            oLL.SetWellKnownGeogCS("WGS84");
×
564
        }
565
        else
566
        {
567
            if (hkvEllipsoids->SpheroidInList(pszSpheroidName))
1✔
568
            {
569
                oUTM.SetGeogCS(
1✔
570
                    "unknown", "unknown", pszSpheroidName,
571
                    hkvEllipsoids->GetSpheroidEqRadius(pszSpheroidName),
572
                    hkvEllipsoids->GetSpheroidInverseFlattening(
573
                        pszSpheroidName));
574
                oLL.SetGeogCS(
1✔
575
                    "unknown", "unknown", pszSpheroidName,
576
                    hkvEllipsoids->GetSpheroidEqRadius(pszSpheroidName),
577
                    hkvEllipsoids->GetSpheroidInverseFlattening(
578
                        pszSpheroidName));
579
            }
580
            else
581
            {
582
                CPLError(CE_Warning, CPLE_AppDefined,
×
583
                         "Unrecognized ellipsoid.  Using wgs-84 parameters.");
584
                oUTM.SetWellKnownGeogCS("WGS84");
×
585
                oLL.SetWellKnownGeogCS("WGS84");
×
586
            }
587
        }
588

589
        OGRCoordinateTransformation *poTransform =
590
            OGRCreateCoordinateTransformation(&oLL, &oUTM);
1✔
591

592
        bool bSuccess = true;
1✔
593
        if (poTransform == nullptr)
1✔
594
        {
595
            CPLErrorReset();
×
596
            bSuccess = false;
×
597
        }
598

599
        double dfUtmX[5] = {0.0};
1✔
600
        double dfUtmY[5] = {0.0};
1✔
601

602
        if (poTransform != nullptr)
1✔
603
        {
604
            for (int gcp_index = 0; gcp_index < 5; gcp_index++)
6✔
605
            {
606
                dfUtmX[gcp_index] = pasGCPList[gcp_index].dfGCPX;
5✔
607
                dfUtmY[gcp_index] = pasGCPList[gcp_index].dfGCPY;
5✔
608

609
                if (bSuccess && !poTransform->Transform(1, &(dfUtmX[gcp_index]),
5✔
610
                                                        &(dfUtmY[gcp_index])))
611
                    bSuccess = false;
×
612
            }
613
        }
614

615
        if (bSuccess)
1✔
616
        {
617
            // Update GCPS to proper projection.
618
            for (int gcp_index = 0; gcp_index < 5; gcp_index++)
6✔
619
            {
620
                pasGCPList[gcp_index].dfGCPX = dfUtmX[gcp_index];
5✔
621
                pasGCPList[gcp_index].dfGCPY = dfUtmY[gcp_index];
5✔
622
            }
623

624
            m_oGCPSRS = oUTM;
1✔
625

626
            bool transform_ok = CPL_TO_BOOL(
2✔
627
                GDALGCPsToGeoTransform(5, pasGCPList, m_gt.data(), 0));
1✔
628

629
            if (!transform_ok)
1✔
630
            {
631
                // Transform may not be sufficient in all cases (slant range
632
                // projection).
633
                m_gt = GDALGeoTransform();
×
634
                m_oGCPSRS.Clear();
×
635
            }
636
            else
637
            {
638
                m_oSRS = std::move(oUTM);
1✔
639
            }
640
        }
641

642
        if (poTransform != nullptr)
1✔
643
            delete poTransform;
2✔
644
    }
645
    else if (pszProjName != nullptr && nGCPCount == 5)
×
646
    {
647
        OGRSpatialReference oLL;
×
648
        oLL.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
×
649

650
        if (pszOriginLong != nullptr)
×
651
        {
652
            oLL.SetProjParm(SRS_PP_LONGITUDE_OF_ORIGIN, CPLAtof(pszOriginLong));
×
653
        }
654

655
        if (pszSpheroidName == nullptr ||
×
656
            EQUAL(pszSpheroidName, "wgs-84") ||  // Dash.
×
657
            EQUAL(pszSpheroidName, "wgs_84"))    // Underscore.
×
658
        {
659
            oLL.SetWellKnownGeogCS("WGS84");
×
660
        }
661
        else
662
        {
663
            if (hkvEllipsoids->SpheroidInList(pszSpheroidName))
×
664
            {
665
                oLL.SetGeogCS(
×
666
                    "", "", pszSpheroidName,
667
                    hkvEllipsoids->GetSpheroidEqRadius(pszSpheroidName),
668
                    hkvEllipsoids->GetSpheroidInverseFlattening(
669
                        pszSpheroidName));
670
            }
671
            else
672
            {
673
                CPLError(CE_Warning, CPLE_AppDefined,
×
674
                         "Unrecognized ellipsoid.  "
675
                         "Using wgs-84 parameters.");
676
                oLL.SetWellKnownGeogCS("WGS84");
×
677
            }
678
        }
679

680
        const bool transform_ok =
681
            CPL_TO_BOOL(GDALGCPsToGeoTransform(5, pasGCPList, m_gt.data(), 0));
×
682

683
        m_oSRS.Clear();
×
684

685
        if (!transform_ok)
×
686
        {
687
            m_gt = GDALGeoTransform();
×
688
        }
689
        else
690
        {
691
            m_oSRS = oLL;
×
692
        }
693

694
        m_oGCPSRS = std::move(oLL);
×
695
    }
696

697
    delete hkvEllipsoids;
1✔
698
}
699

700
/************************************************************************/
701
/*                                Open()                                */
702
/************************************************************************/
703

704
GDALDataset *HKVDataset::Open(GDALOpenInfo *poOpenInfo)
33,281✔
705

706
{
707
    /* -------------------------------------------------------------------- */
708
    /*      We assume the dataset is passed as a directory.  Check for      */
709
    /*      an attrib and blob file as a minimum.                           */
710
    /* -------------------------------------------------------------------- */
711
    if (!poOpenInfo->bIsDirectory)
33,281✔
712
        return nullptr;
32,928✔
713

714
    std::string osFilename =
715
        CPLFormFilenameSafe(poOpenInfo->pszFilename, "image_data", nullptr);
706✔
716
    VSIStatBuf sStat;
717
    if (VSIStat(osFilename.c_str(), &sStat) != 0)
353✔
718
        osFilename =
719
            CPLFormFilenameSafe(poOpenInfo->pszFilename, "blob", nullptr);
352✔
720
    if (VSIStat(osFilename.c_str(), &sStat) != 0)
353✔
721
        return nullptr;
352✔
722

723
    osFilename =
724
        CPLFormFilenameSafe(poOpenInfo->pszFilename, "attrib", nullptr);
1✔
725
    if (VSIStat(osFilename.c_str(), &sStat) != 0)
1✔
726
        return nullptr;
×
727

728
    /* -------------------------------------------------------------------- */
729
    /*      Load the attrib file, and boil white space away from around     */
730
    /*      the equal sign.                                                 */
731
    /* -------------------------------------------------------------------- */
732
    char **papszAttrib = CSLLoad(osFilename.c_str());
1✔
733
    if (papszAttrib == nullptr)
1✔
734
        return nullptr;
×
735

736
    for (int i = 0; papszAttrib[i] != nullptr; i++)
10✔
737
    {
738
        int iDst = 0;
9✔
739
        char *pszLine = papszAttrib[i];
9✔
740

741
        for (int iSrc = 0; pszLine[iSrc] != '\0'; iSrc++)
252✔
742
        {
743
            if (pszLine[iSrc] != ' ')
243✔
744
            {
745
                pszLine[iDst++] = pszLine[iSrc];
211✔
746
            }
747
        }
748
        pszLine[iDst] = '\0';
9✔
749
    }
750

751
    /* -------------------------------------------------------------------- */
752
    /*      Create a corresponding GDALDataset.                             */
753
    /* -------------------------------------------------------------------- */
754
    auto poDS = std::make_unique<HKVDataset>();
2✔
755

756
    poDS->pszPath = CPLStrdup(poOpenInfo->pszFilename);
1✔
757
    poDS->papszAttrib = papszAttrib;
1✔
758

759
    poDS->eAccess = poOpenInfo->eAccess;
1✔
760

761
    /* -------------------------------------------------------------------- */
762
    /*      Set some dataset wide information.                              */
763
    /* -------------------------------------------------------------------- */
764
    bool bNative = false;
1✔
765
    bool bComplex = false;
1✔
766
    int nRawBands = 0;
1✔
767

768
    if (CSLFetchNameValue(papszAttrib, "extent.cols") == nullptr ||
2✔
769
        CSLFetchNameValue(papszAttrib, "extent.rows") == nullptr)
1✔
770
    {
771
        return nullptr;
×
772
    }
773

774
    poDS->nRasterXSize = atoi(CSLFetchNameValue(papszAttrib, "extent.cols"));
1✔
775
    poDS->nRasterYSize = atoi(CSLFetchNameValue(papszAttrib, "extent.rows"));
1✔
776

777
    if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
1✔
778
    {
779
        return nullptr;
×
780
    }
781

782
    const char *pszValue = CSLFetchNameValue(papszAttrib, "pixel.order");
1✔
783
    if (pszValue == nullptr)
1✔
784
        bNative = true;
×
785
    else
786
    {
787
#ifdef CPL_MSB
788
        bNative = strstr(pszValue, "*msbf") != NULL;
789
#else
790
        bNative = strstr(pszValue, "*lsbf") != nullptr;
1✔
791
#endif
792
    }
793

794
    bool bNoDataSet = false;
1✔
795
    double dfNoDataValue = 0.0;
1✔
796
    pszValue = CSLFetchNameValue(papszAttrib, "pixel.no_data");
1✔
797
    if (pszValue != nullptr)
1✔
798
    {
799
        bNoDataSet = true;
×
800
        dfNoDataValue = CPLAtof(pszValue);
×
801
    }
802

803
    pszValue = CSLFetchNameValue(papszAttrib, "channel.enumeration");
1✔
804
    if (pszValue != nullptr)
1✔
805
        nRawBands = atoi(pszValue);
1✔
806
    else
807
        nRawBands = 1;
×
808

809
    if (!GDALCheckBandCount(nRawBands, TRUE))
1✔
810
    {
811
        return nullptr;
×
812
    }
813

814
    pszValue = CSLFetchNameValue(papszAttrib, "pixel.field");
1✔
815
    if (pszValue != nullptr && strstr(pszValue, "*complex") != nullptr)
1✔
816
        bComplex = true;
×
817
    else
818
        bComplex = false;
1✔
819

820
    /* Get the version number, if present (if not, assume old version. */
821
    /* Versions differ in their interpretation of corner coordinates.  */
822

823
    if (CSLFetchNameValue(papszAttrib, "version") != nullptr)
1✔
824
        poDS->SetVersion(static_cast<float>(
1✔
825
            CPLAtof(CSLFetchNameValue(papszAttrib, "version"))));
1✔
826
    else
827
        poDS->SetVersion(1.0);
×
828

829
    /* -------------------------------------------------------------------- */
830
    /*      Figure out the datatype                                         */
831
    /* -------------------------------------------------------------------- */
832
    const char *pszEncoding = CSLFetchNameValue(papszAttrib, "pixel.encoding");
1✔
833
    if (pszEncoding == nullptr)
1✔
834
        pszEncoding = "{ *unsigned }";
×
835

836
    int nSize = 1;
1✔
837
    if (CSLFetchNameValue(papszAttrib, "pixel.size") != nullptr)
1✔
838
        nSize = atoi(CSLFetchNameValue(papszAttrib, "pixel.size")) / 8;
1✔
839
#if 0
840
    int nPseudoBands;
841
    if( bComplex )
842
        nPseudoBands = 2;
843
    else
844
        nPseudoBands = 1;
845
#endif
846

847
    GDALDataType eType;
848
    if (nSize == 1)
1✔
849
        eType = GDT_Byte;
1✔
850
    else if (nSize == 2 && strstr(pszEncoding, "*unsigned") != nullptr)
×
851
        eType = GDT_UInt16;
×
852
    else if (nSize == 4 && bComplex)
×
853
        eType = GDT_CInt16;
×
854
    else if (nSize == 2)
×
855
        eType = GDT_Int16;
×
856
    else if (nSize == 4 && strstr(pszEncoding, "*unsigned") != nullptr)
×
857
        eType = GDT_UInt32;
×
858
    else if (nSize == 8 && strstr(pszEncoding, "*two") != nullptr && bComplex)
×
859
        eType = GDT_CInt32;
×
860
    else if (nSize == 4 && strstr(pszEncoding, "*two") != nullptr)
×
861
        eType = GDT_Int32;
×
862
    else if (nSize == 8 && bComplex)
×
863
        eType = GDT_CFloat32;
×
864
    else if (nSize == 4)
×
865
        eType = GDT_Float32;
×
866
    else if (nSize == 16 && bComplex)
×
867
        eType = GDT_CFloat64;
×
868
    else if (nSize == 8)
×
869
        eType = GDT_Float64;
×
870
    else
871
    {
872
        CPLError(CE_Failure, CPLE_AppDefined,
×
873
                 "Unsupported pixel data type in %s.\n"
874
                 "pixel.size=%d pixel.encoding=%s",
875
                 poDS->pszPath, nSize, pszEncoding);
×
876
        return nullptr;
×
877
    }
878

879
    /* -------------------------------------------------------------------- */
880
    /*      Open the blob file.                                             */
881
    /* -------------------------------------------------------------------- */
882
    osFilename = CPLFormFilenameSafe(poDS->pszPath, "image_data", nullptr);
1✔
883
    if (VSIStat(osFilename.c_str(), &sStat) != 0)
1✔
884
        osFilename = CPLFormFilenameSafe(poDS->pszPath, "blob", nullptr);
×
885
    if (poOpenInfo->eAccess == GA_ReadOnly)
1✔
886
    {
887
        poDS->fpBlob = VSIFOpenL(osFilename.c_str(), "rb");
1✔
888
        if (poDS->fpBlob == nullptr)
1✔
889
        {
890
            CPLError(CE_Failure, CPLE_OpenFailed,
×
891
                     "Unable to open file %s for read access.",
892
                     osFilename.c_str());
893
            return nullptr;
×
894
        }
895
    }
896
    else
897
    {
898
        poDS->fpBlob = VSIFOpenL(osFilename.c_str(), "rb+");
×
899
        if (poDS->fpBlob == nullptr)
×
900
        {
901
            CPLError(CE_Failure, CPLE_OpenFailed,
×
902
                     "Unable to open file %s for update access.",
903
                     osFilename.c_str());
904
            return nullptr;
×
905
        }
906
    }
907

908
    /* -------------------------------------------------------------------- */
909
    /*      Build the overview filename, as blob file = "_ovr".             */
910
    /* -------------------------------------------------------------------- */
911
    std::string osOvrFilename(osFilename);
2✔
912
    osOvrFilename += "_ovr";
1✔
913

914
    /* -------------------------------------------------------------------- */
915
    /*      Define the bands.                                               */
916
    /* -------------------------------------------------------------------- */
917
    const int nPixelOffset = nRawBands * nSize;
1✔
918
    const int nLineOffset = nPixelOffset * poDS->GetRasterXSize();
1✔
919
    int nOffset = 0;
1✔
920

921
    for (int iRawBand = 0; iRawBand < nRawBands; iRawBand++)
2✔
922
    {
923
        auto poBand = std::make_unique<HKVRasterBand>(
924
            poDS.get(), poDS->GetRasterCount() + 1, poDS->fpBlob, nOffset,
1✔
925
            nPixelOffset, nLineOffset, eType, bNative);
1✔
926
        if (!poBand->IsValid())
1✔
927
            return nullptr;
×
928

929
        if (bNoDataSet)
1✔
930
            poBand->SetNoDataValue(dfNoDataValue);
×
931
        poDS->SetBand(poDS->GetRasterCount() + 1, std::move(poBand));
1✔
932
        nOffset += GDALGetDataTypeSizeBytes(eType);
1✔
933
    }
934

935
    poDS->eRasterType = eType;
1✔
936

937
    /* -------------------------------------------------------------------- */
938
    /*      Process the georef file if there is one.                        */
939
    /* -------------------------------------------------------------------- */
940
    osFilename = CPLFormFilenameSafe(poDS->pszPath, "georef", nullptr);
1✔
941
    if (VSIStat(osFilename.c_str(), &sStat) == 0)
1✔
942
        poDS->ProcessGeoref(osFilename.c_str());
1✔
943

944
    /* -------------------------------------------------------------------- */
945
    /*      Initialize any PAM information.                                 */
946
    /* -------------------------------------------------------------------- */
947
    poDS->SetDescription(osOvrFilename.c_str());
1✔
948
    poDS->TryLoadXML();
1✔
949

950
    /* -------------------------------------------------------------------- */
951
    /*      Handle overviews.                                               */
952
    /* -------------------------------------------------------------------- */
953
    poDS->oOvManager.Initialize(poDS.get(), osOvrFilename.c_str(), nullptr,
1✔
954
                                TRUE);
955

956
    return poDS.release();
1✔
957
}
958

959
/************************************************************************/
960
/*                         GDALRegister_HKV()                           */
961
/************************************************************************/
962

963
void GDALRegister_HKV()
1,911✔
964

965
{
966
    if (GDALGetDriverByName("MFF2") != nullptr)
1,911✔
967
        return;
282✔
968

969
    GDALDriver *poDriver = new GDALDriver();
1,629✔
970

971
    poDriver->SetDescription("MFF2");
1,629✔
972
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1,629✔
973
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Vexcel MFF2 (HKV) Raster");
1,629✔
974
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/mff2.html");
1,629✔
975

976
    poDriver->pfnOpen = HKVDataset::Open;
1,629✔
977

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