Coverage Report

Created: 2026-06-30 08:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/raw/cpgdataset.cpp
Line
Count
Source
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 "gdal_priv.h"
17
#include "ogr_spatialref.h"
18
#include "rawdataset.h"
19
20
#include <cinttypes>
21
#include <vector>
22
23
/************************************************************************/
24
/* ==================================================================== */
25
/*                              CPGDataset                              */
26
/* ==================================================================== */
27
/************************************************************************/
28
29
class SIRC_QSLCRasterBand;
30
class CPG_STOKESRasterBand;
31
32
class CPGDataset final : public RawDataset
33
{
34
    friend class SIRC_QSLCRasterBand;
35
    friend class CPG_STOKESRasterBand;
36
37
    static constexpr int NUMBER_OF_BANDS = 4;
38
    std::vector<VSILFILE *> afpImage{NUMBER_OF_BANDS};
39
    std::vector<CPLString> aosImageFilenames{};
40
41
    int nGCPCount;
42
    GDAL_GCP *pasGCPList;
43
    OGRSpatialReference m_oGCPSRS{};
44
45
    GDALGeoTransform m_gt{};
46
    OGRSpatialReference m_oSRS{};
47
48
    int nLoadedStokesLine;
49
    float *padfStokesMatrix;
50
51
    Interleave eInterleave = Interleave::BSQ;
52
    static int AdjustFilename(char **, const char *, const char *);
53
    static int FindType1(const char *pszWorkname);
54
    static int FindType2(const char *pszWorkname);
55
#ifdef notdef
56
    static int FindType3(const char *pszWorkname);
57
#endif
58
    static GDALDataset *InitializeType1Or2Dataset(const char *pszWorkname);
59
#ifdef notdef
60
    static GDALDataset *InitializeType3Dataset(const char *pszWorkname);
61
#endif
62
    CPLErr LoadStokesLine(int iLine, int bNativeOrder);
63
64
    CPL_DISALLOW_COPY_ASSIGN(CPGDataset)
65
66
    CPLErr Close(GDALProgressFunc = nullptr, void * = nullptr) override;
67
68
  public:
69
    CPGDataset();
70
    ~CPGDataset() override;
71
72
    int GetGCPCount() override;
73
74
    const OGRSpatialReference *GetGCPSpatialRef() const override
75
0
    {
76
0
        return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
77
0
    }
78
79
    const GDAL_GCP *GetGCPs() override;
80
81
    const OGRSpatialReference *GetSpatialRef() const override
82
0
    {
83
0
        return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
84
0
    }
85
86
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
87
88
    char **GetFileList() override;
89
90
    static GDALDataset *Open(GDALOpenInfo *);
91
};
92
93
/************************************************************************/
94
/*                             CPGDataset()                             */
95
/************************************************************************/
96
97
CPGDataset::CPGDataset()
98
0
    : nGCPCount(0), pasGCPList(nullptr), nLoadedStokesLine(-1),
99
0
      padfStokesMatrix(nullptr)
100
0
{
101
0
    m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
102
0
    m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
103
0
}
104
105
/************************************************************************/
106
/*                            ~CPGDataset()                             */
107
/************************************************************************/
108
109
CPGDataset::~CPGDataset()
110
111
0
{
112
0
    CPGDataset::Close();
113
0
}
114
115
/************************************************************************/
116
/*                               Close()                                */
117
/************************************************************************/
118
119
CPLErr CPGDataset::Close(GDALProgressFunc, void *)
120
0
{
121
0
    CPLErr eErr = CE_None;
122
0
    if (nOpenFlags != OPEN_FLAGS_CLOSED)
123
0
    {
124
0
        if (CPGDataset::FlushCache(true) != CE_None)
125
0
            eErr = CE_Failure;
126
127
0
        for (auto poFile : afpImage)
128
0
        {
129
0
            if (poFile != nullptr)
130
0
                VSIFCloseL(poFile);
131
0
        }
132
133
0
        if (nGCPCount > 0)
134
0
        {
135
0
            GDALDeinitGCPs(nGCPCount, pasGCPList);
136
0
            CPLFree(pasGCPList);
137
0
        }
138
139
0
        CPLFree(padfStokesMatrix);
140
141
0
        if (GDALPamDataset::Close() != CE_None)
142
0
            eErr = CE_Failure;
143
0
    }
144
0
    return eErr;
145
0
}
146
147
/************************************************************************/
148
/*                            GetFileList()                             */
149
/************************************************************************/
150
151
char **CPGDataset::GetFileList()
152
153
0
{
154
0
    char **papszFileList = RawDataset::GetFileList();
155
0
    for (size_t i = 0; i < aosImageFilenames.size(); ++i)
156
0
        papszFileList = CSLAddString(papszFileList, aosImageFilenames[i]);
157
0
    return papszFileList;
158
0
}
159
160
/************************************************************************/
161
/* ==================================================================== */
162
/*                          SIRC_QSLCPRasterBand                        */
163
/* ==================================================================== */
164
/************************************************************************/
165
166
class SIRC_QSLCRasterBand final : public GDALRasterBand
167
{
168
    friend class CPGDataset;
169
170
  public:
171
    SIRC_QSLCRasterBand(CPGDataset *, int, GDALDataType);
172
173
    ~SIRC_QSLCRasterBand() override
174
0
    {
175
0
    }
176
177
    CPLErr IReadBlock(int, int, void *) override;
178
};
179
180
constexpr int M11 = 0;
181
// constexpr int M12 = 1;
182
constexpr int M13 = 2;
183
constexpr int M14 = 3;
184
// constexpr int M21 = 4;
185
constexpr int M22 = 5;
186
constexpr int M23 = 6;
187
constexpr int M24 = 7;
188
constexpr int M31 = 8;
189
constexpr int M32 = 9;
190
constexpr int M33 = 10;
191
constexpr int M34 = 11;
192
constexpr int M41 = 12;
193
constexpr int M42 = 13;
194
constexpr int M43 = 14;
195
constexpr int M44 = 15;
196
197
/************************************************************************/
198
/* ==================================================================== */
199
/*                          CPG_STOKESRasterBand                        */
200
/* ==================================================================== */
201
/************************************************************************/
202
203
class CPG_STOKESRasterBand final : public GDALRasterBand
204
{
205
    friend class CPGDataset;
206
207
    int bNativeOrder;
208
209
  public:
210
    CPG_STOKESRasterBand(GDALDataset *poDS, GDALDataType eType,
211
                         int bNativeOrder);
212
213
    ~CPG_STOKESRasterBand() override
214
0
    {
215
0
    }
216
217
    CPLErr IReadBlock(int, int, void *) override;
218
};
219
220
/************************************************************************/
221
/*                           AdjustFilename()                           */
222
/*                                                                      */
223
/*      Try to find the file with the request polarization and          */
224
/*      extension and update the passed filename accordingly.           */
225
/*                                                                      */
226
/*      Return TRUE if file found otherwise FALSE.                      */
227
/************************************************************************/
228
229
int CPGDataset::AdjustFilename(char **pszFilename, const char *pszPolarization,
230
                               const char *pszExtension)
