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

OSGeo / gdal / 15899162844

26 Jun 2025 10:14AM UTC coverage: 71.088% (+0.004%) from 71.084%
15899162844

Pull #12623

github

web-flow
Merge c704a8392 into f5cb024d4
Pull Request #12623: gdal raster overview add: add a --overview-src option

209 of 244 new or added lines in 5 files covered. (85.66%)

96 existing lines in 44 files now uncovered.

574014 of 807474 relevant lines covered (71.09%)

250815.03 hits per line

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

38.98
/frmts/raw/cpgdataset.cpp
1
/******************************************************************************
2
 *
3
 * Project:  Polarimetric Workstation
4
 * Purpose:  Convair PolGASP data (.img/.hdr format).
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
9
 * Copyright (c) 2009, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13

14
#include "cpl_string.h"
15
#include "gdal_frmts.h"
16
#include "ogr_spatialref.h"
17
#include "rawdataset.h"
18

19
#include <cinttypes>
20
#include <vector>
21

22
/************************************************************************/
23
/* ==================================================================== */
24
/*                              CPGDataset                              */
25
/* ==================================================================== */
26
/************************************************************************/
27

28
class SIRC_QSLCRasterBand;
29
class CPG_STOKESRasterBand;
30

31
class CPGDataset final : public RawDataset
32
{
33
    friend class SIRC_QSLCRasterBand;
34
    friend class CPG_STOKESRasterBand;
35

36
    static constexpr int NUMBER_OF_BANDS = 4;
37
    std::vector<VSILFILE *> afpImage{NUMBER_OF_BANDS};
38
    std::vector<CPLString> aosImageFilenames{};
39

40
    int nGCPCount;
41
    GDAL_GCP *pasGCPList;
42
    OGRSpatialReference m_oGCPSRS{};
43

44
    GDALGeoTransform m_gt{};
45
    OGRSpatialReference m_oSRS{};
46

47
    int nLoadedStokesLine;
48
    float *padfStokesMatrix;
49

50
    Interleave eInterleave = Interleave::BSQ;
51
    static int AdjustFilename(char **, const char *, const char *);
52
    static int FindType1(const char *pszWorkname);
53
    static int FindType2(const char *pszWorkname);
54
#ifdef notdef
55
    static int FindType3(const char *pszWorkname);
56
#endif
57
    static GDALDataset *InitializeType1Or2Dataset(const char *pszWorkname);
58
#ifdef notdef
59
    static GDALDataset *InitializeType3Dataset(const char *pszWorkname);
60
#endif
61
    CPLErr LoadStokesLine(int iLine, int bNativeOrder);
62

63
    CPL_DISALLOW_COPY_ASSIGN(CPGDataset)
64

65
    CPLErr Close() override;
66

67
  public:
68
    CPGDataset();
69
    ~CPGDataset() override;
70

71
    int GetGCPCount() override;
72

73
    const OGRSpatialReference *GetGCPSpatialRef() const override
×
74
    {
75
        return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
×
76
    }
77

78
    const GDAL_GCP *GetGCPs() override;
79

80
    const OGRSpatialReference *GetSpatialRef() const override
×
81
    {
82
        return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
×
83
    }
84

85
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
86

87
    char **GetFileList() override;
88

89
    static GDALDataset *Open(GDALOpenInfo *);
90
};
91

92
/************************************************************************/
93
/*                            CPGDataset()                             */
94
/************************************************************************/
95

96
CPGDataset::CPGDataset()
2✔
97
    : nGCPCount(0), pasGCPList(nullptr), nLoadedStokesLine(-1),
98
      padfStokesMatrix(nullptr)
2✔
99
{
100
    m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2✔
101
    m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2✔
102
}
2✔
103

104
/************************************************************************/
105
/*                            ~CPGDataset()                            */
106
/************************************************************************/
107

108
CPGDataset::~CPGDataset()
4✔
109

110
{
111
    CPGDataset::Close();
2✔
112
}
4✔
113

114
/************************************************************************/
115
/*                              Close()                                 */
116
/************************************************************************/
117

118
CPLErr CPGDataset::Close()
4✔
119
{
120
    CPLErr eErr = CE_None;
4✔
121
    if (nOpenFlags != OPEN_FLAGS_CLOSED)
4✔
122
    {
123
        if (CPGDataset::FlushCache(true) != CE_None)
2✔
124
            eErr = CE_Failure;
×
125

126
        for (auto poFile : afpImage)
10✔
127
        {
128
            if (poFile != nullptr)
8✔
129
                VSIFCloseL(poFile);
2✔
130
        }
131

132
        if (nGCPCount > 0)
2✔
133
        {
134
            GDALDeinitGCPs(nGCPCount, pasGCPList);
2✔
135
            CPLFree(pasGCPList);
2✔
136
        }
137

138
        CPLFree(padfStokesMatrix);
2✔
139

140
        if (GDALPamDataset::Close() != CE_None)
2✔
141
            eErr = CE_Failure;
×
142
    }
143
    return eErr;
4✔
144
}
145

146
/************************************************************************/
147
/*                            GetFileList()                             */
148
/************************************************************************/
149

150
char **CPGDataset::GetFileList()
1✔
151

152
{
153
    char **papszFileList = RawDataset::GetFileList();
1✔
154
    for (size_t i = 0; i < aosImageFilenames.size(); ++i)
2✔
155
        papszFileList = CSLAddString(papszFileList, aosImageFilenames[i]);
1✔
156
    return papszFileList;
1✔
157
}
158

159
/************************************************************************/
160
/* ==================================================================== */
161
/*                          SIRC_QSLCPRasterBand                        */
162
/* ==================================================================== */
163
/************************************************************************/
164

165
class SIRC_QSLCRasterBand final : public GDALRasterBand
166
{
167
    friend class CPGDataset;
168

169
  public:
170
    SIRC_QSLCRasterBand(CPGDataset *, int, GDALDataType);
171

172
    ~SIRC_QSLCRasterBand() override
16✔
173
    {
8✔
174
    }
16✔
175

176
    CPLErr IReadBlock(int, int, void *) override;
177
};
178

179
constexpr int M11 = 0;
180
// constexpr int M12 = 1;
181
constexpr int M13 = 2;
182
constexpr int M14 = 3;
183
// constexpr int M21 = 4;
184
constexpr int M22 = 5;
185
constexpr int M23 = 6;
186
constexpr int M24 = 7;
187
constexpr int M31 = 8;
188
constexpr int M32 = 9;
189
constexpr int M33 = 10;
190
constexpr int M34 = 11;
191
constexpr int M41 = 12;
192
constexpr int M42 = 13;
193
constexpr int M43 = 14;
194
constexpr int M44 = 15;
195

196
/************************************************************************/
197
/* ==================================================================== */
198
/*                          CPG_STOKESRasterBand                        */
199
/* ==================================================================== */
200
/************************************************************************/
201

202
class CPG_STOKESRasterBand final : public GDALRasterBand
203
{
204
    friend class CPGDataset;
205

206
    int bNativeOrder;
207

208
  public:
209
    CPG_STOKESRasterBand(GDALDataset *poDS, GDALDataType eType,
210
                         int bNativeOrder);
211

212
    ~CPG_STOKESRasterBand() override
×
213
    {
×
214
    }
×
215

216
    CPLErr IReadBlock(int, int, void *) override;
217
};
218

219
/************************************************************************/
220
/*                           AdjustFilename()                           */
221
/*                                                                      */
222
/*      Try to find the file with the request polarization and          */
223
/*      extension and update the passed filename accordingly.           */
224
/*                                                                      */
225
/*      Return TRUE if file found otherwise FALSE.                      */
226
/************************************************************************/
227

228
int CPGDataset::AdjustFilename(char **pszFilename, const char *pszPolarization,
8✔
229
                               const char *pszExtension)
230

231
{
232
    // TODO: Eventually we should handle upper/lower case.
233
    if (EQUAL(pszPolarization, "stokes"))
8✔
234
    {
235
        const std::string osNewName =
236
            CPLResetExtensionSafe(*pszFilename, pszExtension);
×
237
        CPLFree(*pszFilename);
×
238
        *pszFilename = CPLStrdup(osNewName.c_str());
×
239
    }
240
    else if (strlen(pszPolarization) == 2)
8✔
241
    {
242
        char *subptr = strstr(*pszFilename, "hh");
2✔
243
        if (subptr == nullptr)
2✔
244
            subptr = strstr(*pszFilename, "hv");
2✔
245
        if (subptr == nullptr)
2✔
246
            subptr = strstr(*pszFilename, "vv");
2✔
247
        if (subptr == nullptr)
2✔
248
            subptr = strstr(*pszFilename, "vh");
2✔
249
        if (subptr == nullptr)
2✔
250
            return FALSE;
2✔
251

252
        strncpy(subptr, pszPolarization, 2);
×
253
        const std::string osNewName =
254
            CPLResetExtensionSafe(*pszFilename, pszExtension);
×
255
        CPLFree(*pszFilename);
×
256
        *pszFilename = CPLStrdup(osNewName.c_str());
×
257
    }
258
    else
259
    {
260
        const std::string osNewName =
261
            CPLResetExtensionSafe(*pszFilename, pszExtension);
6✔
262
        CPLFree(*pszFilename);
6✔
263
        *pszFilename = CPLStrdup(osNewName.c_str());
6✔
264
    }
265
    VSIStatBufL sStatBuf;
266
    return VSIStatL(*pszFilename, &sStatBuf) == 0;
6✔
267
}
268