231
232
176
{
233
    // TODO: Eventually we should handle upper/lower case.
234
176
    if (EQUAL(pszPolarization, "stokes"))
235
0
    {
236
0
        const std::string osNewName =
237
0
            CPLResetExtensionSafe(*pszFilename, pszExtension);
238
0
        CPLFree(*pszFilename);
239
0
        *pszFilename = CPLStrdup(osNewName.c_str());
240
0
    }
241
176
    else if (strlen(pszPolarization) == 2)
242
0
    {
243
0
        char *subptr = strstr(*pszFilename, "hh");
244
0
        if (subptr == nullptr)
245
0
            subptr = strstr(*pszFilename, "hv");
246
0
        if (subptr == nullptr)
247
0
            subptr = strstr(*pszFilename, "vv");
248
0
        if (subptr == nullptr)
249
0
            subptr = strstr(*pszFilename, "vh");
250
0
        if (subptr == nullptr)
251
0
            return FALSE;
252
253
0
        strncpy(subptr, pszPolarization, 2);
254
0
        const std::string osNewName =
255
0
            CPLResetExtensionSafe(*pszFilename, pszExtension);
256
0
        CPLFree(*pszFilename);
257
0
        *pszFilename = CPLStrdup(osNewName.c_str());
258
0
    }
259
176
    else
260
176
    {
261
176
        const std::string osNewName =
262
176
            CPLResetExtensionSafe(*pszFilename, pszExtension);
263
176
        CPLFree(*pszFilename);
264
176
        *pszFilename = CPLStrdup(osNewName.c_str());
265
176
    }
266
176
    VSIStatBufL sStatBuf;
267
176
    return VSIStatL(*pszFilename, &sStatBuf) == 0;
268
176
}
269
270
/************************************************************************/
271
/*         Search for the various types of Convair filesets             */
272
/*         Return TRUE for a match, FALSE for no match                  */
273
/************************************************************************/
274
int CPGDataset::FindType1(const char *pszFilename)
275
465k
{
276
465k
    const int nNameLen = static_cast<int>(strlen(pszFilename));
277
278
465k
    if ((strstr(pszFilename, "sso") == nullptr) &&
279
464k
        (strstr(pszFilename, "polgasp") == nullptr))
280
464k
        return FALSE;
281
282
384
    if ((strlen(pszFilename) < 5) ||
283
383
        (!EQUAL(pszFilename + nNameLen - 4, ".hdr") &&
284
383
         !EQUAL(pszFilename + nNameLen - 4, ".img")))
285
384
        return FALSE;
286
287
    /* Expect all bands and headers to be present */
288
0
    char *pszTemp = CPLStrdup(pszFilename);
289
290
0
    const bool bNotFound = !AdjustFilename(&pszTemp, "hh", "img") ||
291
0
                           !AdjustFilename(&pszTemp, "hh", "hdr") ||
292
0
                           !AdjustFilename(&pszTemp, "hv", "img") ||
293
0
                           !AdjustFilename(&pszTemp, "hv", "hdr") ||
294
0
                           !AdjustFilename(&pszTemp, "vh", "img") ||
295
0
                           !AdjustFilename(&pszTemp, "vh", "hdr") ||
296
0
                           !AdjustFilename(&pszTemp, "vv", "img") ||
297
0
                           !AdjustFilename(&pszTemp, "vv", "hdr");
298
299
0
    CPLFree(pszTemp);
300
301
0
    return !bNotFound;
302
384
}
303
304
int CPGDataset::FindType2(const char *pszFilename)
305
465k
{
306
465k
    const int nNameLen = static_cast<int>(strlen(pszFilename));
307
308
465k
    if ((strlen(pszFilename) < 9) ||
309
449k
        (!EQUAL(pszFilename + nNameLen - 8, "SIRC.hdr") &&
310
449k
         !EQUAL(pszFilename + nNameLen - 8, "SIRC.img")))
311
465k
        return FALSE;
312
313
96
    char *pszTemp = CPLStrdup(pszFilename);
314
96
    const bool bNotFound = !AdjustFilename(&pszTemp, "", "img") ||
315
80
                           !AdjustFilename(&pszTemp, "", "hdr");
316
96
    CPLFree(pszTemp);
317
318
96
    return !bNotFound;
319
465k
}
320
321
#ifdef notdef
322
int CPGDataset::FindType3(const char *pszFilename)
323
{
324
    const int nNameLen = static_cast<int>(strlen(pszFilename));
325
326
    if ((strstr(pszFilename, "sso") == NULL) &&
327
        (strstr(pszFilename, "polgasp") == NULL))
328
        return FALSE;
329
330
    if ((strlen(pszFilename) < 9) ||
331
        (!EQUAL(pszFilename + nNameLen - 4, ".img") &&
332
         !EQUAL(pszFilename + nNameLen - 8, ".img_def")))
333
        return FALSE;
334
335
    char *pszTemp = CPLStrdup(pszFilename);
336
    const bool bNotFound = !AdjustFilename(&pszTemp, "stokes", "img") ||
337
                           !AdjustFilename(&pszTemp, "stokes", "img_def");
338
    CPLFree(pszTemp);
339
340
    return !bNotFound;
341
}
342
#endif
343
344
/************************************************************************/
345
/*                           LoadStokesLine()                           */
346
/************************************************************************/
347
348
CPLErr CPGDataset::LoadStokesLine(int iLine, int bNativeOrder)
349
350
0
{
351
0
    if (iLine == nLoadedStokesLine)
352
0
        return CE_None;
353
354
0
    constexpr int nDataSize = static_cast<int>(sizeof(float));
355
356
    /* -------------------------------------------------------------------- */
357
    /*      allocate working buffers if we don't have them already.         */
358
    /* -------------------------------------------------------------------- */
359
0
    if (padfStokesMatrix == nullptr)
360
0
    {
361
0
        padfStokesMatrix = reinterpret_cast<float *>(
362
0
            CPLMalloc(sizeof(float) * nRasterXSize * 16));
363
0
    }
364
365
    /* -------------------------------------------------------------------- */
366
    /*      Load all the pixel data associated with this scanline.          */
367
    /*      Retains same interleaving as original dataset.                  */
368
    /* -------------------------------------------------------------------- */
369
0
    if (eInterleave == Interleave::BIP)
370
0
    {
371
0
        const vsi_l_offset offset =
372
0
            static_cast<vsi_l_offset>(nRasterXSize) * iLine * nDataSize * 16;
373
0
        const int nBytesToRead = nDataSize * nRasterXSize * 16;
374
0
        if ((VSIFSeekL(afpImage[0], offset, SEEK_SET) != 0) ||
375
0
            static_cast<int>(
376
0
                VSIFReadL(reinterpret_cast<GByte *>(padfStokesMatrix), 1,
377
0
                          nBytesToRead, afpImage[0])) != nBytesToRead)
378
0
        {
379
0
            CPLError(
380
0
                CE_Failure, CPLE_FileIO,
381
0
                "Error reading %d bytes of Stokes Convair at offset %" PRIu64
382
0
                ".\n"
383
0
                "Reading file %s failed.",
384
0
                nBytesToRead, static_cast<uint64_t>(offset), GetDescription());
385
0
            CPLFree(padfStokesMatrix);
386
0
            padfStokesMatrix = nullptr;
387
0
            nLoadedStokesLine = -1;
388
0
            return CE_Failure;
389
0
        }
390
0
    }
391
0
    else if (eInterleave == Interleave::BIL)
392
0
    {
393
0
        for (int band_index = 0; band_index < 16; band_index++)
394
0
        {
395
0
            const vsi_l_offset offset =
396
0
                nDataSize * static_cast<vsi_l_offset>(nRasterXSize) *
397
0
                (iLine + band_index);
398
0
            const int nBytesToRead = nDataSize * nRasterXSize;
399
0
            if ((VSIFSeekL(afpImage[0], offset, SEEK_SET) != 0) ||
400
0
                static_cast<int>(
401
0
                    VSIFReadL(reinterpret_cast<GByte *>(
402
0
                                  padfStokesMatrix + nBytesToRead * band_index),
403
0
                              1, nBytesToRead, afpImage[0])) != nBytesToRead)
404
0
            {
405
0
                CPLError(CE_Failure, CPLE_FileIO,
406
0
                         "Error reading %d bytes of Stokes Convair at offset "
407
0
                         "%" PRIu64 ".\n"
408
0
                         "Reading file %s failed.",
409
0
                         nBytesToRead, static_cast<uint64_t>(offset),
410
0
                         GetDescription());
411
0
                CPLFree(padfStokesMatrix);
412
0
                padfStokesMatrix = nullptr;
413
0
                nLoadedStokesLine = -1;
414
0
                return CE_Failure;
415
0
            }
416
0
        }
417
0
    }
418
0
    else
419
0
    {
420
0
        for (int band_index = 0; band_index < 16; band_index++)
421
0
        {
422
0
            const vsi_l_offset offset =
423
0
                nDataSize * nRasterXSize *
424
0
                (iLine + static_cast<vsi_l_offset>(nRasterYSize) * band_index);
425
0
            const int nBytesToRead = nDataSize * nRasterXSize;
426
0
            if ((VSIFSeekL(afpImage[0], offset, SEEK_SET) != 0) ||
427
0
                static_cast<int>(
428
0
                    VSIFReadL(reinterpret_cast<GByte *>(
429
0
                                  padfStokesMatrix + nBytesToRead * band_index),
430
0
                              1, nBytesToRead, afpImage[0])) != nBytesToRead)
431
0
            {
432
0
                CPLError(CE_Failure, CPLE_FileIO,
433
0
                         "Error reading %d bytes of Stokes Convair at offset "
434
0
                         "%" PRIu64 ".\n"
435
0
                         "Reading file %s failed.",
436
0
                         nBytesToRead, static_cast<uint64_t>(offset),
437
0
                         GetDescription());
438
0
                CPLFree(padfStokesMatrix);
439
0
                padfStokesMatrix = nullptr;
440
0
                nLoadedStokesLine = -1;
441
0
                return CE_Failure;
442
0
            }
443
0
        }
444
0
    }
445
446
0
    if (!bNativeOrder)
447
0
        GDALSwapWords(padfStokesMatrix, nDataSize, nRasterXSize * 16,
448
0
                      nDataSize);
449
450
0
    nLoadedStokesLine = iLine;
451
452
0
    return CE_None;
453
0
}
454
455
/************************************************************************/
456
/*       Parse header information and initialize dataset for the        */
457
/*       appropriate Convair dataset style.                             */
458
/*       Returns dataset if successful; NULL if there was a problem.    */
459
/************************************************************************/
460
461
GDALDataset *CPGDataset::InitializeType1Or2Dataset(const char *pszFilename)
462
0
{
463
464
    /* -------------------------------------------------------------------- */
465
    /*      Read the .hdr file (the hh one for the .sso and polgasp cases)  */
466
    /*      and parse it.                                                   */
467
    /* -------------------------------------------------------------------- */
468
0
    int nLines = 0;
469
0
    int nSamples = 0;
470
0
    int nError = 0;
471
472
    /* Parameters required for pseudo-geocoding.  GCPs map */
473
    /* slant range to ground range at 16 points.           */
474
0
    int iGeoParamsFound = 0;
475
0
    int itransposed = 0;
476
0
    double dfaltitude = 0.0;
477
0
    double dfnear_srd = 0.0;
478
0
    double dfsample_size = 0.0;
479
0
    double dfsample_size_az = 0.0;
480
481
    /* Parameters in geogratis geocoded images */
482
0
    int iUTMParamsFound = 0;
483
0
    int iUTMZone = 0;
484
    // int iCorner = 0;
485
0
    double dfnorth = 0.0;
486
0
    double dfeast = 0.0;
487
488
0
    std::string osWorkName;
489
0
    {
490
0
        char *pszWorkname = CPLStrdup(pszFilename);
491
0
        AdjustFilename(&pszWorkname, "hh", "hdr");
492
0
        osWorkName = pszWorkname;
493
0
        CPLFree(pszWorkname);
494
0
    }
495
496
0
    char **papszHdrLines = CSLLoad(osWorkName.c_str());
497
498
0
    for (int iLine = 0; papszHdrLines && papszHdrLines[iLine] != nullptr;
499
0
         iLine++)
500
0
    {
501
0
        char **papszTokens = CSLTokenizeString(papszHdrLines[iLine]);
502
503
        /* Note: some cv580 file seem to have comments with #, hence the >=
504
         *       instead of = for token checking, and the equalN for the corner.
505
         */
506
507
0
        if (CSLCount(papszTokens) < 2)
508
0
        {
509
0
            /* ignore */;
510
0
        }
511
0
        else if ((CSLCount(papszTokens) >= 3) &&
512
0
                 EQUAL(papszTokens[0], "reference") &&
513
0
                 EQUAL(papszTokens[1], "north"))
514
0
        {
515
0
            dfnorth = CPLAtof(papszTokens[2]);
516
0
            iUTMParamsFound++;
517
0
        }
518
0
        else if ((CSLCount(papszTokens) >= 3) &&
519
0
                 EQUAL(papszTokens[0], "reference") &&
520
0
                 EQUAL(papszTokens[1], "east"))
521
0
        {
522
0
            dfeast = CPLAtof(papszTokens[2]);
523
0
            iUTMParamsFound++;
524
0
        }
525
0
        else if ((CSLCount(papszTokens) >= 5) &&
526
0
                 EQUAL(papszTokens[0], "reference") &&
527
0
                 EQUAL(papszTokens[1], "projection") &&
528
0
                 EQUAL(papszTokens[2], "UTM") && EQUAL(papszTokens[3], "zone"))
529
0
        {
530
0
            iUTMZone = atoi(papszTokens[4]);
531
0
            iUTMParamsFound++;
532
0
        }
533
0
        else if ((CSLCount(papszTokens) >= 3) &&
534
0
                 EQUAL(papszTokens[0], "reference") &&
535
0
                 EQUAL(papszTokens[1], "corner") &&
536
0
                 STARTS_WITH_CI(papszTokens[2], "Upper_Left"))
537
0
        {
538
            /* iCorner = 0; */
539
0
            iUTMParamsFound++;
540
0
        }
541
0
        else if (EQUAL(papszTokens[0], "number_lines"))
542
0
            nLines = atoi(papszTokens[1]);
543
544
0
        else if (EQUAL(papszTokens[0], "number_samples"))
545
0
            nSamples = atoi(papszTokens[1]);
546
547
0
        else if ((EQUAL(papszTokens[0], "header_offset") &&
548
0
                  atoi(papszTokens[1]) != 0) ||
549
0
                 (EQUAL(papszTokens[0], "number_channels") &&
550
0
                  (atoi(papszTokens[1]) != 1) &&
551
0
                  (atoi(papszTokens[1]) != 10)) ||
552
0
                 (EQUAL(papszTokens[0], "datatype") &&
553
0
                  atoi(papszTokens[1]) != 1) ||
554
0
                 (EQUAL(papszTokens[0], "number_format") &&
555
0
                  !EQUAL(papszTokens[1], "float32") &&
556
0
                  !EQUAL(papszTokens[1], "int8")))
557
0
        {
558
0
            CPLError(CE_Failure, CPLE_AppDefined,
559
0
                     "Keyword %s has value %s which does not match CPG driver "
560
0
                     "expectation.",
561
0
                     papszTokens[0], papszTokens[1]);
562
0
            nError = 1;
563
0
        }
564
0
        else if (EQUAL(papszTokens[0], "altitude"))
565
0
        {
566
0
            dfaltitude = CPLAtof(papszTokens[1]);
567
0
            iGeoParamsFound++;
568
0
        }
569
0
        else if (EQUAL(papszTokens[0], "near_srd"))
570
0
        {
571
0
            dfnear_srd = CPLAtof(papszTokens[1]);
572
0
            iGeoParamsFound++;
573
0
        }
574
575
0
        else if (EQUAL(papszTokens[0], "sample_size"))
576
0
        {
577
0
            dfsample_size = CPLAtof(papszTokens[1]);
578
0
            iGeoParamsFound++;
579
0
            iUTMParamsFound++;
580
0
        }
581
0
        else if (EQUAL(papszTokens[0], "sample_size_az"))
582
0
        {
583
0
            dfsample_size_az = CPLAtof(papszTokens[1]);
584
0
            iGeoParamsFound++;
585
0
            iUTMParamsFound++;
586
0
        }
587
0
        else if (EQUAL(papszTokens[0], "transposed"))
588
0
        {
589
0
            itransposed = atoi(papszTokens[1]);
590
0
            iGeoParamsFound++;
591
0
            iUTMParamsFound++;
592
0
        }
593
594
0
        CSLDestroy(papszTokens);
595
0
    }
596
0
    CSLDestroy(papszHdrLines);
597
    /* -------------------------------------------------------------------- */
598
    /*      Check for successful completion.                                */
599
    /* -------------------------------------------------------------------- */
600
0
    if (nError)
601
0
    {
602
0
        return nullptr;
603
0
    }
604
605
0
    if (nLines <= 0 || nSamples <= 0)
606
0
    {
607
0
        CPLError(
608
0
            CE_Failure, CPLE_AppDefined,
609
0
            "Did not find valid number_lines or number_samples keywords in %s.",
610
0
            osWorkName.c_str());
611
0
        return nullptr;
612
0
    }
613
614
    /* -------------------------------------------------------------------- */
615
    /*      Initialize dataset.                                             */
616
    /* -------------------------------------------------------------------- */
617
0
    auto poDS = std::make_unique<CPGDataset>();
618
619
0
    poDS->nRasterXSize = nSamples;
620
0
    poDS->nRasterYSize = nLines;
621
622
    /* -------------------------------------------------------------------- */
623
    /*      Open the four bands.                                            */
624
    /* -------------------------------------------------------------------- */
625
0
    static const char *const apszPolarizations[NUMBER_OF_BANDS] = {"hh", "hv",
626
0
                                                                   "vv", "vh"};
627
628
0
    const int nNameLen = static_cast<int>(osWorkName.size());
629
630
0
    if (EQUAL(osWorkName.c_str() + nNameLen - 7, "IRC.hdr") ||
631
0
        EQUAL(osWorkName.c_str() + nNameLen - 7, "IRC.img"))
632
0
    {
633
0
        {
634
0
            char *pszWorkname = CPLStrdup(osWorkName.c_str());
635
0
            AdjustFilename(&pszWorkname, "", "img");
636
0
            osWorkName = pszWorkname;
637
0
            CPLFree(pszWorkname);
638
0
        }
639
640
0
        poDS->afpImage[0] = VSIFOpenL(osWorkName.c_str(), "rb");
641
0
        if (poDS->afpImage[0] == nullptr)
642
0
        {
643
0
            CPLError(CE_Failure, CPLE_OpenFailed,
644
0
                     "Failed to open .img file: %s", osWorkName.c_str());
645
0
            return nullptr;
646
0
        }
647
0
        poDS->aosImageFilenames.push_back(osWorkName.c_str());
648
0
        for (int iBand = 0; iBand < NUMBER_OF_BANDS; iBand++)
649
0
        {
650
0
            SIRC_QSLCRasterBand *poBand =
651
0
                new SIRC_QSLCRasterBand(poDS.get(), iBand + 1, GDT_CFloat32);
652
0
            poDS->SetBand(iBand + 1, poBand);
653
0
            poBand->SetMetadataItem("POLARIMETRIC_INTERP",
654
0
                                    apszPolarizations[iBand]);
655
0
        }
656
0
    }
657
0
    else
658
0
    {
659
0
        constexpr int SIZEOF_CFLOAT32 = 2 * static_cast<int>(sizeof(float));
660
0
        if (nSamples > INT_MAX / SIZEOF_CFLOAT32)
661
0
        {
662
0
            CPLError(CE_Failure, CPLE_AppDefined, "Too large nBlockXSize");
663
0
            return nullptr;
664
0
        }
665
666
0
        CPLAssert(poDS->afpImage.size() == NUMBER_OF_BANDS);
667
0
        for (int iBand = 0; iBand < NUMBER_OF_BANDS; iBand++)
668
0
        {
669
0
            {
670
0
                char *pszWorkname = CPLStrdup(osWorkName.c_str());
671
0
                AdjustFilename(&pszWorkname, apszPolarizations[iBand], "img");
672
0
                osWorkName = pszWorkname;
673
0
                CPLFree(pszWorkname);
674
0
            }
675
676
0
            poDS->afpImage[iBand] = VSIFOpenL(osWorkName.c_str(), "rb");
677
0
            if (poDS->afpImage[iBand] == nullptr)
678
0
            {
679
0
                CPLError(CE_Failure, CPLE_OpenFailed,
680
0
                         "Failed to open .img file: %s", osWorkName.c_str());
681
0
                return nullptr;
682
0
            }
683
0
            poDS->aosImageFilenames.push_back(osWorkName.c_str());
684
685
0
            auto poBand = RawRasterBand::Create(
686
0
                poDS.get(), iBand + 1, poDS->afpImage[iBand], 0, 8,
687
0
                SIZEOF_CFLOAT32 * nSamples, GDT_CFloat32,
688
0
                RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
689
0
                RawRasterBand::OwnFP::NO);
690
0
            if (!poBand)
691
0
                return nullptr;
692
0
            poBand->SetMetadataItem("POLARIMETRIC_INTERP",
693
0
                                    apszPolarizations[iBand]);
694
0
            poDS->SetBand(iBand + 1, std::move(poBand));
695
0
        }
696
0
    }
697
698
    /* Set an appropriate matrix representation metadata item for the set */
699
0
    poDS->SetMetadataItem("MATRIX_REPRESENTATION", "SCATTERING");
700
701
    /* -------------------------------------------------------------------------
702
     */
703
    /*  Add georeferencing or pseudo-geocoding, if enough information found. */
704
    /* -------------------------------------------------------------------------
705
     */
706
0
    if (iUTMParamsFound == 7)
707
0
    {
708
0
        poDS->m_gt.xscale = 0.0;
709
0
        poDS->m_gt.xrot = 0.0;
710
0
        poDS->m_gt.yrot = 0.0;
711
0
        poDS->m_gt.yscale = 0.0;
712
713
0
        double dfnorth_center;
714
0
        if (itransposed == 1)
715
0
        {
716
0
            CPLError(CE_Warning, CPLE_AppDefined,
717
0
                     "Did not have a convair SIRC-style test dataset\n"
718
0
                     "with transposed=1 for testing.  Georeferencing may be "
719
0
                     "wrong.");
720
0
            dfnorth_center = dfnorth - nSamples * dfsample_size / 2.0;
721
0
            poDS->m_gt.xorig = dfeast;
722
0
            poDS->m_gt.xrot = dfsample_size_az;
723
0
            poDS->m_gt.yorig = dfnorth;
724
0
            poDS->m_gt.yrot = -1 * dfsample_size;
725
0
        }
726
0
        else
727
0
        {
728
0
            dfnorth_center = dfnorth - nLines * dfsample_size / 2.0;
729
0
            poDS->m_gt.xorig = dfeast;
730
0
            poDS->m_gt.xscale = dfsample_size_az;
731
0
            poDS->m_gt.yorig = dfnorth;
732
0
            poDS->m_gt.yscale = -1 * dfsample_size;
733
0
        }
734
735
0
        if (dfnorth_center < 0)
736
0
            poDS->m_oSRS.SetUTM(iUTMZone, 0);
737
0
        else
738
0
            poDS->m_oSRS.SetUTM(iUTMZone, 1);
739
740
        /* Assuming WGS84 */
741
0
        poDS->m_oSRS.SetWellKnownGeogCS("WGS84");
742
0
    }
743
0
    else if (iGeoParamsFound == 5)
744
0
    {
745
0
        double dfgcpLine, dfgcpPixel, dfgcpX, dfgcpY, dftemp;
746
747
0
        poDS->nGCPCount = 16;
748
0
        poDS->pasGCPList = reinterpret_cast<GDAL_GCP *>(
749
0
            CPLCalloc(sizeof(GDAL_GCP), poDS->nGCPCount));
750
0
        GDALInitGCPs(poDS->nGCPCount, poDS->pasGCPList);
751
752
0
        for (int ngcp = 0; ngcp < 16; ngcp++)
753
0
        {
754
0
            char szID[32];
755
756
0
            snprintf(szID, sizeof(szID), "%d", ngcp + 1);
757
0
            if (itransposed == 1)
758
0
            {
759
0
                if (ngcp < 4)
760
0
                    dfgcpPixel = 0.0;
761
0
                else if (ngcp < 8)
762
0
                    dfgcpPixel = nSamples / 3.0;
763
0
                else if (ngcp < 12)
764
0
                    dfgcpPixel = 2.0 * nSamples / 3.0;
765
0
                else
766
0
                    dfgcpPixel = nSamples;
767
768
0
                dfgcpLine = nLines * (ngcp % 4) / 3.0;
769
770
0
                dftemp = dfnear_srd + (dfsample_size * dfgcpLine);
771
                /* -1 so that 0,0 maps to largest Y */
772
0
                dfgcpY = -1 * sqrt(dftemp * dftemp - dfaltitude * dfaltitude);
773
0
                dfgcpX = dfgcpPixel * dfsample_size_az;
774
0
            }
775
0
            else
776
0
            {
777
0
                if (ngcp < 4)
778
0
                    dfgcpLine = 0.0;
779
0
                else if (ngcp < 8)
780
0
                    dfgcpLine = nLines / 3.0;
781
0
                else if (ngcp < 12)
782
0
                    dfgcpLine = 2.0 * nLines / 3.0;
783
0
                else
784
0
                    dfgcpLine = nLines;
785
786
0
                dfgcpPixel = nSamples * ((ngcp % 4) / 3.0);
787
788
0
                dftemp = dfnear_srd + (dfsample_size * dfgcpPixel);
789
0
                dfgcpX = sqrt(dftemp * dftemp - dfaltitude * dfaltitude);
790
0
                dfgcpY = (nLines - dfgcpLine) * dfsample_size_az;
791
0
            }
792
0
            poDS->pasGCPList[ngcp].dfGCPX = dfgcpX;
793
0
            poDS->pasGCPList[ngcp].dfGCPY = dfgcpY;
794
0
            poDS->pasGCPList[ngcp].dfGCPZ = 0.0;
795
796
0
            poDS->pasGCPList[ngcp].dfGCPPixel = dfgcpPixel;
797
0
            poDS->pasGCPList[ngcp].dfGCPLine = dfgcpLine;
798
799
0
            CPLFree(poDS->pasGCPList[ngcp].pszId);
800
0
            poDS->pasGCPList[ngcp].pszId = CPLStrdup(szID);
801
0
        }
802
803
0
        poDS->m_oGCPSRS.importFromWkt(
804
0
            "LOCAL_CS[\"Ground range view / unreferenced meters\","
805
0
            "UNIT[\"Meter\",1.0]]");
806
0
    }
807
808
0
    return poDS.release();
809
0
}
810
811
#ifdef notdef
812
GDALDataset *CPGDataset::InitializeType3Dataset(const char *pszFilename)
813
{
814
    int iBytesPerPixel = 0;
815
    Interleave::eInterleave = Interleave::BSQ;
816
    bool bInterleaveSpecified = false;
817
    int nLines = 0;
818
    int nSamples = 0;
819
    int nBands = 0;
820
    int nError = 0;
821
822
    /* Parameters in geogratis geocoded images */
823
    int iUTMParamsFound = 0;
824
    int iUTMZone = 0;
825
    double dfnorth = 0.0;
826
    double dfeast = 0.0;
827
    double dfOffsetX = 0.0;
828
    double dfOffsetY = 0.0;
829
    double dfxsize = 0.0;
830
    double dfysize = 0.0;
831
832
    char *pszWorkname = CPLStrdup(pszFilename);
833
    AdjustFilename(&pszWorkname, "stokes", "img_def");
834
    char **papszHdrLines = CSLLoad(pszWorkname);
835
836
    for (int iLine = 0; papszHdrLines && papszHdrLines[iLine] != NULL; iLine++)
837
    {
838
        char **papszTokens =
839
            CSLTokenizeString2(papszHdrLines[iLine], " \t",
840
                               CSLT_HONOURSTRINGS & CSLT_ALLOWEMPTYTOKENS);
841
842
        /* Note: some cv580 file seem to have comments with #, hence the >=
843
         * instead of = for token checking, and the equalN for the corner.
844
         */
845
846
        if ((CSLCount(papszTokens) >= 3) && EQUAL(papszTokens[0], "data") &&
847
            EQUAL(papszTokens[1], "organization:"))
848
        {
849
850
            if (STARTS_WITH_CI(papszTokens[2], "BSQ"))
851
            {
852
                bInterleaveSpecified = true;
853
                eInterleave = Interleave::BSQ;
854
            }
855
            else if (STARTS_WITH_CI(papszTokens[2], "BIL"))
856
            {
857
                bInterleaveSpecified = true;
858
                eInterleave = Interleave::BIL;
859
            }
860
            else if (STARTS_WITH_CI(papszTokens[2], "BIP"))
861
            {
862
                bInterleaveSpecified = true;
863
                eInterleave = Interleave::BIP;
864
            }
865
            else
866
            {
867
                CPLError(
868
                    CE_Failure, CPLE_AppDefined,
869
                    "The interleaving type of the file (%s) is not supported.",
870
                    papszTokens[2]);
871
                nError = 1;
872
            }
873
        }
874
        else if ((CSLCount(papszTokens) >= 3) &&
875
                 EQUAL(papszTokens[0], "data") &&
876
                 EQUAL(papszTokens[1], "state:"))
877
        {
878
879
            if (!STARTS_WITH_CI(papszTokens[2], "RAW") &&
880
                !STARTS_WITH_CI(papszTokens[2], "GEO"))
881
            {
882
                CPLError(CE_Failure, CPLE_AppDefined,
883
                         "The data state of the file (%s) is not "
884
                         "supported.\n.  Only RAW and GEO are currently "
885
                         "recognized.",
886
                         papszTokens[2]);
887
                nError = 1;
888
            }
889
        }
890
        else if ((CSLCount(papszTokens) >= 4) &&
891
                 EQUAL(papszTokens[0], "data") &&
892
                 EQUAL(papszTokens[1], "origin") &&
893
                 EQUAL(papszTokens[2], "point:"))
894
        {
895
            if (!STARTS_WITH_CI(papszTokens[3], "Upper_Left"))
896
            {
897
                CPLError(CE_Failure, CPLE_AppDefined,
898
                         "Unexpected value (%s) for data origin point- expect "
899
                         "Upper_Left.",
900
                         papszTokens[3]);
901
                nError = 1;
902
            }
903
            iUTMParamsFound++;
904
        }
905
        else if ((CSLCount(papszTokens) >= 5) && EQUAL(papszTokens[0], "map") &&
906
                 EQUAL(papszTokens[1], "projection:") &&
907
                 EQUAL(papszTokens[2], "UTM") && EQUAL(papszTokens[3], "zone"))
908
        {
909
            iUTMZone = atoi(papszTokens[4]);
910
            iUTMParamsFound++;
911
        }
912
        else if ((CSLCount(papszTokens) >= 4) &&
913
                 EQUAL(papszTokens[0], "project") &&
914
                 EQUAL(papszTokens[1], "origin:"))
915
        {
916
            dfeast = CPLAtof(papszTokens[2]);
917
            dfnorth = CPLAtof(papszTokens[3]);
918
            iUTMParamsFound += 2;
919
        }
920
        else if ((CSLCount(papszTokens) >= 4) &&
921
                 EQUAL(papszTokens[0], "file") &&
922
                 EQUAL(papszTokens[1], "start:"))
923
        {
924
            dfOffsetX = CPLAtof(papszTokens[2]);
925
            dfOffsetY = CPLAtof(papszTokens[3]);
926
            iUTMParamsFound += 2;
927
        }
928
        else if ((CSLCount(papszTokens) >= 6) &&
929
                 EQUAL(papszTokens[0], "pixel") &&
930
                 EQUAL(papszTokens[1], "size") && EQUAL(papszTokens[2], "on") &&
931
                 EQUAL(papszTokens[3], "ground:"))
932
        {
933
            dfxsize = CPLAtof(papszTokens[4]);
934
            dfysize = CPLAtof(papszTokens[5]);
935
            iUTMParamsFound += 2;
936
        }
937
        else if ((CSLCount(papszTokens) >= 4) &&
938
                 EQUAL(papszTokens[0], "number") &&
939
                 EQUAL(papszTokens[1], "of") &&
940
                 EQUAL(papszTokens[2], "pixels:"))
941
        {
942
            nSamples = atoi(papszTokens[3]);
943
        }
944
        else if ((CSLCount(papszTokens) >= 4) &&
945
                 EQUAL(papszTokens[0], "number") &&
946
                 EQUAL(papszTokens[1], "of") && EQUAL(papszTokens[2], "lines:"))
947
        {
948
            nLines = atoi(papszTokens[3]);
949
        }
950
        else if ((CSLCount(papszTokens) >= 4) &&
951
                 EQUAL(papszTokens[0], "number") &&
952
                 EQUAL(papszTokens[1], "of") && EQUAL(papszTokens[2], "bands:"))
953
        {
954
            nBands = atoi(papszTokens[3]);
955
            if (nBands != 16)
956
            {
957
                CPLError(CE_Failure, CPLE_AppDefined,
958
                         "Number of bands has a value %s which does not match "
959
                         "CPG driver\nexpectation (expect a value of 16).",
960
                         papszTokens[3]);
961
                nError = 1;
962
            }
963
        }
964
        else if ((CSLCount(papszTokens) >= 4) &&
965
                 EQUAL(papszTokens[0], "bytes") &&
966
                 EQUAL(papszTokens[1], "per") &&
967
                 EQUAL(papszTokens[2], "pixel:"))
968
        {
969
            iBytesPerPixel = atoi(papszTokens[3]);
970
            if (iBytesPerPixel != 4)
971
            {
972
                CPLError(CE_Failure, CPLE_AppDefined,
973
                         "Bytes per pixel has a value %s which does not match "
974
                         "CPG driver\nexpectation (expect a value of 4).",
975
                         papszTokens[1]);
976
                nError = 1;
977
            }
978
        }
979
        CSLDestroy(papszTokens);
980
    }
981
982
    CSLDestroy(papszHdrLines);
983
984
    /* -------------------------------------------------------------------- */
985
    /*      Check for successful completion.                                */
986
    /* -------------------------------------------------------------------- */
987
    if (nError)
988
    {
989
        CPLFree(pszWorkname);
990
        return NULL;
991
    }
992
993
    if (!GDALCheckDatasetDimensions(nSamples, nLines) ||
994
        !GDALCheckBandCount(nBands, FALSE) || !bInterleaveSpecified ||
995
        iBytesPerPixel == 0)
996
    {
997
        CPLError(CE_Failure, CPLE_AppDefined,
998
                 "%s is missing a required parameter (number of pixels, "
999
                 "number of lines,\number of bands, bytes per pixel, or "
1000
                 "data organization).",
1001
                 pszWorkname);
1002
        CPLFree(pszWorkname);
1003
        return NULL;
1004
    }
1005
1006
    /* -------------------------------------------------------------------- */
1007
    /*      Initialize dataset.                                             */
1008
    /* -------------------------------------------------------------------- */
1009
    CPGDataset *poDS = new CPGDataset();
1010
1011
    poDS->nRasterXSize = nSamples;
1012
    poDS->nRasterYSize = nLines;
1013
    poDS->eInterleave = eInterleave;
1014
1015
    /* -------------------------------------------------------------------- */
1016
    /*      Open the 16 bands.                                              */
1017
    /* -------------------------------------------------------------------- */
1018
1019
    AdjustFilename(&pszWorkname, "stokes", "img");
1020
    poDS->afpImage[0] = VSIFOpenL(pszWorkname, "rb");
1021
    if (poDS->afpImage[0] == NULL)
1022
    {
1023
        CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open .img file: %s",
1024
                 pszWorkname);
1025
        CPLFree(pszWorkname);
1026
        delete poDS;
1027
        return NULL;
1028
    }
1029
    aosImageFilenames.push_back(pszWorkname);
1030
    for (int iBand = 0; iBand < 16; iBand++)
1031
    {
1032
        CPG_STOKESRasterBand *poBand =
1033
            new CPG_STOKESRasterBand(poDS, GDT_CFloat32, !CPL_IS_LSB);
1034
        poDS->SetBand(iBand + 1, poBand);
1035
    }
1036
1037
    /* -------------------------------------------------------------------- */
1038
    /*      Set appropriate MATRIX_REPRESENTATION.                          */
1039
    /* -------------------------------------------------------------------- */
1040
    if (poDS->GetRasterCount() == 6)
1041
    {
1042
        poDS->SetMetadataItem("MATRIX_REPRESENTATION", "COVARIANCE");
1043
    }
1044
1045
    /* -------------------------------------------------------------------------
1046
     */
1047
    /*  Add georeferencing, if enough information found. */
1048
    /* -------------------------------------------------------------------------
1049
     */
1050
    if (iUTMParamsFound == 8)
1051
    {
1052
        double dfnorth_center = dfnorth - nLines * dfysize / 2.0;
1053
        poDS->m_gt.xorig = dfeast + dfOffsetX;
1054
        poDS->m_gt.xscale = dfxsize;
1055
        poDS->m_gt.xrot = 0.0;
1056
        poDS->m_gt.yorig = dfnorth + dfOffsetY;
1057
        poDS->m_gt.yrot = 0.0;
1058
        poDS->m_gt.yscale = -1 * dfysize;
1059
1060
        OGRSpatialReference oUTM;
1061
        if (dfnorth_center < 0)
1062
            oUTM.SetUTM(iUTMZone, 0);
1063
        else
1064
            oUTM.SetUTM(iUTMZone, 1);
1065
1066
        /* Assuming WGS84 */
1067
        oUTM.SetWellKnownGeogCS("WGS84");
1068
        CPLFree(poDS->pszProjection);
1069
        poDS->pszProjection = NULL;
1070
        oUTM.exportToWkt(&(poDS->pszProjection));
1071
    }