269
/************************************************************************/
270
/*         Search for the various types of Convair filesets             */
271
/*         Return TRUE for a match, FALSE for no match                  */
272
/************************************************************************/
273
int CPGDataset::FindType1(const char *pszFilename)
33,271✔
274
{
275
    const int nNameLen = static_cast<int>(strlen(pszFilename));
33,271✔
276

277
    if ((strstr(pszFilename, "sso") == nullptr) &&
33,271✔
278
        (strstr(pszFilename, "polgasp") == nullptr))
33,268✔
279
        return FALSE;
33,271✔
280

UNCOV
281
    if ((strlen(pszFilename) < 5) ||
×
282
        (!EQUAL(pszFilename + nNameLen - 4, ".hdr") &&
×
283
         !EQUAL(pszFilename + nNameLen - 4, ".img")))
×
284
        return FALSE;
×
285

286
    /* Expect all bands and headers to be present */
UNCOV
287
    char *pszTemp = CPLStrdup(pszFilename);
×
288

289
    const bool bNotFound = !AdjustFilename(&pszTemp, "hh", "img") ||
×
290
                           !AdjustFilename(&pszTemp, "hh", "hdr") ||
×
291
                           !AdjustFilename(&pszTemp, "hv", "img") ||
×
292
                           !AdjustFilename(&pszTemp, "hv", "hdr") ||
×
293
                           !AdjustFilename(&pszTemp, "vh", "img") ||
×
294
                           !AdjustFilename(&pszTemp, "vh", "hdr") ||
×
295
                           !AdjustFilename(&pszTemp, "vv", "img") ||
×
296
                           !AdjustFilename(&pszTemp, "vv", "hdr");
×
297

298
    CPLFree(pszTemp);
×
299

300
    return !bNotFound;
×
301
}
302

303
int CPGDataset::FindType2(const char *pszFilename)
33,272✔
304
{
305
    const int nNameLen = static_cast<int>(strlen(pszFilename));
33,272✔
306

307
    if ((strlen(pszFilename) < 9) ||
33,272✔
308
        (!EQUAL(pszFilename + nNameLen - 8, "SIRC.hdr") &&
32,586✔
309
         !EQUAL(pszFilename + nNameLen - 8, "SIRC.img")))
32,590✔
310
        return FALSE;
33,267✔
311

312
    char *pszTemp = CPLStrdup(pszFilename);
5✔
313
    const bool bNotFound = !AdjustFilename(&pszTemp, "", "img") ||
4✔
314
                           !AdjustFilename(&pszTemp, "", "hdr");
2✔
315
    CPLFree(pszTemp);
2✔
316

317
    return !bNotFound;
2✔
318
}
319

320
#ifdef notdef
321
int CPGDataset::FindType3(const char *pszFilename)
322
{
323
    const int nNameLen = static_cast<int>(strlen(pszFilename));
324

325
    if ((strstr(pszFilename, "sso") == NULL) &&
326
        (strstr(pszFilename, "polgasp") == NULL))
327
        return FALSE;
328

329
    if ((strlen(pszFilename) < 9) ||
330
        (!EQUAL(pszFilename + nNameLen - 4, ".img") &&
331
         !EQUAL(pszFilename + nNameLen - 8, ".img_def")))
332
        return FALSE;
333

334
    char *pszTemp = CPLStrdup(pszFilename);
335
    const bool bNotFound = !AdjustFilename(&pszTemp, "stokes", "img") ||
336
                           !AdjustFilename(&pszTemp, "stokes", "img_def");
337
    CPLFree(pszTemp);
338

339
    return !bNotFound;
340
}
341
#endif
342

343
/************************************************************************/
344
/*                        LoadStokesLine()                              */
345
/************************************************************************/
346

347
CPLErr CPGDataset::LoadStokesLine(int iLine, int bNativeOrder)
×
348

349
{
350
    if (iLine == nLoadedStokesLine)
×
351
        return CE_None;
×
352

353
    constexpr int nDataSize = static_cast<int>(sizeof(float));
×
354

355
    /* -------------------------------------------------------------------- */
356
    /*      allocate working buffers if we don't have them already.         */
357
    /* -------------------------------------------------------------------- */
358
    if (padfStokesMatrix == nullptr)
×
359
    {
360
        padfStokesMatrix = reinterpret_cast<float *>(
×
361
            CPLMalloc(sizeof(float) * nRasterXSize * 16));
×
362
    }
363

364
    /* -------------------------------------------------------------------- */
365
    /*      Load all the pixel data associated with this scanline.          */
366
    /*      Retains same interleaving as original dataset.                  */
367
    /* -------------------------------------------------------------------- */
368
    if (eInterleave == Interleave::BIP)
×
369
    {
370
        const int offset = nRasterXSize * iLine * nDataSize * 16;
×
371
        const int nBytesToRead = nDataSize * nRasterXSize * 16;
×
372
        if ((VSIFSeekL(afpImage[0], offset, SEEK_SET) != 0) ||
×
373
            static_cast<int>(
374
                VSIFReadL(reinterpret_cast<GByte *>(padfStokesMatrix), 1,
×
375
                          nBytesToRead, afpImage[0])) != nBytesToRead)
×
376
        {
377
            CPLError(CE_Failure, CPLE_FileIO,
×
378
                     "Error reading %d bytes of Stokes Convair at offset %d.\n"
379
                     "Reading file %s failed.",
380
                     nBytesToRead, offset, GetDescription());
×
381
            CPLFree(padfStokesMatrix);
×
382
            padfStokesMatrix = nullptr;
×
383
            nLoadedStokesLine = -1;
×
384
            return CE_Failure;
×
385
        }
386
    }
387
    else if (eInterleave == Interleave::BIL)
×
388
    {
389
        for (int band_index = 0; band_index < 16; band_index++)
×
390
        {
391
            const int offset =
×
392
                nDataSize * (nRasterXSize * iLine + nRasterXSize * band_index);
×
393
            const int nBytesToRead = nDataSize * nRasterXSize;
×
394
            if ((VSIFSeekL(afpImage[0], offset, SEEK_SET) != 0) ||
×
395
                static_cast<int>(
396
                    VSIFReadL(reinterpret_cast<GByte *>(
×
397
                                  padfStokesMatrix + nBytesToRead * band_index),
×
398
                              1, nBytesToRead, afpImage[0])) != nBytesToRead)
×
399
            {
400
                CPLError(
×
401
                    CE_Failure, CPLE_FileIO,
402
                    "Error reading %d bytes of Stokes Convair at offset %d.\n"
403
                    "Reading file %s failed.",
404
                    nBytesToRead, offset, GetDescription());
×
405
                CPLFree(padfStokesMatrix);
×
406
                padfStokesMatrix = nullptr;
×
407
                nLoadedStokesLine = -1;
×
408
                return CE_Failure;
×
409
            }
410
        }
411
    }
412
    else
413
    {
414
        for (int band_index = 0; band_index < 16; band_index++)
×
415
        {
416
            const int offset =
×
417
                nDataSize * (nRasterXSize * iLine +
×
418
                             nRasterXSize * nRasterYSize * band_index);
×
419
            const int nBytesToRead = nDataSize * nRasterXSize;
×
420
            if ((VSIFSeekL(afpImage[0], offset, SEEK_SET) != 0) ||
×
421
                static_cast<int>(
422
                    VSIFReadL(reinterpret_cast<GByte *>(
×
423
                                  padfStokesMatrix + nBytesToRead * band_index),
×
424
                              1, nBytesToRead, afpImage[0])) != nBytesToRead)
×
425
            {
426
                CPLError(
×
427
                    CE_Failure, CPLE_FileIO,
428
                    "Error reading %d bytes of Stokes Convair at offset %d.\n"
429
                    "Reading file %s failed.",
430
                    nBytesToRead, offset, GetDescription());
×
431
                CPLFree(padfStokesMatrix);
×
432
                padfStokesMatrix = nullptr;
×
433
                nLoadedStokesLine = -1;
×
434
                return CE_Failure;
×
435
            }
436
        }
437
    }
438

439
    if (!bNativeOrder)
×
440
        GDALSwapWords(padfStokesMatrix, nDataSize, nRasterXSize * 16,
×
441
                      nDataSize);
442

443
    nLoadedStokesLine = iLine;
×
444

445
    return CE_None;
×
446
}
447

448
/************************************************************************/
449
/*       Parse header information and initialize dataset for the        */
450
/*       appropriate Convair dataset style.                             */
451
/*       Returns dataset if successful; NULL if there was a problem.    */
452
/************************************************************************/
453

454
GDALDataset *CPGDataset::InitializeType1Or2Dataset(const char *pszFilename)
2✔
455
{
456

457
    /* -------------------------------------------------------------------- */
458
    /*      Read the .hdr file (the hh one for the .sso and polgasp cases)  */
459
    /*      and parse it.                                                   */
460
    /* -------------------------------------------------------------------- */
461
    int nLines = 0;
2✔
462
    int nSamples = 0;
2✔
463
    int nError = 0;
2✔
464

465
    /* Parameters required for pseudo-geocoding.  GCPs map */
466
    /* slant range to ground range at 16 points.           */
467
    int iGeoParamsFound = 0;
2✔
468
    int itransposed = 0;
2✔
469
    double dfaltitude = 0.0;
2✔
470
    double dfnear_srd = 0.0;
2✔
471
    double dfsample_size = 0.0;
2✔
472
    double dfsample_size_az = 0.0;
2✔
473

474
    /* Parameters in geogratis geocoded images */
475
    int iUTMParamsFound = 0;
2✔
476
    int iUTMZone = 0;
2✔
477
    // int iCorner = 0;
478
    double dfnorth = 0.0;
2✔
479
    double dfeast = 0.0;
2✔
480

481
    std::string osWorkName;
4✔
482
    {
483
        char *pszWorkname = CPLStrdup(pszFilename);
2✔
484
        AdjustFilename(&pszWorkname, "hh", "hdr");
2✔
485
        osWorkName = pszWorkname;
2✔
486
        CPLFree(pszWorkname);
2✔
487
    }
488

489
    char **papszHdrLines = CSLLoad(osWorkName.c_str());
2✔
490

491
    for (int iLine = 0; papszHdrLines && papszHdrLines[iLine] != nullptr;
16✔
492
         iLine++)
493
    {
494
        char **papszTokens = CSLTokenizeString(papszHdrLines[iLine]);
14✔
495

496
        /* Note: some cv580 file seem to have comments with #, hence the >=
497
         *       instead of = for token checking, and the equalN for the corner.
498
         */
499

500
        if (CSLCount(papszTokens) < 2)
14✔
501
        {
502
            /* ignore */;
503
        }
504
        else if ((CSLCount(papszTokens) >= 3) &&
14✔
505
                 EQUAL(papszTokens[0], "reference") &&
14✔
506
                 EQUAL(papszTokens[1], "north"))
×
507
        {
508
            dfnorth = CPLAtof(papszTokens[2]);
×
509
            iUTMParamsFound++;
×
510
        }
511
        else if ((CSLCount(papszTokens) >= 3) &&
14✔
512
                 EQUAL(papszTokens[0], "reference") &&
14✔
513
                 EQUAL(papszTokens[1], "east"))
×
514
        {
515
            dfeast = CPLAtof(papszTokens[2]);
×
516
            iUTMParamsFound++;
×
517
        }
518
        else if ((CSLCount(papszTokens) >= 5) &&
14✔
519
                 EQUAL(papszTokens[0], "reference") &&
×
520
                 EQUAL(papszTokens[1], "projection") &&
×
521
                 EQUAL(papszTokens[2], "UTM") && EQUAL(papszTokens[3], "zone"))
14✔
522
        {
523
            iUTMZone = atoi(papszTokens[4]);
×
524
            iUTMParamsFound++;
×
525
        }
526
        else if ((CSLCount(papszTokens) >= 3) &&
14✔
527
                 EQUAL(papszTokens[0], "reference") &&
×
528
                 EQUAL(papszTokens[1], "corner") &&
14✔
529
                 STARTS_WITH_CI(papszTokens[2], "Upper_Left"))
×
530
        {
531
            /* iCorner = 0; */
532
            iUTMParamsFound++;
×
533
        }
534
        else if (EQUAL(papszTokens[0], "number_lines"))
14✔
535
            nLines = atoi(papszTokens[1]);
2✔
536

537
        else if (EQUAL(papszTokens[0], "number_samples"))
12✔
538
            nSamples = atoi(papszTokens[1]);
2✔
539

540
        else if ((EQUAL(papszTokens[0], "header_offset") &&
10✔
541
                  atoi(papszTokens[1]) != 0) ||
×
542
                 (EQUAL(papszTokens[0], "number_channels") &&
10✔
543
                  (atoi(papszTokens[1]) != 1) &&
×
544
                  (atoi(papszTokens[1]) != 10)) ||
×
545
                 (EQUAL(papszTokens[0], "datatype") &&
10✔
546
                  atoi(papszTokens[1]) != 1) ||
×
547
                 (EQUAL(papszTokens[0], "number_format") &&
10✔
548
                  !EQUAL(papszTokens[1], "float32") &&
×
549
                  !EQUAL(papszTokens[1], "int8")))
×
550
        {
551
            CPLError(CE_Failure, CPLE_AppDefined,
×
552
                     "Keyword %s has value %s which does not match CPG driver "
553
                     "expectation.",
554
                     papszTokens[0], papszTokens[1]);
×
555
            nError = 1;
×
556
        }
557
        else if (EQUAL(papszTokens[0], "altitude"))
10✔
558
        {
559
            dfaltitude = CPLAtof(papszTokens[1]);
2✔
560
            iGeoParamsFound++;
2✔
561
        }
562
        else if (EQUAL(papszTokens[0], "near_srd"))
8✔
563
        {
564
            dfnear_srd = CPLAtof(papszTokens[1]);
2✔
565
            iGeoParamsFound++;
2✔
566
        }
567

568
        else if (EQUAL(papszTokens[0], "sample_size"))
6✔
569
        {
570
            dfsample_size = CPLAtof(papszTokens[1]);
2✔
571
            iGeoParamsFound++;
2✔
572
            iUTMParamsFound++;
2✔
573
        }
574
        else if (EQUAL(papszTokens[0], "sample_size_az"))
4✔
575
        {
576
            dfsample_size_az = CPLAtof(papszTokens[1]);
2✔
577
            iGeoParamsFound++;
2✔
578
            iUTMParamsFound++;
2✔
579
        }
580
        else if (EQUAL(papszTokens[0], "transposed"))
2✔
581
        {
582
            itransposed = atoi(papszTokens[1]);
2✔
583
            iGeoParamsFound++;
2✔
584
            iUTMParamsFound++;
2✔
585
        }
586

587
        CSLDestroy(papszTokens);
14✔
588
    }
589
    CSLDestroy(papszHdrLines);
2✔
590
    /* -------------------------------------------------------------------- */
591
    /*      Check for successful completion.                                */
592
    /* -------------------------------------------------------------------- */
593
    if (nError)
2✔
594
    {
595
        return nullptr;
×
596
    }
597

598
    if (nLines <= 0 || nSamples <= 0)
2✔
599
    {
600
        CPLError(
×
601
            CE_Failure, CPLE_AppDefined,
602
            "Did not find valid number_lines or number_samples keywords in %s.",
603
            osWorkName.c_str());
604
        return nullptr;
×
605
    }
606

607
    /* -------------------------------------------------------------------- */
608
    /*      Initialize dataset.                                             */
609
    /* -------------------------------------------------------------------- */
610
    auto poDS = std::make_unique<CPGDataset>();
4✔
611

612
    poDS->nRasterXSize = nSamples;
2✔
613
    poDS->nRasterYSize = nLines;
2✔
614

615
    /* -------------------------------------------------------------------- */
616
    /*      Open the four bands.                                            */
617
    /* -------------------------------------------------------------------- */
618
    static const char *const apszPolarizations[NUMBER_OF_BANDS] = {"hh", "hv",
619
                                                                   "vv", "vh"};
620

621
    const int nNameLen = static_cast<int>(osWorkName.size());
2✔
622

623
    if (EQUAL(osWorkName.c_str() + nNameLen - 7, "IRC.hdr") ||
2✔
624
        EQUAL(osWorkName.c_str() + nNameLen - 7, "IRC.img"))
×
625
    {
626
        {
627
            char *pszWorkname = CPLStrdup(osWorkName.c_str());
2✔
628
            AdjustFilename(&pszWorkname, "", "img");
2✔
629
            osWorkName = pszWorkname;
2✔
630
            CPLFree(pszWorkname);
2✔
631
        }
632

633
        poDS->afpImage[0] = VSIFOpenL(osWorkName.c_str(), "rb");
2✔
634
        if (poDS->afpImage[0] == nullptr)
2✔
635
        {
636
            CPLError(CE_Failure, CPLE_OpenFailed,
×
637
                     "Failed to open .img file: %s", osWorkName.c_str());
638
            return nullptr;
×
639
        }
640
        poDS->aosImageFilenames.push_back(osWorkName.c_str());
2✔
641
        for (int iBand = 0; iBand < NUMBER_OF_BANDS; iBand++)
10✔
642
        {
643
            SIRC_QSLCRasterBand *poBand =
644
                new SIRC_QSLCRasterBand(poDS.get(), iBand + 1, GDT_CFloat32);
8✔
645
            poDS->SetBand(iBand + 1, poBand);
8✔
646
            poBand->SetMetadataItem("POLARIMETRIC_INTERP",
8✔
647
                                    apszPolarizations[iBand]);
8✔
648
        }
649
    }
650
    else
651
    {
652
        constexpr int SIZEOF_CFLOAT32 = 2 * static_cast<int>(sizeof(float));
×
653
        if (nSamples > INT_MAX / SIZEOF_CFLOAT32)
×
654
        {
655
            CPLError(CE_Failure, CPLE_AppDefined, "Too large nBlockXSize");
×
656
            return nullptr;
×
657
        }
658

659
        CPLAssert(poDS->afpImage.size() == NUMBER_OF_BANDS);
×
660
        for (int iBand = 0; iBand < NUMBER_OF_BANDS; iBand++)
×
661
        {
662
            {
663
                char *pszWorkname = CPLStrdup(osWorkName.c_str());
×
664
                AdjustFilename(&pszWorkname, apszPolarizations[iBand], "img");
×
665
                osWorkName = pszWorkname;
×
666
                CPLFree(pszWorkname);
×
667
            }
668

669
            poDS->afpImage[iBand] = VSIFOpenL(osWorkName.c_str(), "rb");
×
670
            if (poDS->afpImage[iBand] == nullptr)
×
671
            {
672
                CPLError(CE_Failure, CPLE_OpenFailed,
×
673
                         "Failed to open .img file: %s", osWorkName.c_str());
674
                return nullptr;
×
675
            }
676
            poDS->aosImageFilenames.push_back(osWorkName.c_str());
×
677

678
            auto poBand = RawRasterBand::Create(
679
                poDS.get(), iBand + 1, poDS->afpImage[iBand], 0, 8,
×
680
                SIZEOF_CFLOAT32 * nSamples, GDT_CFloat32,
681
                RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
682
                RawRasterBand::OwnFP::NO);
×
683
            if (!poBand)
×
684
                return nullptr;
×
685
            poBand->SetMetadataItem("POLARIMETRIC_INTERP",
×
686
                                    apszPolarizations[iBand]);
×
687
            poDS->SetBand(iBand + 1, std::move(poBand));
×
688
        }
689
    }
690

691
    /* Set an appropriate matrix representation metadata item for the set */
692
    poDS->SetMetadataItem("MATRIX_REPRESENTATION", "SCATTERING");
2✔
693

694
    /* -------------------------------------------------------------------------
695
     */
696
    /*  Add georeferencing or pseudo-geocoding, if enough information found. */
697
    /* -------------------------------------------------------------------------
698
     */
699
    if (iUTMParamsFound == 7)
2✔
700
    {
701
        poDS->m_gt[1] = 0.0;
×
702
        poDS->m_gt[2] = 0.0;
×
703
        poDS->m_gt[4] = 0.0;
×
704
        poDS->m_gt[5] = 0.0;
×
705

706
        double dfnorth_center;
707
        if (itransposed == 1)
×
708
        {
709
            CPLError(CE_Warning, CPLE_AppDefined,
×
710
                     "Did not have a convair SIRC-style test dataset\n"
711
                     "with transposed=1 for testing.  Georeferencing may be "
712
                     "wrong.\n");
713
            dfnorth_center = dfnorth - nSamples * dfsample_size / 2.0;
×
714
            poDS->m_gt[0] = dfeast;
×
715
            poDS->m_gt[2] = dfsample_size_az;
×
716
            poDS->m_gt[3] = dfnorth;
×
717
            poDS->m_gt[4] = -1 * dfsample_size;
×
718
        }
719
        else
720
        {
721
            dfnorth_center = dfnorth - nLines * dfsample_size / 2.0;
×
722
            poDS->m_gt[0] = dfeast;
×
723
            poDS->m_gt[1] = dfsample_size_az;
×
724
            poDS->m_gt[3] = dfnorth;
×
725
            poDS->m_gt[5] = -1 * dfsample_size;
×
726
        }
727

728
        if (dfnorth_center < 0)
×
729
            poDS->m_oSRS.SetUTM(iUTMZone, 0);
×
730
        else
731
            poDS->m_oSRS.SetUTM(iUTMZone, 1);
×
732

733
        /* Assuming WGS84 */
734
        poDS->m_oSRS.SetWellKnownGeogCS("WGS84");
×
735
    }
736
    else if (iGeoParamsFound == 5)
2✔
737
    {
738
        double dfgcpLine, dfgcpPixel, dfgcpX, dfgcpY, dftemp;
739

740
        poDS->nGCPCount = 16;
2✔
741
        poDS->pasGCPList = reinterpret_cast<GDAL_GCP *>(
4✔
742
            CPLCalloc(sizeof(GDAL_GCP), poDS->nGCPCount));
2✔
743
        GDALInitGCPs(poDS->nGCPCount, poDS->pasGCPList);
2✔
744

745
        for (int ngcp = 0; ngcp < 16; ngcp++)
34✔
746
        {
747
            char szID[32];
748

749
            snprintf(szID, sizeof(szID), "%d", ngcp + 1);
32✔
750
            if (itransposed == 1)
32✔
751
            {
752
                if (ngcp < 4)
×
753
                    dfgcpPixel = 0.0;
×
754
                else if (ngcp < 8)
×
755
                    dfgcpPixel = nSamples / 3.0;
×
756
                else if (ngcp < 12)
×
757
                    dfgcpPixel = 2.0 * nSamples / 3.0;
×
758
                else
759
                    dfgcpPixel = nSamples;
×
760

761
                dfgcpLine = nLines * (ngcp % 4) / 3.0;
×
762

763
                dftemp = dfnear_srd + (dfsample_size * dfgcpLine);
×
764
                /* -1 so that 0,0 maps to largest Y */
765
                dfgcpY = -1 * sqrt(dftemp * dftemp - dfaltitude * dfaltitude);
×
766
                dfgcpX = dfgcpPixel * dfsample_size_az;
×
767
            }
768
            else
769
            {
770
                if (ngcp < 4)
32✔
771
                    dfgcpLine = 0.0;
8✔
772
                else if (ngcp < 8)
24✔
773
                    dfgcpLine = nLines / 3.0;
8✔
774
                else if (ngcp < 12)
16✔
775
                    dfgcpLine = 2.0 * nLines / 3.0;
8✔
776
                else
777
                    dfgcpLine = nLines;
8✔
778

779
                dfgcpPixel = nSamples * ((ngcp % 4) / 3.0);
32✔
780

781
                dftemp = dfnear_srd + (dfsample_size * dfgcpPixel);
32✔
782
                dfgcpX = sqrt(dftemp * dftemp - dfaltitude * dfaltitude);
32✔
783
                dfgcpY = (nLines - dfgcpLine) * dfsample_size_az;
32✔
784
            }
785
            poDS->pasGCPList[ngcp].dfGCPX = dfgcpX;
32✔
786
            poDS->pasGCPList[ngcp].dfGCPY = dfgcpY;
32✔
787
            poDS->pasGCPList[ngcp].dfGCPZ = 0.0;
32✔
788

789
            poDS->pasGCPList[ngcp].dfGCPPixel = dfgcpPixel;
32✔
790
            poDS->pasGCPList[ngcp].dfGCPLine = dfgcpLine;
32✔
791

792
            CPLFree(poDS->pasGCPList[ngcp].pszId);
32✔
793
            poDS->pasGCPList[ngcp].pszId = CPLStrdup(szID);
32✔
794
        }
795

796
        poDS->m_oGCPSRS.importFromWkt(
2✔
797
            "LOCAL_CS[\"Ground range view / unreferenced meters\","
798
            "UNIT[\"Meter\",1.0]]");
799
    }
800

801
    return poDS.release();
2✔
802
}
803