1072
1073
    return poDS;
1074
}
1075
#endif
1076
1077
/************************************************************************/
1078
/*                                Open()                                */
1079
/************************************************************************/
1080
1081
GDALDataset *CPGDataset::Open(GDALOpenInfo *poOpenInfo)
1082
1083
465k
{
1084
    /* -------------------------------------------------------------------- */
1085
    /*      Is this a PolGASP fileset?  We expect fileset to follow         */
1086
    /*      one of these patterns:                                          */
1087
    /*               1) <stuff>hh<stuff2>.img, <stuff>hh<stuff2>.hdr,       */
1088
    /*                  <stuff>hv<stuff2>.img, <stuff>hv<stuff2>.hdr,       */
1089
    /*                  <stuff>vh<stuff2>.img, <stuff>vh<stuff2>.hdr,       */
1090
    /*                  <stuff>vv<stuff2>.img, <stuff>vv<stuff2>.hdr,       */
1091
    /*                  where <stuff> or <stuff2> should contain the        */
1092
    /*                  substring "sso" or "polgasp"                        */
1093
    /*               2) <stuff>SIRC.hdr and <stuff>SIRC.img                 */
1094
    /*               3) <stuff>.img and <stuff>.img_def                     */
1095
    /*                  where <stuff> should contain the                    */
1096
    /*                  substring "sso" or "polgasp"                        */
1097
    /* -------------------------------------------------------------------- */
1098
465k
    int CPGType = 0;
1099
465k
    if (FindType1(poOpenInfo->pszFilename))
1100
0
        CPGType = 1;
1101
465k
    else if (FindType2(poOpenInfo->pszFilename))
1102
0
        CPGType = 2;
1103
1104
    /* Stokes matrix convair data: not quite working yet- something
1105
     * is wrong in the interpretation of the matrix elements in terms
1106
     * of hh, hv, vv, vh.  Data will load if the next two lines are
1107
     * uncommented, but values will be incorrect.  Expect C11 = hh*conj(hh),
1108
     * C12 = hh*conj(hv), etc.  Used geogratis data in both scattering
1109
     * matrix and stokes format for comparison.
1110
     */
1111
    // else if ( FindType3( poOpenInfo->pszFilename ))
1112
    //   CPGType = 3;
1113
1114
    /* Set working name back to original */
1115
1116
465k
    if (CPGType == 0)
1117
465k
    {
1118
465k
        int nNameLen = static_cast<int>(strlen(poOpenInfo->pszFilename));
1119
465k
        if ((nNameLen > 8) &&
1120
449k
            ((strstr(poOpenInfo->pszFilename, "sso") != nullptr) ||
1121
448k
             (strstr(poOpenInfo->pszFilename, "polgasp") != nullptr)) &&
1122
383
            (EQUAL(poOpenInfo->pszFilename + nNameLen - 4, "img") ||
1123
383
             EQUAL(poOpenInfo->pszFilename + nNameLen - 4, "hdr") ||
1124
383
             EQUAL(poOpenInfo->pszFilename + nNameLen - 7, "img_def")))
1125
0
        {
1126
0
            CPLError(
1127
0
                CE_Failure, CPLE_OpenFailed,
1128
0
                "Apparent attempt to open Convair PolGASP data failed as\n"
1129
0
                "one or more of the required files is missing (eight files\n"
1130
0
                "are expected for scattering matrix format, two for Stokes).");
1131
0
        }
1132
465k
        else if ((nNameLen > 8) &&
1133
449k
                 (strstr(poOpenInfo->pszFilename, "SIRC") != nullptr) &&
1134
253
                 (EQUAL(poOpenInfo->pszFilename + nNameLen - 4, "img") ||
1135
253
                  EQUAL(poOpenInfo->pszFilename + nNameLen - 4, "hdr")))
1136
0
        {
1137
0
            CPLError(
1138
0
                CE_Failure, CPLE_OpenFailed,
1139
0
                "Apparent attempt to open SIRC Convair PolGASP data failed \n"
1140
0
                "as one of the expected files is missing (hdr or img)!");
1141
0
        }
1142
465k
        return nullptr;
1143
465k
    }
1144
1145
    /* -------------------------------------------------------------------- */
1146
    /*      Confirm the requested access is supported.                      */
1147
    /* -------------------------------------------------------------------- */
1148
0
    if (poOpenInfo->eAccess == GA_Update)
1149
0
    {
1150
0
        ReportUpdateNotSupportedByDriver("CPG");
1151
0
        return nullptr;
1152
0
    }
1153
1154
    /* Read the header info and create the dataset */
1155
#ifdef notdef
1156
    if (CPGType < 3)
1157
#endif
1158
0
        CPGDataset *poDS = reinterpret_cast<CPGDataset *>(
1159
0
            InitializeType1Or2Dataset(poOpenInfo->pszFilename));
1160
#ifdef notdef
1161
    else
1162
        poDS = reinterpret_cast<CPGDataset *>(
1163
            InitializeType3Dataset(poOpenInfo->pszFilename));
1164
#endif
1165
0
    if (poDS == nullptr)
1166
0
        return nullptr;
1167
1168
    /* -------------------------------------------------------------------- */
1169
    /*      Check for overviews.                                            */
1170
    /* -------------------------------------------------------------------- */
1171
    // Need to think about this.
1172
    // poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
1173
1174
    /* -------------------------------------------------------------------- */
1175
    /*      Initialize any PAM information.                                 */
1176
    /* -------------------------------------------------------------------- */
1177
0
    poDS->SetDescription(poOpenInfo->pszFilename);
1178
0
    poDS->TryLoadXML();
1179
1180
0
    return poDS;
1181
0
}
1182
1183
/************************************************************************/
1184
/*                            GetGCPCount()                             */
1185
/************************************************************************/
1186
1187
int CPGDataset::GetGCPCount()
1188
1189
0
{
1190
0
    return nGCPCount;
1191
0
}
1192
1193
/************************************************************************/
1194
/*                              GetGCPs()                               */
1195
/************************************************************************/
1196
1197
const GDAL_GCP *CPGDataset::GetGCPs()
1198
1199
0
{
1200
0
    return pasGCPList;
1201
0
}
1202
1203
/************************************************************************/
1204
/*                          GetGeoTransform()                           */
1205
/************************************************************************/
1206
1207
CPLErr CPGDataset::GetGeoTransform(GDALGeoTransform &gt) const
1208
1209
0
{
1210
0
    gt = m_gt;
1211
0
    return CE_None;
1212
0
}
1213
1214
/************************************************************************/
1215
/*                        SIRC_QSLCRasterBand()                         */
1216
/************************************************************************/
1217
1218
SIRC_QSLCRasterBand::SIRC_QSLCRasterBand(CPGDataset *poGDSIn, int nBandIn,
1219
                                         GDALDataType eType)