804
#ifdef notdef
805
GDALDataset *CPGDataset::InitializeType3Dataset(const char *pszFilename)
806
{
807
    int iBytesPerPixel = 0;
808
    Interleave::eInterleave = Interleave::BSQ;
809
    bool bInterleaveSpecified = false;
810
    int nLines = 0;
811
    int nSamples = 0;
812
    int nBands = 0;
813
    int nError = 0;
814

815
    /* Parameters in geogratis geocoded images */
816
    int iUTMParamsFound = 0;
817
    int iUTMZone = 0;
818
    double dfnorth = 0.0;
819
    double dfeast = 0.0;
820
    double dfOffsetX = 0.0;
821
    double dfOffsetY = 0.0;
822
    double dfxsize = 0.0;
823
    double dfysize = 0.0;
824

825
    char *pszWorkname = CPLStrdup(pszFilename);
826
    AdjustFilename(&pszWorkname, "stokes", "img_def");
827
    char **papszHdrLines = CSLLoad(pszWorkname);
828

829
    for (int iLine = 0; papszHdrLines && papszHdrLines[iLine] != NULL; iLine++)
830
    {
831
        char **papszTokens =
832
            CSLTokenizeString2(papszHdrLines[iLine], " \t",
833
                               CSLT_HONOURSTRINGS & CSLT_ALLOWEMPTYTOKENS);
834

835
        /* Note: some cv580 file seem to have comments with #, hence the >=
836
         * instead of = for token checking, and the equalN for the corner.
837
         */
838

839
        if ((CSLCount(papszTokens) >= 3) && EQUAL(papszTokens[0], "data") &&
840
            EQUAL(papszTokens[1], "organization:"))
841
        {
842

843
            if (STARTS_WITH_CI(papszTokens[2], "BSQ"))
844
            {
845
                bInterleaveSpecified = true;
846
                eInterleave = Interleave::BSQ;
847
            }
848
            else if (STARTS_WITH_CI(papszTokens[2], "BIL"))
849
            {
850
                bInterleaveSpecified = true;
851
                eInterleave = Interleave::BIL;
852
            }
853
            else if (STARTS_WITH_CI(papszTokens[2], "BIP"))
854
            {
855
                bInterleaveSpecified = true;
856
                eInterleave = Interleave::BIP;
857
            }
858
            else
859
            {
860
                CPLError(
861
                    CE_Failure, CPLE_AppDefined,
862
                    "The interleaving type of the file (%s) is not supported.",
863
                    papszTokens[2]);
864
                nError = 1;
865
            }
866
        }
867
        else if ((CSLCount(papszTokens) >= 3) &&
868
                 EQUAL(papszTokens[0], "data") &&
869
                 EQUAL(papszTokens[1], "state:"))
870
        {
871

872
            if (!STARTS_WITH_CI(papszTokens[2], "RAW") &&
873
                !STARTS_WITH_CI(papszTokens[2], "GEO"))
874
            {
875
                CPLError(CE_Failure, CPLE_AppDefined,
876
                         "The data state of the file (%s) is not "
877
                         "supported.\n.  Only RAW and GEO are currently "
878
                         "recognized.",
879
                         papszTokens[2]);
880
                nError = 1;
881
            }
882
        }
883
        else if ((CSLCount(papszTokens) >= 4) &&
884
                 EQUAL(papszTokens[0], "data") &&
885
                 EQUAL(papszTokens[1], "origin") &&
886
                 EQUAL(papszTokens[2], "point:"))
887
        {
888
            if (!STARTS_WITH_CI(papszTokens[3], "Upper_Left"))
889
            {
890
                CPLError(CE_Failure, CPLE_AppDefined,
891
                         "Unexpected value (%s) for data origin point- expect "
892
                         "Upper_Left.",
893
                         papszTokens[3]);
894
                nError = 1;
895
            }
896
            iUTMParamsFound++;
897
        }
898
        else if ((CSLCount(papszTokens) >= 5) && EQUAL(papszTokens[0], "map") &&
899
                 EQUAL(papszTokens[1], "projection:") &&
900
                 EQUAL(papszTokens[2], "UTM") && EQUAL(papszTokens[3], "zone"))
901
        {
902
            iUTMZone = atoi(papszTokens[4]);
903
            iUTMParamsFound++;
904
        }
905
        else if ((CSLCount(papszTokens) >= 4) &&
906
                 EQUAL(papszTokens[0], "project") &&
907
                 EQUAL(papszTokens[1], "origin:"))
908
        {
909
            dfeast = CPLAtof(papszTokens[2]);
910
            dfnorth = CPLAtof(papszTokens[3]);
911
            iUTMParamsFound += 2;
912
        }
913
        else if ((CSLCount(papszTokens) >= 4) &&
914
                 EQUAL(papszTokens[0], "file") &&
915
                 EQUAL(papszTokens[1], "start:"))
916
        {
917
            dfOffsetX = CPLAtof(papszTokens[2]);
918
            dfOffsetY = CPLAtof(papszTokens[3]);
919
            iUTMParamsFound += 2;
920
        }
921
        else if ((CSLCount(papszTokens) >= 6) &&
922
                 EQUAL(papszTokens[0], "pixel") &&
923
                 EQUAL(papszTokens[1], "size") && EQUAL(papszTokens[2], "on") &&
924
                 EQUAL(papszTokens[3], "ground:"))
925
        {
926
            dfxsize = CPLAtof(papszTokens[4]);
927
            dfysize = CPLAtof(papszTokens[5]);
928
            iUTMParamsFound += 2;
929
        }
930
        else if ((CSLCount(papszTokens) >= 4) &&
931
                 EQUAL(papszTokens[0], "number") &&
932
                 EQUAL(papszTokens[1], "of") &&
933
                 EQUAL(papszTokens[2], "pixels:"))
934
        {
935
            nSamples = atoi(papszTokens[3]);
936
        }
937
        else if ((CSLCount(papszTokens) >= 4) &&
938
                 EQUAL(papszTokens[0], "number") &&
939
                 EQUAL(papszTokens[1], "of") && EQUAL(papszTokens[2], "lines:"))
940
        {
941
            nLines = atoi(papszTokens[3]);
942
        }
943
        else if ((CSLCount(papszTokens) >= 4) &&
944
                 EQUAL(papszTokens[0], "number") &&
945
                 EQUAL(papszTokens[1], "of") && EQUAL(papszTokens[2], "bands:"))
946
        {
947
            nBands = atoi(papszTokens[3]);
948
            if (nBands != 16)
949
            {
950
                CPLError(CE_Failure, CPLE_AppDefined,
951
                         "Number of bands has a value %s which does not match "
952
                         "CPG driver\nexpectation (expect a value of 16).",
953
                         papszTokens[3]);
954
                nError = 1;
955
            }
956
        }
957
        else if ((CSLCount(papszTokens) >= 4) &&
958
                 EQUAL(papszTokens[0], "bytes") &&
959
                 EQUAL(papszTokens[1], "per") &&
960
                 EQUAL(papszTokens[2], "pixel:"))
961
        {
962
            iBytesPerPixel = atoi(papszTokens[3]);
963
            if (iBytesPerPixel != 4)
964
            {
965
                CPLError(CE_Failure, CPLE_AppDefined,
966
                         "Bytes per pixel has a value %s which does not match "
967
                         "CPG driver\nexpectation (expect a value of 4).",
968
                         papszTokens[1]);
969
                nError = 1;
970
            }
971
        }
972
        CSLDestroy(papszTokens);
973
    }
974

975
    CSLDestroy(papszHdrLines);
976

977
    /* -------------------------------------------------------------------- */
978
    /*      Check for successful completion.                                */
979
    /* -------------------------------------------------------------------- */
980
    if (nError)
981
    {
982
        CPLFree(pszWorkname);
983
        return NULL;
984
    }
985

986
    if (!GDALCheckDatasetDimensions(nSamples, nLines) ||
987
        !GDALCheckBandCount(nBands, FALSE) || !bInterleaveSpecified ||
988
        iBytesPerPixel == 0)
989
    {
990
        CPLError(CE_Failure, CPLE_AppDefined,
991
                 "%s is missing a required parameter (number of pixels, "
992
                 "number of lines,\number of bands, bytes per pixel, or "
993
                 "data organization).",
994
                 pszWorkname);
995
        CPLFree(pszWorkname);
996
        return NULL;
997
    }
998

999
    /* -------------------------------------------------------------------- */
1000
    /*      Initialize dataset.                                             */
1001
    /* -------------------------------------------------------------------- */
1002
    CPGDataset *poDS = new CPGDataset();
1003

1004
    poDS->nRasterXSize = nSamples;
1005
    poDS->nRasterYSize = nLines;
1006
    poDS->eInterleave = eInterleave;
1007

1008
    /* -------------------------------------------------------------------- */
1009
    /*      Open the 16 bands.                                              */
1010
    /* -------------------------------------------------------------------- */
1011

1012
    AdjustFilename(&pszWorkname, "stokes", "img");
1013
    poDS->afpImage[0] = VSIFOpenL(pszWorkname, "rb");
1014
    if (poDS->afpImage[0] == NULL)
1015
    {
1016
        CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open .img file: %s",
1017
                 pszWorkname);
1018
        CPLFree(pszWorkname);
1019
        delete poDS;
1020
        return NULL;
1021
    }
1022
    aosImageFilenames.push_back(pszWorkname);
1023
    for (int iBand = 0; iBand < 16; iBand++)
1024
    {
1025
        CPG_STOKESRasterBand *poBand =
1026
            new CPG_STOKESRasterBand(poDS, GDT_CFloat32, !CPL_IS_LSB);
1027
        poDS->SetBand(iBand + 1, poBand);
1028
    }
1029

1030
    /* -------------------------------------------------------------------- */
1031
    /*      Set appropriate MATRIX_REPRESENTATION.                          */
1032
    /* -------------------------------------------------------------------- */
1033
    if (poDS->GetRasterCount() == 6)
1034
    {
1035
        poDS->SetMetadataItem("MATRIX_REPRESENTATION", "COVARIANCE");
1036
    }
1037

1038
    /* -------------------------------------------------------------------------
1039
     */
1040
    /*  Add georeferencing, if enough information found. */
1041
    /* -------------------------------------------------------------------------
1042
     */
1043
    if (iUTMParamsFound == 8)
1044
    {
1045
        double dfnorth_center = dfnorth - nLines * dfysize / 2.0;
1046
        poDS->m_gt[0] = dfeast + dfOffsetX;
1047
        poDS->m_gt[1] = dfxsize;
1048
        poDS->m_gt[2] = 0.0;
1049
        poDS->m_gt[3] = dfnorth + dfOffsetY;
1050
        poDS->m_gt[4] = 0.0;
1051
        poDS->m_gt[5] = -1 * dfysize;
1052

1053
        OGRSpatialReference oUTM;
1054
        if (dfnorth_center < 0)
1055
            oUTM.SetUTM(iUTMZone, 0);
1056
        else
1057
            oUTM.SetUTM(iUTMZone, 1);
1058

1059
        /* Assuming WGS84 */
1060
        oUTM.SetWellKnownGeogCS("WGS84");
1061
        CPLFree(poDS->pszProjection);
1062
        poDS->pszProjection = NULL;
1063
        oUTM.exportToWkt(&(poDS->pszProjection));
1064
    }