1220
1221
0
{
1222
0
    poDS = poGDSIn;
1223
0
    nBand = nBandIn;
1224
1225
0
    eDataType = eType;
1226
1227
0
    nBlockXSize = poGDSIn->nRasterXSize;
1228
0
    nBlockYSize = 1;
1229
1230
0
    if (nBand == 1)
1231
0
        SetMetadataItem("POLARIMETRIC_INTERP", "HH");
1232
0
    else if (nBand == 2)
1233
0
        SetMetadataItem("POLARIMETRIC_INTERP", "HV");
1234
0
    else if (nBand == 3)
1235
0
        SetMetadataItem("POLARIMETRIC_INTERP", "VH");
1236
0
    else if (nBand == 4)
1237
0
        SetMetadataItem("POLARIMETRIC_INTERP", "VV");
1238
0
}
1239
1240
/************************************************************************/
1241
/*                             IReadBlock()                             */
1242
/************************************************************************/
1243
1244
/* From: http://southport.jpl.nasa.gov/software/dcomp/dcomp.html
1245
1246
ysca = sqrt{ [ (Byte(2) / 254 ) + 1.5] 2Byte(1) }
1247
Re(SHH) = byte(3) ysca/127
1248
Im(SHH) = byte(4) ysca/127
1249
Re(SHV) = byte(5) ysca/127
1250
Im(SHV) = byte(6) ysca/127
1251
Re(SVH) = byte(7) ysca/127
1252
Im(SVH) = byte(8) ysca/127
1253
Re(SVV) = byte(9) ysca/127
1254
Im(SVV) = byte(10) ysca/127
1255
*/
1256
1257
CPLErr SIRC_QSLCRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff,
1258
                                       int nBlockYOff, void *pImage)