1065

1066
    return poDS;
1067
}
1068
#endif
1069

1070
/************************************************************************/
1071
/*                                Open()                                */
1072
/************************************************************************/
1073

1074
GDALDataset *CPGDataset::Open(GDALOpenInfo *poOpenInfo)
33,272✔
1075

1076
{
1077
    /* -------------------------------------------------------------------- */
1078
    /*      Is this a PolGASP fileset?  We expect fileset to follow         */
1079
    /*      one of these patterns:                                          */
1080
    /*               1) <stuff>hh<stuff2>.img, <stuff>hh<stuff2>.hdr,       */
1081
    /*                  <stuff>hv<stuff2>.img, <stuff>hv<stuff2>.hdr,       */
1082
    /*                  <stuff>vh<stuff2>.img, <stuff>vh<stuff2>.hdr,       */
1083
    /*                  <stuff>vv<stuff2>.img, <stuff>vv<stuff2>.hdr,       */
1084
    /*                  where <stuff> or <stuff2> should contain the        */
1085
    /*                  substring "sso" or "polgasp"                        */
1086
    /*               2) <stuff>SIRC.hdr and <stuff>SIRC.img                 */
1087
    /*               3) <stuff>.img and <stuff>.img_def                     */
1088
    /*                  where <stuff> should contain the                    */
1089
    /*                  substring "sso" or "polgasp"                        */
1090
    /* -------------------------------------------------------------------- */
1091
    int CPGType = 0;
33,272✔
1092
    if (FindType1(poOpenInfo->pszFilename))
33,272✔
1093
        CPGType = 1;
×
1094
    else if (FindType2(poOpenInfo->pszFilename))
33,266✔
1095
        CPGType = 2;
2✔
1096

1097
    /* Stokes matrix convair data: not quite working yet- something
1098
     * is wrong in the interpretation of the matrix elements in terms
1099
     * of hh, hv, vv, vh.  Data will load if the next two lines are
1100
     * uncommented, but values will be incorrect.  Expect C11 = hh*conj(hh),
1101
     * C12 = hh*conj(hv), etc.  Used geogratis data in both scattering
1102
     * matrix and stokes format for comparison.
1103
     */
1104
    // else if ( FindType3( poOpenInfo->pszFilename ))
1105
    //   CPGType = 3;
1106

1107
    /* Set working name back to original */
1108

1109
    if (CPGType == 0)
33,268✔
1110
    {
1111
        int nNameLen = static_cast<int>(strlen(poOpenInfo->pszFilename));
33,265✔
1112
        if ((nNameLen > 8) &&
33,265✔
1113
            ((strstr(poOpenInfo->pszFilename, "sso") != nullptr) ||
32,587✔
1114
             (strstr(poOpenInfo->pszFilename, "polgasp") != nullptr)) &&
32,589✔
1115
            (EQUAL(poOpenInfo->pszFilename + nNameLen - 4, "img") ||
×
1116
             EQUAL(poOpenInfo->pszFilename + nNameLen - 4, "hdr") ||
×
1117
             EQUAL(poOpenInfo->pszFilename + nNameLen - 7, "img_def")))
×
1118
        {
1119
            CPLError(
×
1120
                CE_Failure, CPLE_OpenFailed,
1121
                "Apparent attempt to open Convair PolGASP data failed as\n"
1122
                "one or more of the required files is missing (eight files\n"
1123
                "are expected for scattering matrix format, two for Stokes).");
1124
        }
1125
        else if ((nNameLen > 8) &&
33,267✔
1126
                 (strstr(poOpenInfo->pszFilename, "SIRC") != nullptr) &&
32,586✔
1127
                 (EQUAL(poOpenInfo->pszFilename + nNameLen - 4, "img") ||
×
1128
                  EQUAL(poOpenInfo->pszFilename + nNameLen - 4, "hdr")))
×
1129
        {
1130
            CPLError(
×
1131
                CE_Failure, CPLE_OpenFailed,
1132
                "Apparent attempt to open SIRC Convair PolGASP data failed \n"
1133
                "as one of the expected files is missing (hdr or img)!");
1134
        }
1135
        return nullptr;
33,265✔
1136
    }
1137

1138
    /* -------------------------------------------------------------------- */
1139
    /*      Confirm the requested access is supported.                      */
1140
    /* -------------------------------------------------------------------- */
1141
    if (poOpenInfo->eAccess == GA_Update)
3✔
1142
    {
1143
        ReportUpdateNotSupportedByDriver("CPG");
×
1144
        return nullptr;
×
1145
    }
1146

1147
    /* Read the header info and create the dataset */
1148
#ifdef notdef
1149
    if (CPGType < 3)
1150
#endif
1151
        CPGDataset *poDS = reinterpret_cast<CPGDataset *>(
1152
            InitializeType1Or2Dataset(poOpenInfo->pszFilename));
3✔
1153
#ifdef notdef
1154
    else
1155
        poDS = reinterpret_cast<CPGDataset *>(
1156
            InitializeType3Dataset(poOpenInfo->pszFilename));
1157
#endif
1158
    if (poDS == nullptr)
2✔
1159
        return nullptr;
×
1160

1161
    /* -------------------------------------------------------------------- */
1162
    /*      Check for overviews.                                            */
1163
    /* -------------------------------------------------------------------- */
1164
    // Need to think about this.
1165
    // poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
1166

1167
    /* -------------------------------------------------------------------- */
1168
    /*      Initialize any PAM information.                                 */
1169
    /* -------------------------------------------------------------------- */
1170
    poDS->SetDescription(poOpenInfo->pszFilename);
2✔
1171
    poDS->TryLoadXML();
2✔
1172

1173
    return poDS;
2✔
1174
}
1175

1176
/************************************************************************/
1177
/*                            GetGCPCount()                             */
1178
/************************************************************************/
1179

1180
int CPGDataset::GetGCPCount()
×
1181

1182
{
1183
    return nGCPCount;
×
1184
}
1185

1186
/************************************************************************/
1187
/*                               GetGCPs()                               */
1188
/************************************************************************/
1189

1190
const GDAL_GCP *CPGDataset::GetGCPs()
×
1191

1192
{
1193
    return pasGCPList;
×
1194
}
1195

1196
/************************************************************************/
1197
/*                          GetGeoTransform()                           */
1198
/************************************************************************/
1199

1200
CPLErr CPGDataset::GetGeoTransform(GDALGeoTransform &gt) const
×
1201

1202
{
1203
    gt = m_gt;
×
1204
    return CE_None;
×
1205
}
1206

1207
/************************************************************************/
1208
/*                           SIRC_QSLCRasterBand()                      */
1209
/************************************************************************/
1210

1211
SIRC_QSLCRasterBand::SIRC_QSLCRasterBand(CPGDataset *poGDSIn, int nBandIn,
8✔
1212
                                         GDALDataType eType)
8✔
1213

1214
{
1215
    poDS = poGDSIn;
8✔
1216
    nBand = nBandIn;
8✔
1217

1218
    eDataType = eType;
8✔
1219

1220
    nBlockXSize = poGDSIn->nRasterXSize;
8✔
1221
    nBlockYSize = 1;
8✔
1222

1223
    if (nBand == 1)
8✔
1224
        SetMetadataItem("POLARIMETRIC_INTERP", "HH");
2✔
1225
    else if (nBand == 2)
6✔
1226
        SetMetadataItem("POLARIMETRIC_INTERP", "HV");
2✔
1227
    else if (nBand == 3)
4✔
1228
        SetMetadataItem("POLARIMETRIC_INTERP", "VH");
2✔
1229
    else if (nBand == 4)
2✔
1230
        SetMetadataItem("POLARIMETRIC_INTERP", "VV");
2✔
1231
}
8✔
1232

1233
/************************************************************************/
1234
/*                             IReadBlock()                             */
1235
/************************************************************************/
1236

1237
/* From: http://southport.jpl.nasa.gov/software/dcomp/dcomp.html
1238

1239
ysca = sqrt{ [ (Byte(2) / 254 ) + 1.5] 2Byte(1) }
1240
Re(SHH) = byte(3) ysca/127
1241
Im(SHH) = byte(4) ysca/127
1242
Re(SHV) = byte(5) ysca/127
1243
Im(SHV) = byte(6) ysca/127
1244
Re(SVH) = byte(7) ysca/127
1245
Im(SVH) = byte(8) ysca/127
1246
Re(SVV) = byte(9) ysca/127
1247
Im(SVV) = byte(10) ysca/127
1248
*/
1249

1250
CPLErr SIRC_QSLCRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff,
1✔
1251
                                       int nBlockYOff, void *pImage)
1252
{
1253
    const int nBytesPerSample = 10;
1✔
1254
    CPGDataset *poGDS = cpl::down_cast<CPGDataset *>(poDS);
1✔
1255
    const vsi_l_offset offset =
1✔
1256
        static_cast<vsi_l_offset>(nBlockXSize) * nBlockYOff * nBytesPerSample;
1✔
1257

1258
    /* -------------------------------------------------------------------- */
1259
    /*      Load all the pixel data associated with this scanline.          */
1260
    /* -------------------------------------------------------------------- */
1261
    if (nBytesPerSample > INT_MAX / nBlockXSize)
1✔
1262
    {
1263
        CPLError(CE_Failure, CPLE_AppDefined, "Too large nBlockXSize");
×
1264
        return CE_Failure;
×
1265
    }
1266
    const int nBytesToRead = nBytesPerSample * nBlockXSize;
1✔
1267

1268
    signed char *pabyRecord =
1269
        static_cast<signed char *>(VSI_MALLOC_VERBOSE(nBytesToRead));
1✔
1270
    if (!pabyRecord)
1✔
1271
        return CE_Failure;
×
1272

1273
    if (VSIFSeekL(poGDS->afpImage[0], offset, SEEK_SET) != 0 ||
2✔
1274
        static_cast<int>(VSIFReadL(pabyRecord, 1, nBytesToRead,
1✔
1275
                                   poGDS->afpImage[0])) != nBytesToRead)
2✔
1276
    {
1277
        CPLError(CE_Failure, CPLE_FileIO,
×
1278
                 "Error reading %d bytes of SIRC Convair at offset %" PRIu64
1279
                 ".\n"
1280
                 "Reading file %s failed.",
1281
                 nBytesToRead, static_cast<uint64_t>(offset),
1282
                 poGDS->GetDescription());
×
1283
        CPLFree(pabyRecord);
×
1284
        return CE_Failure;
×
1285
    }
1286

1287
    /* -------------------------------------------------------------------- */
1288
    /*      Initialize our power table if this is our first time through.   */
1289
    /* -------------------------------------------------------------------- */
1290
    static float afPowTable[256];
1291
    [[maybe_unused]] static bool bPowTableInitialized = []()
1✔
1292
    {
1293
        for (int i = 0; i < 256; i++)
257✔
1294
        {
1295
            afPowTable[i] = static_cast<float>(pow(2.0, i - 128));
256✔
1296
        }
1297
        return true;
1✔
1298
    }();
1✔
1299

1300
    /* -------------------------------------------------------------------- */
1301
    /*      Copy the desired band out based on the size of the type, and    */
1302
    /*      the interleaving mode.                                          */
1303
    /* -------------------------------------------------------------------- */
1304
    for (int iX = 0; iX < nBlockXSize; iX++)
2✔
1305
    {
1306
        /* A ones based alias */
1307
        const signed char *pabyIn = pabyRecord + iX * nBytesPerSample - 1;
1✔
1308

1309
        /* coverity[tainted_data] */
1310
        const float fScale = static_cast<float>(
1311
            sqrt((static_cast<double>(pabyIn[2]) / 254 + 1.5) *
1✔
1312
                 afPowTable[pabyIn[1] + 128]) /
1✔
1313
            127.0);
1✔
1314

1315
        float *pafImage = static_cast<float *>(pImage);
1✔
1316

1317
        if (nBand == 1)
1✔
1318
        {
1319
            const float fReSHH = static_cast<float>(pabyIn[3] * fScale);
1✔
1320
            const float fImSHH = static_cast<float>(pabyIn[4] * fScale);
1✔
1321

1322
            pafImage[iX * 2] = fReSHH;
1✔
1323
            pafImage[iX * 2 + 1] = fImSHH;
1✔
1324
        }
1325
        else if (nBand == 2)
×
1326
        {
1327
            const float fReSHV = static_cast<float>(pabyIn[5] * fScale);
×
1328
            const float fImSHV = static_cast<float>(pabyIn[6] * fScale);
×
1329

1330
            pafImage[iX * 2] = fReSHV;
×
1331
            pafImage[iX * 2 + 1] = fImSHV;
×
1332
        }
1333
        else if (nBand == 3)
×
1334
        {
1335
            const float fReSVH = static_cast<float>(pabyIn[7] * fScale);
×
1336
            const float fImSVH = static_cast<float>(pabyIn[8] * fScale);
×
1337

1338
            pafImage[iX * 2] = fReSVH;
×
1339
            pafImage[iX * 2 + 1] = fImSVH;
×
1340
        }
1341
        else if (nBand == 4)
×
1342
        {
1343
            const float fReSVV = static_cast<float>(pabyIn[9] * fScale);
×
1344
            const float fImSVV = static_cast<float>(pabyIn[10] * fScale);
×
1345

1346
            pafImage[iX * 2] = fReSVV;
×
1347
            pafImage[iX * 2 + 1] = fImSVV;
×
1348
        }
1349
    }
1350

1351
    CPLFree(pabyRecord);
1✔
1352

1353
    return CE_None;
1✔
1354
}
1355

1356
/************************************************************************/
1357
/*                        CPG_STOKESRasterBand()                        */
1358
/************************************************************************/
1359

1360
CPG_STOKESRasterBand::CPG_STOKESRasterBand(GDALDataset *poDSIn,
×
1361
                                           GDALDataType eType,
1362
                                           int bNativeOrderIn)
×
1363
    : bNativeOrder(bNativeOrderIn)
×
1364
{
1365
    static const char *const apszPolarizations[16] = {
1366
        "Covariance_11", "Covariance_12", "Covariance_13", "Covariance_14",
1367
        "Covariance_21", "Covariance_22", "Covariance_23", "Covariance_24",
1368
        "Covariance_31", "Covariance_32", "Covariance_33", "Covariance_34",
1369
        "Covariance_41", "Covariance_42", "Covariance_43", "Covariance_44"};
1370

1371
    poDS = poDSIn;
×
1372
    eDataType = eType;
×
1373

1374
    nBlockXSize = poDSIn->GetRasterXSize();
×
1375
    nBlockYSize = 1;
×
1376

1377
    SetMetadataItem("POLARIMETRIC_INTERP", apszPolarizations[nBand - 1]);
×
1378
    SetDescription(apszPolarizations[nBand - 1]);
×
1379
}
×
1380

1381
/************************************************************************/
1382
/*                             IReadBlock()                             */
1383
/************************************************************************/
1384

1385
/* Convert from Stokes to Covariance representation */
1386

1387
CPLErr CPG_STOKESRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff,
×
1388
                                        int nBlockYOff, void *pImage)
1389