1259
0
{
1260
0
    const int nBytesPerSample = 10;
1261
0
    CPGDataset *poGDS = cpl::down_cast<CPGDataset *>(poDS);
1262
0
    const vsi_l_offset offset =
1263
0
        static_cast<vsi_l_offset>(nBlockXSize) * nBlockYOff * nBytesPerSample;
1264
1265
    /* -------------------------------------------------------------------- */
1266
    /*      Load all the pixel data associated with this scanline.          */
1267
    /* -------------------------------------------------------------------- */
1268
0
    if (nBytesPerSample > INT_MAX / nBlockXSize)
1269
0
    {
1270
0
        CPLError(CE_Failure, CPLE_AppDefined, "Too large nBlockXSize");
1271
0
        return CE_Failure;
1272
0
    }
1273
0
    const int nBytesToRead = nBytesPerSample * nBlockXSize;
1274
1275
0
    signed char *pabyRecord =
1276
0
        static_cast<signed char *>(VSI_MALLOC_VERBOSE(nBytesToRead));
1277
0
    if (!pabyRecord)
1278
0
        return CE_Failure;
1279
1280
0
    if (VSIFSeekL(poGDS->afpImage[0], offset, SEEK_SET) != 0 ||
1281
0
        static_cast<int>(VSIFReadL(pabyRecord, 1, nBytesToRead,
1282
0
                                   poGDS->afpImage[0])) != nBytesToRead)
1283
0
    {
1284
0
        CPLError(CE_Failure, CPLE_FileIO,
1285
0
                 "Error reading %d bytes of SIRC Convair at offset %" PRIu64
1286
0
                 ".\n"
1287
0
                 "Reading file %s failed.",
1288
0
                 nBytesToRead, static_cast<uint64_t>(offset),
1289
0
                 poGDS->GetDescription());
1290
0
        CPLFree(pabyRecord);
1291
0
        return CE_Failure;
1292
0
    }
1293
1294
    /* -------------------------------------------------------------------- */
1295
    /*      Initialize our power table if this is our first time through.   */
1296
    /* -------------------------------------------------------------------- */
1297
0
    static float afPowTable[256];
1298
0
    [[maybe_unused]] static bool bPowTableInitialized = [](bool ret)
1299
0
    {
1300
0
        for (int i = 0; i < 256; i++)
1301
0
        {
1302
0
            afPowTable[i] = static_cast<float>(pow(2.0, i - 128));
1303
0
        }
1304
0
        return ret;
1305
0
    }(true);
1306
1307
    /* -------------------------------------------------------------------- */
1308
    /*      Copy the desired band out based on the size of the type, and    */
1309
    /*      the interleaving mode.                                          */
1310
    /* -------------------------------------------------------------------- */
1311
0
    for (int iX = 0; iX < nBlockXSize; iX++)
1312
0
    {
1313
        /* A ones based alias */
1314
0
        const signed char *pabyIn = pabyRecord + iX * nBytesPerSample - 1;
1315
1316
        /* coverity[tainted_data] */
1317
0
        const float fScale = static_cast<float>(
1318
0
            sqrt((static_cast<double>(pabyIn[2]) / 254 + 1.5) *
1319
0
                 afPowTable[pabyIn[1] + 128]) /
1320
0
            127.0);
1321
1322
0
        float *pafImage = static_cast<float *>(pImage);
1323
1324
0
        if (nBand == 1)
1325
0
        {
1326
0
            const float fReSHH = static_cast<float>(pabyIn[3] * fScale);
1327
0
            const float fImSHH = static_cast<float>(pabyIn[4] * fScale);
1328
1329
0
            pafImage[iX * 2] = fReSHH;
1330
0
            pafImage[iX * 2 + 1] = fImSHH;
1331
0
        }
1332
0
        else if (nBand == 2)
1333
0
        {
1334
0
            const float fReSHV = static_cast<float>(pabyIn[5] * fScale);
1335
0
            const float fImSHV = static_cast<float>(pabyIn[6] * fScale);
1336
1337
0
            pafImage[iX * 2] = fReSHV;
1338
0
            pafImage[iX * 2 + 1] = fImSHV;
1339
0
        }
1340
0
        else if (nBand == 3)
1341
0
        {
1342
0
            const float fReSVH = static_cast<float>(pabyIn[7] * fScale);
1343
0
            const float fImSVH = static_cast<float>(pabyIn[8] * fScale);
1344
1345
0
            pafImage[iX * 2] = fReSVH;
1346
0
            pafImage[iX * 2 + 1] = fImSVH;
1347
0
        }
1348
0
        else if (nBand == 4)
1349
0
        {
1350
0
            const float fReSVV = static_cast<float>(pabyIn[9] * fScale);
1351
0
            const float fImSVV = static_cast<float>(pabyIn[10] * fScale);
1352
1353
0
            pafImage[iX * 2] = fReSVV;
1354
0
            pafImage[iX * 2 + 1] = fImSVV;
1355
0
        }
1356
0
    }
1357
1358
0
    CPLFree(pabyRecord);
1359
1360
0
    return CE_None;
1361
0
}
1362
1363
/************************************************************************/
1364
/*                        CPG_STOKESRasterBand()                        */
1365
/************************************************************************/
1366
1367
CPG_STOKESRasterBand::CPG_STOKESRasterBand(GDALDataset *poDSIn,
1368
                                           GDALDataType eType,
1369
                                           int bNativeOrderIn)