1390
{
1391
    CPLAssert(nBlockXOff == 0);
×
1392

1393
    int m11, /* m12, */ m13, m14, /* m21, */ m22, m23, m24, step;
1394
    int m31, m32, m33, m34, m41, m42, m43, m44;
1395
    CPGDataset *poGDS = reinterpret_cast<CPGDataset *>(poDS);
×
1396

1397
    CPLErr eErr = poGDS->LoadStokesLine(nBlockYOff, bNativeOrder);
×
1398
    if (eErr != CE_None)
×
1399
        return eErr;
×
1400

1401
    float *M = poGDS->padfStokesMatrix;
×
1402
    float *pafLine = reinterpret_cast<float *>(pImage);
×
1403

1404
    if (poGDS->eInterleave == RawDataset::Interleave::BIP)
×
1405
    {
1406
        step = 16;
×
1407
        m11 = M11;
×
1408
        // m12 = M12;
1409
        m13 = M13;
×
1410
        m14 = M14;
×
1411
        // m21 = M21;
1412
        m22 = M22;
×
1413
        m23 = M23;
×
1414
        m24 = M24;
×
1415
        m31 = M31;
×
1416
        m32 = M32;
×
1417
        m33 = M33;
×
1418
        m34 = M34;
×
1419
        m41 = M41;
×
1420
        m42 = M42;
×
1421
        m43 = M43;
×
1422
        m44 = M44;
×
1423
    }
1424
    else
1425
    {
1426
        step = 1;
×
1427
        m11 = 0;
×
1428
        // m12=nRasterXSize;
1429
        m13 = nRasterXSize * 2;
×
1430
        m14 = nRasterXSize * 3;
×
1431
        // m21=nRasterXSize*4;
1432
        m22 = nRasterXSize * 5;
×
1433
        m23 = nRasterXSize * 6;
×
1434
        m24 = nRasterXSize * 7;
×
1435
        m31 = nRasterXSize * 8;
×
1436
        m32 = nRasterXSize * 9;
×
1437
        m33 = nRasterXSize * 10;
×
1438
        m34 = nRasterXSize * 11;
×
1439
        m41 = nRasterXSize * 12;
×
1440
        m42 = nRasterXSize * 13;
×
1441
        m43 = nRasterXSize * 14;
×
1442
        m44 = nRasterXSize * 15;
×
1443
    }
1444
    if (nBand == 1) /* C11 */
×
1445
    {
1446
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1447
        {
1448
            pafLine[iPixel * 2 + 0] = M[m11] - M[m22] - M[m33] + M[m44];
×
1449
            pafLine[iPixel * 2 + 1] = 0.0;
×
1450
            m11 += step;
×
1451
            m22 += step;
×
1452
            m33 += step;
×
1453
            m44 += step;
×
1454
        }
1455
    }
1456
    else if (nBand == 2) /* C12 */
×
1457
    {
1458
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1459
        {
1460
            pafLine[iPixel * 2 + 0] = M[m13] - M[m23];
×
1461
            pafLine[iPixel * 2 + 1] = M[m14] - M[m24];
×
1462
            m13 += step;
×
1463
            m23 += step;
×
1464
            m14 += step;
×
1465
            m24 += step;
×
1466
        }
1467
    }
1468
    else if (nBand == 3) /* C13 */
×
1469
    {
1470
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1471
        {
1472
            pafLine[iPixel * 2 + 0] = M[m33] - M[m44];
×
1473
            pafLine[iPixel * 2 + 1] = M[m43] + M[m34];
×
1474
            m33 += step;
×
1475
            m44 += step;
×
1476
            m43 += step;
×
1477
            m34 += step;
×
1478
        }
1479
    }
1480
    else if (nBand == 4) /* C14 */
×
1481
    {
1482
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1483
        {
1484
            pafLine[iPixel * 2 + 0] = M[m31] - M[m32];
×
1485
            pafLine[iPixel * 2 + 1] = M[m41] - M[m42];
×
1486
            m31 += step;
×
1487
            m32 += step;
×
1488
            m41 += step;
×
1489
            m42 += step;
×
1490
        }
1491
    }
1492
    else if (nBand == 5) /* C21 */
×
1493
    {
1494
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1495
        {
1496
            pafLine[iPixel * 2 + 0] = M[m13] - M[m23];
×
1497
            pafLine[iPixel * 2 + 1] = M[m24] - M[m14];
×
1498
            m13 += step;
×
1499
            m23 += step;
×
1500
            m14 += step;
×
1501
            m24 += step;
×
1502
        }
1503
    }
1504
    else if (nBand == 6) /* C22 */
×
1505
    {
1506
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1507
        {
1508
            pafLine[iPixel * 2 + 0] = M[m11] + M[m22] - M[m33] - M[m44];
×
1509
            pafLine[iPixel * 2 + 1] = 0.0;
×
1510
            m11 += step;
×
1511
            m22 += step;
×
1512
            m33 += step;
×
1513
            m44 += step;
×
1514
        }
1515
    }
1516
    else if (nBand == 7) /* C23 */
×
1517
    {
1518
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1519
        {
1520
            pafLine[iPixel * 2 + 0] = M[m31] + M[m32];
×
1521
            pafLine[iPixel * 2 + 1] = M[m41] + M[m42];
×
1522
            m31 += step;
×
1523
            m32 += step;
×
1524
            m41 += step;
×
1525
            m42 += step;
×
1526
        }
1527
    }
1528
    else if (nBand == 8) /* C24 */
×
1529
    {
1530
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1531
        {
1532
            pafLine[iPixel * 2 + 0] = M[m33] + M[m44];
×
1533
            pafLine[iPixel * 2 + 1] = M[m43] - M[m34];
×
1534
            m33 += step;
×
1535
            m44 += step;
×
1536
            m43 += step;
×
1537
            m34 += step;
×
1538
        }
1539
    }
1540
    else if (nBand == 9) /* C31 */
×
1541
    {
1542
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1543
        {
1544
            pafLine[iPixel * 2 + 0] = M[m33] - M[m44];
×
1545
            pafLine[iPixel * 2 + 1] = -1 * M[m43] - M[m34];
×
1546
            m33 += step;
×
1547
            m44 += step;
×
1548
            m43 += step;
×
1549
            m34 += step;
×
1550
        }
1551
    }
1552
    else if (nBand == 10) /* C32 */
×
1553
    {
1554
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1555
        {
1556
            pafLine[iPixel * 2 + 0] = M[m31] + M[m32];
×
1557
            pafLine[iPixel * 2 + 1] = -1 * M[m41] - M[m42];
×
1558
            m31 += step;
×
1559
            m32 += step;
×
1560
            m41 += step;
×
1561
            m42 += step;
×
1562
        }
1563
    }
1564
    else if (nBand == 11) /* C33 */
×
1565
    {
1566
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1567
        {
1568
            pafLine[iPixel * 2 + 0] = M[m11] + M[m22] + M[m33] + M[m44];
×
1569
            pafLine[iPixel * 2 + 1] = 0.0;
×
1570
            m11 += step;
×
1571
            m22 += step;
×
1572
            m33 += step;
×
1573
            m44 += step;
×
1574
        }
1575
    }
1576
    else if (nBand == 12) /* C34 */
×
1577
    {
1578
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1579
        {
1580
            pafLine[iPixel * 2 + 0] = M[m13] - M[m23];
×
1581
            pafLine[iPixel * 2 + 1] = -1 * M[m14] - M[m24];
×
1582
            m13 += step;
×
1583
            m23 += step;
×
1584
            m14 += step;
×
1585
            m24 += step;
×
1586
        }
1587
    }
1588
    else if (nBand == 13) /* C41 */
×
1589
    {
1590
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1591
        {
1592
            pafLine[iPixel * 2 + 0] = M[m31] - M[m32];
×
1593
            pafLine[iPixel * 2 + 1] = M[m42] - M[m41];
×
1594
            m31 += step;
×
1595
            m32 += step;
×
1596
            m41 += step;
×
1597
            m42 += step;
×
1598
        }
1599
    }
1600
    else if (nBand == 14) /* C42 */
×
1601
    {
1602
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1603
        {
1604
            pafLine[iPixel * 2 + 0] = M[m33] + M[m44];
×
1605
            pafLine[iPixel * 2 + 1] = M[m34] - M[m43];
×
1606
            m33 += step;
×
1607
            m44 += step;
×
1608
            m43 += step;
×
1609
            m34 += step;
×
1610
        }
1611
    }
1612
    else if (nBand == 15) /* C43 */
×
1613
    {
1614
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1615
        {
1616
            pafLine[iPixel * 2 + 0] = M[m13] - M[m23];
×
1617
            pafLine[iPixel * 2 + 1] = M[m14] + M[m24];
×
1618
            m13 += step;
×
1619
            m23 += step;
×
1620
            m14 += step;
×
1621
            m24 += step;
×
1622
        }
1623
    }
1624
    else /* C44 */
1625
    {
1626
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
×
1627
        {
1628
            pafLine[iPixel * 2 + 0] = M[m11] - M[m22] + M[m33] - M[m44];
×
1629
            pafLine[iPixel * 2 + 1] = 0.0;
×
1630
            m11 += step;
×
1631
            m22 += step;
×
1632
            m33 += step;
×
1633
            m44 += step;
×
1634
        }
1635
    }
1636

1637
    return CE_None;
×
1638
}
1639

1640
/************************************************************************/
1641
/*                         GDALRegister_CPG()                           */
1642
/************************************************************************/
1643

1644
void GDALRegister_CPG()
1,911✔
1645

1646
{
1647
    if (GDALGetDriverByName("CPG") != nullptr)
1,911✔
1648
        return;
282✔
1649

1650
    GDALDriver *poDriver = new GDALDriver();
1,629✔
1651

1652
    poDriver->SetDescription("CPG");
1,629✔
1653
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1,629✔
1654
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Convair PolGASP");
1,629✔
1655
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1,629✔
1656

1657
    poDriver->pfnOpen = CPGDataset::Open;
1,629✔
1658

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