1370
0
    : bNativeOrder(bNativeOrderIn)
1371
0
{
1372
0
    static const char *const apszPolarizations[16] = {
1373
0
        "Covariance_11", "Covariance_12", "Covariance_13", "Covariance_14",
1374
0
        "Covariance_21", "Covariance_22", "Covariance_23", "Covariance_24",
1375
0
        "Covariance_31", "Covariance_32", "Covariance_33", "Covariance_34",
1376
0
        "Covariance_41", "Covariance_42", "Covariance_43", "Covariance_44"};
1377
1378
0
    poDS = poDSIn;
1379
0
    eDataType = eType;
1380
1381
0
    nBlockXSize = poDSIn->GetRasterXSize();
1382
0
    nBlockYSize = 1;
1383
1384
0
    SetMetadataItem("POLARIMETRIC_INTERP", apszPolarizations[nBand - 1]);
1385
0
    SetDescription(apszPolarizations[nBand - 1]);
1386
0
}
1387
1388
/************************************************************************/
1389
/*                             IReadBlock()                             */
1390
/************************************************************************/
1391
1392
/* Convert from Stokes to Covariance representation */
1393
1394
CPLErr CPG_STOKESRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff,
1395
                                        int nBlockYOff, void *pImage)
1396
1397
0
{
1398
0
    CPLAssert(nBlockXOff == 0);
1399
1400
0
    int m11, /* m12, */ m13, m14, /* m21, */ m22, m23, m24, step;
1401
0
    int m31, m32, m33, m34, m41, m42, m43, m44;
1402
0
    CPGDataset *poGDS = cpl::down_cast<CPGDataset *>(poDS);
1403
1404
0
    CPLErr eErr = poGDS->LoadStokesLine(nBlockYOff, bNativeOrder);
1405
0
    if (eErr != CE_None)
1406
0
        return eErr;
1407
1408
0
    float *M = poGDS->padfStokesMatrix;
1409
0
    float *pafLine = reinterpret_cast<float *>(pImage);
1410
1411
0
    if (poGDS->eInterleave == RawDataset::Interleave::BIP)
1412
0
    {
1413
0
        step = 16;
1414
0
        m11 = M11;
1415
        // m12 = M12;
1416
0
        m13 = M13;
1417
0
        m14 = M14;
1418
        // m21 = M21;
1419
0
        m22 = M22;
1420
0
        m23 = M23;
1421
0
        m24 = M24;
1422
0
        m31 = M31;
1423
0
        m32 = M32;
1424
0
        m33 = M33;
1425
0
        m34 = M34;
1426
0
        m41 = M41;
1427
0
        m42 = M42;
1428
0
        m43 = M43;
1429
0
        m44 = M44;
1430
0
    }
1431
0
    else
1432
0
    {
1433
0
        step = 1;
1434
0
        m11 = 0;
1435
        // m12=nRasterXSize;
1436
0
        m13 = nRasterXSize * 2;
1437
0
        m14 = nRasterXSize * 3;
1438
        // m21=nRasterXSize*4;
1439
0
        m22 = nRasterXSize * 5;
1440
0
        m23 = nRasterXSize * 6;
1441
0
        m24 = nRasterXSize * 7;
1442
0
        m31 = nRasterXSize * 8;
1443
0
        m32 = nRasterXSize * 9;
1444
0
        m33 = nRasterXSize * 10;
1445
0
        m34 = nRasterXSize * 11;
1446
0
        m41 = nRasterXSize * 12;
1447
0
        m42 = nRasterXSize * 13;
1448
0
        m43 = nRasterXSize * 14;
1449
0
        m44 = nRasterXSize * 15;
1450
0
    }
1451
0
    if (nBand == 1) /* C11 */
1452
0
    {
1453
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1454
0
        {
1455
0
            pafLine[iPixel * 2 + 0] = M[m11] - M[m22] - M[m33] + M[m44];
1456
0
            pafLine[iPixel * 2 + 1] = 0.0;
1457
0
            m11 += step;
1458
0
            m22 += step;
1459
0
            m33 += step;
1460
0
            m44 += step;
1461
0
        }
1462
0
    }
1463
0
    else if (nBand == 2) /* C12 */
1464
0
    {
1465
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1466
0
        {
1467
0
            pafLine[iPixel * 2 + 0] = M[m13] - M[m23];
1468
0
            pafLine[iPixel * 2 + 1] = M[m14] - M[m24];
1469
0
            m13 += step;
1470
0
            m23 += step;
1471
0
            m14 += step;
1472
0
            m24 += step;
1473
0
        }
1474
0
    }
1475
0
    else if (nBand == 3) /* C13 */
1476
0
    {
1477
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1478
0
        {
1479
0
            pafLine[iPixel * 2 + 0] = M[m33] - M[m44];
1480
0
            pafLine[iPixel * 2 + 1] = M[m43] + M[m34];
1481
0
            m33 += step;
1482
0
            m44 += step;
1483
0
            m43 += step;
1484
0
            m34 += step;
1485
0
        }
1486
0
    }
1487
0
    else if (nBand == 4) /* C14 */
1488
0
    {
1489
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1490
0
        {
1491
0
            pafLine[iPixel * 2 + 0] = M[m31] - M[m32];
1492
0
            pafLine[iPixel * 2 + 1] = M[m41] - M[m42];
1493
0
            m31 += step;
1494
0
            m32 += step;
1495
0
            m41 += step;
1496
0
            m42 += step;
1497
0
        }
1498
0
    }
1499
0
    else if (nBand == 5) /* C21 */
1500
0
    {
1501
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1502
0
        {
1503
0
            pafLine[iPixel * 2 + 0] = M[m13] - M[m23];
1504
0
            pafLine[iPixel * 2 + 1] = M[m24] - M[m14];
1505
0
            m13 += step;
1506
0
            m23 += step;
1507
0
            m14 += step;
1508
0
            m24 += step;
1509
0
        }
1510
0
    }
1511
0
    else if (nBand == 6) /* C22 */
1512
0
    {
1513
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1514
0
        {
1515
0
            pafLine[iPixel * 2 + 0] = M[m11] + M[m22] - M[m33] - M[m44];
1516
0
            pafLine[iPixel * 2 + 1] = 0.0;
1517
0
            m11 += step;
1518
0
            m22 += step;
1519
0
            m33 += step;
1520
0
            m44 += step;
1521
0
        }
1522
0
    }
1523
0
    else if (nBand == 7) /* C23 */
1524
0
    {
1525
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1526
0
        {
1527
0
            pafLine[iPixel * 2 + 0] = M[m31] + M[m32];
1528
0
            pafLine[iPixel * 2 + 1] = M[m41] + M[m42];
1529
0
            m31 += step;
1530
0
            m32 += step;
1531
0
            m41 += step;
1532
0
            m42 += step;
1533
0
        }
1534
0
    }
1535
0
    else if (nBand == 8) /* C24 */
1536
0
    {
1537
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1538
0
        {
1539
0
            pafLine[iPixel * 2 + 0] = M[m33] + M[m44];
1540
0
            pafLine[iPixel * 2 + 1] = M[m43] - M[m34];
1541
0
            m33 += step;
1542
0
            m44 += step;
1543
0
            m43 += step;
1544
0
            m34 += step;
1545
0
        }
1546
0
    }
1547
0
    else if (nBand == 9) /* C31 */
1548
0
    {
1549
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1550
0
        {
1551
0
            pafLine[iPixel * 2 + 0] = M[m33] - M[m44];
1552
0
            pafLine[iPixel * 2 + 1] = -1 * M[m43] - M[m34];
1553
0
            m33 += step;
1554
0
            m44 += step;
1555
0
            m43 += step;
1556
0
            m34 += step;
1557
0
        }
1558
0
    }
1559
0
    else if (nBand == 10) /* C32 */
1560
0
    {
1561
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1562
0
        {
1563
0
            pafLine[iPixel * 2 + 0] = M[m31] + M[m32];
1564
0
            pafLine[iPixel * 2 + 1] = -1 * M[m41] - M[m42];
1565
0
            m31 += step;
1566
0
            m32 += step;
1567
0
            m41 += step;
1568
0
            m42 += step;
1569
0
        }
1570
0
    }
1571
0
    else if (nBand == 11) /* C33 */
1572
0
    {
1573
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1574
0
        {
1575
0
            pafLine[iPixel * 2 + 0] = M[m11] + M[m22] + M[m33] + M[m44];
1576
0
            pafLine[iPixel * 2 + 1] = 0.0;
1577
0
            m11 += step;
1578
0
            m22 += step;
1579
0
            m33 += step;
1580
0
            m44 += step;
1581
0
        }
1582
0
    }
1583
0
    else if (nBand == 12) /* C34 */
1584
0
    {
1585
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1586
0
        {
1587
0
            pafLine[iPixel * 2 + 0] = M[m13] - M[m23];
1588
0
            pafLine[iPixel * 2 + 1] = -1 * M[m14] - M[m24];
1589
0
            m13 += step;
1590
0
            m23 += step;
1591
0
            m14 += step;
1592
0
            m24 += step;
1593
0
        }
1594
0
    }
1595
0
    else if (nBand == 13) /* C41 */
1596
0
    {
1597
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1598
0
        {
1599
0
            pafLine[iPixel * 2 + 0] = M[m31] - M[m32];
1600
0
            pafLine[iPixel * 2 + 1] = M[m42] - M[m41];
1601
0
            m31 += step;
1602
0
            m32 += step;
1603
0
            m41 += step;
1604
0
            m42 += step;
1605
0
        }
1606
0
    }
1607
0
    else if (nBand == 14) /* C42 */
1608
0
    {
1609
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1610
0
        {
1611
0
            pafLine[iPixel * 2 + 0] = M[m33] + M[m44];
1612
0
            pafLine[iPixel * 2 + 1] = M[m34] - M[m43];
1613
0
            m33 += step;
1614
0
            m44 += step;
1615
0
            m43 += step;
1616
0
            m34 += step;
1617
0
        }
1618
0
    }
1619
0
    else if (nBand == 15) /* C43 */
1620
0
    {
1621
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1622
0
        {
1623
0
            pafLine[iPixel * 2 + 0] = M[m13] - M[m23];
1624
0
            pafLine[iPixel * 2 + 1] = M[m14] + M[m24];
1625
0
            m13 += step;
1626
0
            m23 += step;
1627
0
            m14 += step;
1628
0
            m24 += step;
1629
0
        }
1630
0
    }
1631
0
    else /* C44 */
1632
0
    {
1633
0
        for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
1634
0
        {
1635
0
            pafLine[iPixel * 2 + 0] = M[m11] - M[m22] + M[m33] - M[m44];
1636
0
            pafLine[iPixel * 2 + 1] = 0.0;
1637
0
            m11 += step;
1638
0
            m22 += step;
1639
0
            m33 += step;
1640
0
            m44 += step;
1641
0
        }
1642
0
    }
1643
1644
0
    return CE_None;
1645
0
}
1646
1647
/************************************************************************/
1648
/*                          GDALRegister_CPG()                          */
1649
/************************************************************************/
1650
1651
void GDALRegister_CPG()
1652
1653
22
{
1654
22
    if (GDALGetDriverByName("CPG") != nullptr)
1655
0
        return;
1656
1657
22
    GDALDriver *poDriver = new GDALDriver();
1658
1659
22
    poDriver->SetDescription("CPG");
1660
22
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1661
22
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Convair PolGASP");
1662
22
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1663
1664
22
    poDriver->pfnOpen = CPGDataset::Open;
1665
1666
22
    GetGDALDriverManager()->RegisterDriver(poDriver);
1667
22
}