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

OSGeo / gdal / 15885686134

25 Jun 2025 07:44PM UTC coverage: 71.084%. Remained the same
15885686134

push

github

rouault
gdal_priv.h: fix C++11 compatibility

573814 of 807237 relevant lines covered (71.08%)

250621.56 hits per line

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

56.36
/frmts/safe/safedataset.cpp
1
/******************************************************************************
2
 *
3
 * Project:  Sentinel SAFE products
4
 * Purpose:  Sentinel Products (manifest.safe) driver
5
 * Author:   Delfim Rego, delfimrego@gmail.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2015, Delfim Rego <delfimrego@gmail.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12

13
#include "safedataset.h"
14

15
#include "cpl_time.h"
16

17
#ifdef USE_OMP
18
#include <omp.h>
19
#endif
20

21
#ifdef USE_OMP
22
static int GetNumThreadsToUse()
23
{
24
    unsigned int nCores = std::thread::hardware_concurrency();
25
    return (nCores / 2 > 1) ? nCores / 2 : 1;
26
}
27
#endif
28

29
/************************************************************************/
30
/*                            SAFERasterBand                            */
31
/************************************************************************/
32

33
SAFERasterBand::SAFERasterBand(SAFEDataset *poDSIn, GDALDataType eDataTypeIn,
14✔
34
                               const CPLString &osSwath,
35
                               const CPLString &osPolarization,
36
                               std::unique_ptr<GDALDataset> &&poBandFileIn)
14✔
37
    : poBandFile(std::move(poBandFileIn))
14✔
38
{
39
    poDS = poDSIn;
14✔
40
    GDALRasterBand *poSrcBand = poBandFile->GetRasterBand(1);
14✔
41
    poSrcBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
14✔
42
    eDataType = eDataTypeIn;
14✔
43

44
    if (!osSwath.empty())
14✔
45
        SetMetadataItem("SWATH", osSwath.c_str());
14✔
46

47
    if (!osPolarization.empty())
14✔
48
        SetMetadataItem("POLARIZATION", osPolarization.c_str());
14✔
49
}
14✔
50

51
/************************************************************************/
52
/*                             IReadBlock()                             */
53
/************************************************************************/
54

55
CPLErr SAFERasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
55✔
56

57
{
58
    /* -------------------------------------------------------------------- */
59
    /*      If the last strip is partial, we need to avoid                  */
60
    /*      over-requesting.  We also need to initialize the extra part     */
61
    /*      of the block to zero.                                           */
62
    /* -------------------------------------------------------------------- */
63
    int nRequestYSize;
64
    if ((nBlockYOff + 1) * nBlockYSize > nRasterYSize)
55✔
65
    {
66
        nRequestYSize = nRasterYSize - nBlockYOff * nBlockYSize;
5✔
67
        memset(pImage, 0,
5✔
68
               static_cast<size_t>(GDALGetDataTypeSizeBytes(eDataType)) *
5✔
69
                   nBlockXSize * nBlockYSize);
5✔
70
    }
71
    else
72
    {
73
        nRequestYSize = nBlockYSize;
50✔
74
    }
75

76
    /*-------------------------------------------------------------------- */
77
    /*      If the input imagery is tiled, also need to avoid over-        */
78
    /*      requesting in the X-direction.                                 */
79
    /* ------------------------------------------------------------------- */
80
    int nRequestXSize;
81
    if ((nBlockXOff + 1) * nBlockXSize > nRasterXSize)
55✔
82
    {
83
        nRequestXSize = nRasterXSize - nBlockXOff * nBlockXSize;
×
84
        memset(pImage, 0,
×
85
               static_cast<size_t>(GDALGetDataTypeSizeBytes(eDataType)) *
×
86
                   nBlockXSize * nBlockYSize);
×
87
    }
88
    else
89
    {
90
        nRequestXSize = nBlockXSize;
55✔
91
    }
92
    if (eDataType == GDT_CInt16 && poBandFile->GetRasterCount() == 2)
55✔
93
        return poBandFile->RasterIO(
×
94
            GF_Read, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
×
95
            nRequestXSize, nRequestYSize, pImage, nRequestXSize, nRequestYSize,
96
            GDT_Int16, 2, nullptr, 4, nBlockXSize * 4, 2, nullptr);
×
97

98
    /* -------------------------------------------------------------------- */
99
    /*      File has one sample marked as sample format void, a 32bits.     */
100
    /* -------------------------------------------------------------------- */
101
    else if (eDataType == GDT_CInt16 && poBandFile->GetRasterCount() == 1)
55✔
102
    {
103
        CPLErr eErr = poBandFile->RasterIO(
×
104
            GF_Read, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
×
105
            nRequestXSize, nRequestYSize, pImage, nRequestXSize, nRequestYSize,
106
            GDT_CInt16, 1, nullptr, 4, nBlockXSize * 4, 0, nullptr);
×
107

108
        return eErr;
×
109
    }
110

111
    /* -------------------------------------------------------------------- */
112
    /*      The 16bit case is straight forward.  The underlying file        */
113
    /*      looks like a 16bit unsigned data too.                           */
114
    /* -------------------------------------------------------------------- */
115
    else if (eDataType == GDT_UInt16)
55✔
116
        return poBandFile->RasterIO(
55✔
117
            GF_Read, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
55✔
118
            nRequestXSize, nRequestYSize, pImage, nRequestXSize, nRequestYSize,
119
            GDT_UInt16, 1, nullptr, 2, nBlockXSize * 2, 0, nullptr);
55✔
120

121
    else if (eDataType == GDT_Byte)
×
122
        return poBandFile->RasterIO(
×
123
            GF_Read, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
×
124
            nRequestXSize, nRequestYSize, pImage, nRequestXSize, nRequestYSize,
125
            GDT_Byte, 1, nullptr, 1, nBlockXSize, 0, nullptr);
×
126

127
    CPLAssert(false);
×
128
    return CE_Failure;
129
}
130

131
/************************************************************************/
132
/*                            SAFESLCRasterBand                         */
133
/************************************************************************/
134

135
SAFESLCRasterBand::SAFESLCRasterBand(
3✔
136
    SAFEDataset *poDSIn, GDALDataType eDataTypeIn, const CPLString &osSwath,
137
    const CPLString &osPolarization,
138
    std::unique_ptr<GDALDataset> &&poBandFileIn, BandType eBandType)
3✔
139
    : poBandFile(std::move(poBandFileIn))
3✔
140
{
141
    poDS = poDSIn;
3✔
142
    eDataType = eDataTypeIn;
3✔
143
    m_eInputDataType = eDataTypeIn;
3✔
144
    GDALRasterBand *poSrcBand = poBandFile->GetRasterBand(1);
3✔
145
    poSrcBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
3✔
146
    m_eBandType = eBandType;
3✔
147

148
    if (!osSwath.empty())
3✔
149
        SetMetadataItem("SWATH", osSwath.c_str());
3✔
150

151
    if (!osPolarization.empty())
3✔
152
        SetMetadataItem("POLARIZATION", osPolarization.c_str());
3✔
153

154
    // For intensity band
155
    if (m_eBandType == INTENSITY)
3✔
156
        eDataType = GDT_Float32;
2✔
157
    else
158
        // For complex bands
159
        eDataType = GDT_CInt16;
1✔
160
}
3✔
161

162
/************************************************************************/
163
/*                             IReadBlock()                             */
164
/************************************************************************/
165

166
CPLErr SAFESLCRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
×
167
                                     void *pImage)
168

169
{
170
    /* -------------------------------------------------------------------- */
171
    /*      If the last strip is partial, we need to avoid                  */
172
    /*      over-requesting.  We also need to initialize the extra part     */
173
    /*      of the block to zero.                                           */
174
    /* -------------------------------------------------------------------- */
175
    int nRequestYSize;
176
    if ((nBlockYOff + 1) * nBlockYSize > nRasterYSize)
×
177
    {
178
        nRequestYSize = nRasterYSize - nBlockYOff * nBlockYSize;
×
179
        memset(pImage, 0,
×
180
               static_cast<size_t>(GDALGetDataTypeSizeBytes(eDataType)) *
×
181
                   nBlockXSize * nBlockYSize);
×
182
    }
183
    else
184
    {
185
        nRequestYSize = nBlockYSize;
×
186
    }
187

188
    /*-------------------------------------------------------------------- */
189
    /*      If the input imagery is tiled, also need to avoid over-        */
190
    /*      requesting in the X-direction.                                 */
191
    /* ------------------------------------------------------------------- */
192
    int nRequestXSize;
193
    if ((nBlockXOff + 1) * nBlockXSize > nRasterXSize)
×
194
    {
195
        nRequestXSize = nRasterXSize - nBlockXOff * nBlockXSize;
×
196
        memset(pImage, 0,
×
197
               static_cast<size_t>(GDALGetDataTypeSizeBytes(eDataType)) *
×
198
                   nBlockXSize * nBlockYSize);
×
199
    }
200
    else
201
        nRequestXSize = nBlockXSize;
×
202

203
    if (m_eInputDataType == GDT_CInt16 && poBandFile->GetRasterCount() == 2)
×
204
    {
205
        return poBandFile->RasterIO(
×
206
            GF_Read, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
×
207
            nRequestXSize, nRequestYSize, pImage, nRequestXSize, nRequestYSize,
208
            GDT_Int16, 2, nullptr, 4, nBlockXSize * 4, 2, nullptr);
×
209
    }
210
    // File has one sample marked as sample format void, a 32bits.
211
    else if (m_eInputDataType == GDT_CInt16 &&
×
212
             poBandFile->GetRasterCount() == 1)
×
213
    {
214
        if (m_eBandType == COMPLEX)
×
215
        {
216
            CPLErr eErr = poBandFile->RasterIO(
×
217
                GF_Read, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
×
218
                nRequestXSize, nRequestYSize, pImage, nRequestXSize,
219
                nRequestYSize, GDT_CInt16, 1, nullptr, 4, nBlockXSize * 4, 0,
×
220
                nullptr);
221
            if (eErr != CE_None)
×
222
            {
223
                return eErr;
×
224
            }
225
        }
226
        else if (m_eBandType == INTENSITY)
×
227
        {
228
            GInt16 *pnImageTmp = static_cast<GInt16 *>(VSI_MALLOC3_VERBOSE(
×
229
                2 * sizeof(int16_t), nBlockXSize, nBlockYSize));
230
            if (!pnImageTmp)
×
231
            {
232
                return CE_Failure;
×
233
            }
234

235
            CPLErr eErr = poBandFile->RasterIO(
×
236
                GF_Read, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
×
237
                nRequestXSize, nRequestYSize, pnImageTmp, nRequestXSize,
238
                nRequestYSize, GDT_CInt16, 1, nullptr, 4, nBlockXSize * 4, 0,
×
239
                nullptr);
240
            if (eErr != CE_None)
×
241
            {
242
                CPLFree(pnImageTmp);
×
243
                return eErr;
×
244
            }
245

246
            float *pfBuffer = static_cast<float *>(pImage);
×
247
#ifdef USE_OMP
248
            omp_set_num_threads(GetNumThreadsToUse());
249
#pragma omp parallel
250
#endif
251
            for (int i = 0; i < nBlockYSize; i++)
×
252
            {
253
#ifdef USE_OMP
254
#pragma omp for nowait
255
#endif
256
                for (int j = 0; j < nBlockXSize; j++)
×
257
                {
258
                    int nPixOff = (2 * (i * nBlockXSize)) + (j * 2);
×
259
                    int nOutPixOff = (i * nBlockXSize) + j;
×
260
                    pfBuffer[nOutPixOff] = static_cast<float>(
×
261
                        static_cast<double>(pnImageTmp[nPixOff] *
×
262
                                            pnImageTmp[nPixOff]) +
×
263
                        static_cast<double>(pnImageTmp[nPixOff + 1] *
×
264
                                            pnImageTmp[nPixOff + 1]));
×
265
                }
266
            }
267
            CPLFree(pnImageTmp);
×
268
        }
269
        return CE_None;
×
270
    }
271

272
    CPLAssert(false);
×
273
    return CE_Failure;
274
}
275

276
/************************************************************************/
277
/*                            SAFECalibRasterBand                       */
278
/************************************************************************/
279

280
SAFECalibratedRasterBand::SAFECalibratedRasterBand(
×
281
    SAFEDataset *poDSIn, GDALDataType eDataTypeIn, const CPLString &osSwath,
282
    const CPLString &osPolarization,
283
    std::unique_ptr<GDALDataset> &&poBandDatasetIn,
284
    const char *pszCalibrationFilename, CalibrationType eCalibrationType)
×
285
    : poBandDataset(std::move(poBandDatasetIn))
×
286
{
287
    poDS = poDSIn;
×
288
    GDALRasterBand *poSrcBand = poBandDataset->GetRasterBand(1);
×
289
    poSrcBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
×
290
    eDataType = eDataTypeIn;
×
291

292
    if (!osSwath.empty())
×
293
        SetMetadataItem("SWATH", osSwath.c_str());
×
294

295
    if (!osPolarization.empty())
×
296
        SetMetadataItem("POLARIZATION", osPolarization.c_str());
×
297

298
    m_osCalibrationFilename = pszCalibrationFilename;
×
299
    m_eInputDataType = eDataTypeIn;
×
300
    eDataType = GDT_Float32;
×
301
    m_eCalibrationType = eCalibrationType;
×
302
}
×
303

304
/************************************************************************/
305
/*                            ReadLUT()                                 */
306
/************************************************************************/
307
/* Read the provided LUT in to m_ndTable                                */
308
/************************************************************************/
309
bool SAFECalibratedRasterBand::ReadLUT()
×
310
{
311
    const char *const papszCalibrationNodes[3] = {
×
312
        "=calibrationVector.sigmaNought", "=calibrationVector.betaNought",
313
        "=calibrationVector.gamma"};
314
    CPLString osCalibrationNodeName = papszCalibrationNodes[m_eCalibrationType];
×
315
    const char *pszEndSpace = " ";
×
316
    CPLString osStartTime, osEndTime;
×
317
    CPLXMLNode *poLUT = CPLParseXMLFile(m_osCalibrationFilename);
×
318
    if (!poLUT)
×
319
        return false;
×
320

321
    CPLString osParseLUT;
×
322
    CPLString osParsePixelLUT;
×
323
    CPLString osParseAzimuthLUT;
×
324
    CPLString osParseLineNoLUT;
×
325
    for (CPLXMLNode *psNode = poLUT; psNode != nullptr;)
×
326
    {
327
        if (psNode->psNext != nullptr)
×
328
            psNode = psNode->psNext;
×
329

330
        if (EQUAL(psNode->pszValue, "calibration"))
×
331
        {
332
            for (psNode = psNode->psChild; psNode != nullptr;)
×
333
            {
334
                if (EQUAL(psNode->pszValue, "adsHeader"))
×
335
                {
336
                    osStartTime =
337
                        CPLGetXMLValue(psNode, "=adsHeader.startTime", " ");
×
338
                    osEndTime =
339
                        CPLGetXMLValue(psNode, "=adsHeader.stopTime", " ");
×
340
                }
341

342
                if (psNode->psNext != nullptr)
×
343
                    psNode = psNode->psNext;
×
344

345
                if (EQUAL(psNode->pszValue, "calibrationVectorList"))
×
346
                {
347
                    for (psNode = psNode->psChild; psNode != nullptr;
×
348
                         psNode = psNode->psNext)
×
349
                    {
350
                        if (EQUAL(psNode->pszValue, "calibrationVector"))
×
351
                        {
352
                            osParseAzimuthLUT += CPLGetXMLValue(
353
                                psNode, "=calibrationVector.azimuthTime", " ");
×
354
                            osParseAzimuthLUT += pszEndSpace;
×
355
                            osParseLineNoLUT += CPLGetXMLValue(
356
                                psNode, "=calibrationVector.line", " ");
×
357
                            osParseLineNoLUT += pszEndSpace;
×
358
                            osParsePixelLUT =
359
                                CPLGetXMLValue(psNode, "pixel", " ");
×
360
                            m_nNumPixels = static_cast<int>(CPLAtof(
×
361
                                CPLGetXMLValue(psNode, "pixel.count", " ")));
362
                            osParseLUT += CPLGetXMLValue(
363
                                psNode, osCalibrationNodeName, " ");
×
364
                            osParseLUT += pszEndSpace;
×
365
                        }
366
                    }
367
                }
368
            }
369
        }
370
    }
371
    CPLDestroyXMLNode(poLUT);
×
372

373
    osParsePixelLUT += pszEndSpace;
×
374

375
    CPLStringList oStartTimeList(
376
        CSLTokenizeString2(osStartTime, " ", CSLT_HONOURSTRINGS));
×
377
    if (!oStartTimeList.size())
×
378
        return false;
×
379
    m_oStartTimePoint = getTimePoint(oStartTimeList[0]);
×
380
    CPLStringList oEndTimeList(
381
        CSLTokenizeString2(osEndTime, " ", CSLT_HONOURSTRINGS));
×
382
    if (!oEndTimeList.size())
×
383
        return false;
×
384
    m_oStopTimePoint = getTimePoint(oEndTimeList[0]);
×
385
    m_oAzimuthList.Assign(
386
        CSLTokenizeString2(osParseAzimuthLUT, " ", CSLT_HONOURSTRINGS));
×
387
    CPLStringList oLUTList(
388
        CSLTokenizeString2(osParseLUT, " ", CSLT_HONOURSTRINGS));
×
389
    CPLStringList oPixelList(
390
        CSLTokenizeString2(osParsePixelLUT, " ", CSLT_HONOURSTRINGS));
×
391
    CPLStringList oLineNoList(
392
        CSLTokenizeString2(osParseLineNoLUT, " ", CSLT_HONOURSTRINGS));
×
393

394
    m_anPixelLUT.resize(m_nNumPixels);
×
395
    for (int i = 0; i < m_nNumPixels; i++)
×
396
        m_anPixelLUT[i] = static_cast<int>(CPLAtof(oPixelList[i]));
×
397

398
    int nTableSize = oLUTList.size();
×
399
    m_afTable.resize(nTableSize);
×
400
    for (int i = 0; i < nTableSize; i++)
×
401
        m_afTable[i] = static_cast<float>(CPLAtof(oLUTList[i]));
×
402

403
    int nLineListSize = oLineNoList.size();
×
404
    m_anLineLUT.resize(nLineListSize);
×
405
    for (int i = 0; i < nLineListSize; i++)
×
406
        m_anLineLUT[i] = static_cast<int>(CPLAtof(oLineNoList[i]));
×
407

408
    return true;
×
409
}
410

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

415
CPLErr SAFECalibratedRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
×
416
                                            void *pImage)
417

418
{
419
    /* -------------------------------------------------------------------- */
420
    /*      If the last strip is partial, we need to avoid                  */
421
    /*      over-requesting.  We also need to initialize the extra part     */
422
    /*      of the block to zero.                                           */
423
    /* -------------------------------------------------------------------- */
424
    int nRequestYSize;
425
    if ((nBlockYOff + 1) * nBlockYSize > nRasterYSize)
×
426
    {
427
        nRequestYSize = nRasterYSize - nBlockYOff * nBlockYSize;
×
428
        memset(pImage, 0,
×
429
               static_cast<size_t>(GDALGetDataTypeSizeBytes(eDataType)) *
×
430
                   nBlockXSize * nBlockYSize);
×
431
    }
432
    else
433
    {
434
        nRequestYSize = nBlockYSize;
×
435
    }
436

437
    // Check LUT values and fail before reading
438
    int nLineCalVecIdx = getCalibrationVectorIndex(nBlockYOff);
×
439
    const char *pszVec0Str = m_oAzimuthList[nLineCalVecIdx];
×
440
    const char *pszVec1Str = m_oAzimuthList[nLineCalVecIdx + 1];
×
441
    if (((m_eInputDataType == GDT_CInt16) || (m_eInputDataType == GDT_Int16)) &&
×
442
        (!pszVec0Str || !pszVec1Str))
×
443
        return CE_Failure;
×
444

445
    /*-------------------------------------------------------------------- */
446
    /*      If the input imagery is tiled, also need to avoid over-        */
447
    /*      requesting in the X-direction.                                 */
448
    /* ------------------------------------------------------------------- */
449
    int nRequestXSize;
450
    if ((nBlockXOff + 1) * nBlockXSize > nRasterXSize)
×
451
    {
452
        nRequestXSize = nRasterXSize - nBlockXOff * nBlockXSize;
×
453
        memset(pImage, 0,
×
454
               static_cast<size_t>(GDALGetDataTypeSizeBytes(eDataType)) *
×
455
                   nBlockXSize * nBlockYSize);
×
456
    }
457
    else
458
    {
459
        nRequestXSize = nBlockXSize;
×
460
    }
461

462
    TimePoint azTime = getazTime(m_oStartTimePoint, m_oStopTimePoint,
463
                                 nRasterYSize, nBlockYOff);
×
464
    TimePoint oVec0Time = getTimePoint(pszVec0Str);
×
465
    TimePoint oVec1Time = getTimePoint(pszVec1Str);
×
466
    double dfMuY =
467
        getTimeDiff(oVec0Time, azTime) / getTimeDiff(oVec0Time, oVec1Time);
×
468

469
    if (m_eInputDataType == GDT_CInt16)
×
470
    {
471
        CPLErr eErr = CE_None;
×
472
        GInt16 *pnImageTmp = static_cast<GInt16 *>(
473
            VSI_MALLOC3_VERBOSE(2 * sizeof(int16_t), nBlockXSize, nBlockYSize));
×
474
        if (!pnImageTmp)
×
475
            return CE_Failure;
×
476

477
        if (poBandDataset->GetRasterCount() == 2)
×
478
        {
479
            eErr = poBandDataset->RasterIO(
×
480
                GF_Read, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
×
481
                nRequestXSize, nRequestYSize, pnImageTmp, nRequestXSize,
482
                nRequestYSize, GDT_Int16, 2, nullptr, 4, nBlockXSize * 4, 2,
×
483
                nullptr);
484
        }
485
        /* --------------------------------------------------------------------
486
         */
487
        /*      File has one sample marked as sample format void, a 32bits. */
488
        /* --------------------------------------------------------------------
489
         */
490
        else if (poBandDataset->GetRasterCount() == 1)
×
491
        {
492
            eErr = poBandDataset->RasterIO(
×
493
                GF_Read, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
×
494
                nRequestXSize, nRequestYSize, pnImageTmp, nRequestXSize,
495
                nRequestYSize, GDT_CInt16, 1, nullptr, 4, nBlockXSize * 4, 0,
×
496
                nullptr);
497
        }
498

499
        // Interpolation of LUT Value
500
#ifdef USE_OMP
501
        omp_set_num_threads(GetNumThreadsToUse());
502
#pragma omp parallel
503
#endif
504
        for (int i = 0; i < nBlockYSize; i++)
×
505
        {
506
#ifdef USE_OMP
507
#pragma omp for nowait
508
#endif
509
            for (int j = 0; j < nBlockXSize; j++)
×
510
            {
511
                int nPixOff = (2 * (i * nBlockXSize)) + (j * 2);
×
512
                int nOutPixOff = (i * nBlockXSize) + j;
×
513
                int nPixelCalvecIdx = getPixelIndex(j);
×
514
                double dfMuX = (double)(j - m_anPixelLUT[nPixelCalvecIdx]) /
×
515
                               (double)(m_anPixelLUT[nPixelCalvecIdx + 1] -
×
516
                                        m_anPixelLUT[nPixelCalvecIdx]);
×
517
                int lutIdx1 = (nLineCalVecIdx * m_nNumPixels) + nPixelCalvecIdx;
×
518
                int lutIdx2 =
×
519
                    (nLineCalVecIdx * m_nNumPixels) + (nPixelCalvecIdx + 1);
×
520
                int lutIdx3 =
×
521
                    ((nLineCalVecIdx + 1) * m_nNumPixels) + nPixelCalvecIdx;
×
522
                int lutIdx4 = ((nLineCalVecIdx + 1) * m_nNumPixels) +
×
523
                              (nPixelCalvecIdx + 1);
×
524
                double dfLutValue =
525
                    ((1 - dfMuY) * (((1 - dfMuX) * m_afTable[lutIdx1]) +
×
526
                                    (dfMuX * m_afTable[lutIdx2]))) +
×
527
                    (dfMuY * (((1 - dfMuX) * m_afTable[lutIdx3]) +
×
528
                              (dfMuX * m_afTable[lutIdx4])));
×
529
                double dfNum = static_cast<double>(
×
530
                    (pnImageTmp[nPixOff] * pnImageTmp[nPixOff]) +
×
531
                    (pnImageTmp[nPixOff + 1] * pnImageTmp[nPixOff + 1]));
×
532
                double dfCalibValue = dfNum / (dfLutValue * dfLutValue);
×
533
                ((float *)pImage)[nOutPixOff] = (float)dfCalibValue;
×
534
            }
535
        }
536
        CPLFree(pnImageTmp);
×
537
        return eErr;
×
538
    }
539
    else if (m_eInputDataType == GDT_UInt16)
×
540
    {
541
        CPLErr eErr = CE_None;
×
542
        GUInt16 *pnImageTmp = static_cast<GUInt16 *>(VSI_MALLOC3_VERBOSE(
×
543
            nBlockXSize, nBlockYSize, GDALGetDataTypeSizeBytes(GDT_UInt16)));
544
        if (!pnImageTmp)
×
545
            return CE_Failure;
×
546
        eErr = poBandDataset->RasterIO(GF_Read, nBlockXOff * nBlockXSize,
×
547
                                       nBlockYOff * nBlockYSize, nRequestXSize,
×
548
                                       nRequestYSize, pnImageTmp, nRequestXSize,
549
                                       nRequestYSize, GDT_UInt16, 1, nullptr, 2,
550
                                       nBlockXSize * 2, 0, nullptr);
×
551

552
#ifdef USE_OMP
553
        omp_set_num_threads(GetNumThreadsToUse());
554
#pragma omp parallel
555
#endif
556
        for (int i = 0; i < nBlockYSize; i++)
×
557
        {
558
#ifdef USE_OMP
559
#pragma omp for nowait
560
#endif
561
            for (int j = 0; j < nBlockXSize; j++)
×
562
            {
563
                int nPixOff = (i * nBlockXSize) + j;
×
564
                int nPixelCalvecIdx = getPixelIndex(j);
×
565
                double dfMuX = (double)(j - m_anPixelLUT[nPixelCalvecIdx]) /
×
566
                               (double)(m_anPixelLUT[nPixelCalvecIdx + 1] -
×
567
                                        m_anPixelLUT[nPixelCalvecIdx]);
×
568
                int lutIdx1 = (nLineCalVecIdx * m_nNumPixels) + nPixelCalvecIdx;
×
569
                int lutIdx2 =
×
570
                    (nLineCalVecIdx * m_nNumPixels) + (nPixelCalvecIdx + 1);
×
571
                int lutIdx3 =
×
572
                    ((nLineCalVecIdx + 1) * m_nNumPixels) + (nPixelCalvecIdx);
×
573
                int lutIdx4 = ((nLineCalVecIdx + 1) * m_nNumPixels) +
×
574
                              (nPixelCalvecIdx + 1);
×
575
                double dfLutValue =
576
                    ((1 - dfMuY) * (((1 - dfMuX) * m_afTable[lutIdx1]) +
×
577
                                    (dfMuX * m_afTable[lutIdx2]))) +
×
578
                    (dfMuY * (((1 - dfMuX) * m_afTable[lutIdx3]) +
×
579
                              (dfMuX * m_afTable[lutIdx4])));
×
580
                double dfCalibValue =
×
581
                    (double)(pnImageTmp[nPixOff] * pnImageTmp[nPixOff]) /
×
582
                    (dfLutValue * dfLutValue);
×
583
                ((float *)pImage)[nPixOff] = (float)dfCalibValue;
×
584
            }
585
        }
586
        CPLFree(pnImageTmp);
×
587
        return eErr;
×
588
    }
589
    else if (eDataType == GDT_Byte)  // Check if this is required.
×
590
        return poBandDataset->RasterIO(
×
591
            GF_Read, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
×
592
            nRequestXSize, nRequestYSize, pImage, nRequestXSize, nRequestYSize,
593
            GDT_Byte, 1, nullptr, 1, nBlockXSize, 0, nullptr);
×
594

595
    CPLAssert(false);
×
596
    return CE_Failure;
597
}
598

599
/************************************************************************/
600
/* ==================================================================== */
601
/*                              SAFEDataset                              */
602
/* ==================================================================== */
603
/************************************************************************/
604

605
/************************************************************************/
606
/*                             SAFEDataset()                            */
607
/************************************************************************/
608

609
SAFEDataset::SAFEDataset()
11✔
610
{
611
    m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
11✔
612
}
11✔
613

614
/************************************************************************/
615
/*                            ~SAFEDataset()                            */
616
/************************************************************************/
617

618
SAFEDataset::~SAFEDataset()
22✔
619

620
{
621
    SAFEDataset::FlushCache(true);
11✔
622

623
    if (nGCPCount > 0)
11✔
624
    {
625
        GDALDeinitGCPs(nGCPCount, pasGCPList);
11✔
626
        CPLFree(pasGCPList);
11✔
627
    }
628

629
    SAFEDataset::CloseDependentDatasets();
11✔
630

631
    CSLDestroy(papszSubDatasets);
11✔
632
    CSLDestroy(papszExtraFiles);
11✔
633
}
22✔
634

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

639
int SAFEDataset::CloseDependentDatasets()
11✔
640
{
641
    int bHasDroppedRef = GDALPamDataset::CloseDependentDatasets();
11✔
642

643
    if (nBands != 0)
11✔
644
        bHasDroppedRef = TRUE;
11✔
645

646
    for (int iBand = 0; iBand < nBands; iBand++)
28✔
647
    {
648
        delete papoBands[iBand];
17✔
649
    }
650
    nBands = 0;
11✔
651

652
    return bHasDroppedRef;
11✔
653
}
654

655
/************************************************************************/
656
/*                      GetMetaDataObject()                             */
657
/************************************************************************/
658

659
const CPLXMLNode *
660
SAFEDataset::GetMetaDataObject(const CPLXMLNode *psMetaDataObjects,
121✔
661
                               const char *metadataObjectId)
662
{
663
    /* -------------------------------------------------------------------- */
664
    /*      Look for DataObject Element by ID.                              */
665
    /* -------------------------------------------------------------------- */
666
    for (const CPLXMLNode *psMDO = psMetaDataObjects->psChild; psMDO != nullptr;
1,848✔
667
         psMDO = psMDO->psNext)
1,727✔
668
    {
669
        if (psMDO->eType != CXT_Element ||
1,848✔
670
            !(EQUAL(psMDO->pszValue, "metadataObject")))
1,848✔
671
        {
672
            continue;
×
673
        }
674

675
        const char *pszElementID = CPLGetXMLValue(psMDO, "ID", "");
1,848✔
676

677
        if (EQUAL(pszElementID, metadataObjectId))
1,848✔
678
        {
679
            return psMDO;
121✔
680
        }
681
    }
682

683
    CPLError(CE_Warning, CPLE_AppDefined, "MetadataObject not found with ID=%s",
×
684
             metadataObjectId);
685

686
    return nullptr;
×
687
}
688

689
/************************************************************************/
690
/*                      GetDataObject()                                 */
691
/************************************************************************/
692

693
const CPLXMLNode *SAFEDataset::GetDataObject(const CPLXMLNode *psDataObjects,
88✔
694
                                             const char *dataObjectId)
695
{
696
    /* -------------------------------------------------------------------- */
697
    /*      Look for DataObject Element by ID.                              */
698
    /* -------------------------------------------------------------------- */
699
    for (const CPLXMLNode *psDO = psDataObjects->psChild; psDO != nullptr;
836✔
700
         psDO = psDO->psNext)
748✔
701
    {
702
        if (psDO->eType != CXT_Element ||
836✔
703
            !(EQUAL(psDO->pszValue, "dataObject")))
836✔
704
        {
705
            continue;
×
706
        }
707

708
        const char *pszElementID = CPLGetXMLValue(psDO, "ID", "");
836✔
709

710
        if (EQUAL(pszElementID, dataObjectId))
836✔
711
        {
712
            return psDO;
88✔
713
        }
714
    }
715

716
    CPLError(CE_Warning, CPLE_AppDefined, "DataObject not found with ID=%s",
×
717
             dataObjectId);
718

719
    return nullptr;
×
720
}
721

722
const CPLXMLNode *
723
SAFEDataset::GetDataObject(const CPLXMLNode *psMetaDataObjects,
66✔
724
                           const CPLXMLNode *psDataObjects,
725
                           const char *metadataObjectId)
726
{
727
    /* -------------------------------------------------------------------- */
728
    /*      Look for MetadataObject Element by ID.                          */
729
    /* -------------------------------------------------------------------- */
730
    const CPLXMLNode *psMDO =
731
        SAFEDataset::GetMetaDataObject(psMetaDataObjects, metadataObjectId);
66✔
732

733
    if (psMDO != nullptr)
66✔
734
    {
735
        const char *dataObjectId =
736
            CPLGetXMLValue(psMDO, "dataObjectPointer.dataObjectID", "");
66✔
737
        if (*dataObjectId != '\0')
66✔
738
        {
739
            return SAFEDataset::GetDataObject(psDataObjects, dataObjectId);
66✔
740
        }
741
    }
742

743
    CPLError(CE_Warning, CPLE_AppDefined, "DataObject not found with MetaID=%s",
×
744
             metadataObjectId);
745

746
    return nullptr;
×
747
}
748

749
/************************************************************************/
750
/*                            GetFileList()                             */
751
/************************************************************************/
752

753
char **SAFEDataset::GetFileList()
5✔
754

755
{
756
    char **papszFileList = GDALPamDataset::GetFileList();
5✔
757

758
    papszFileList = CSLInsertStrings(papszFileList, -1, papszExtraFiles);
5✔
759

760
    return papszFileList;
5✔
761
}
762

763
/************************************************************************/
764
/*                             Identify()                               */
765
/************************************************************************/
766

767
int SAFEDataset::Identify(GDALOpenInfo *poOpenInfo)
60,947✔
768
{
769
    /* Check for the case where we're trying to read the calibrated data: */
770
    if (STARTS_WITH_CI(poOpenInfo->pszFilename, "SENTINEL1_CALIB:"))
60,947✔
771
    {
772
        return TRUE;
12✔
773
    }
774

775
    /* Check for directory access when there is a manifest.safe file in the
776
       directory. */
777
    if (poOpenInfo->bIsDirectory)
60,935✔
778
    {
779
        VSIStatBufL sStat;
780
        CPLString osMDFilename = CPLFormCIFilenameSafe(
×
781
            poOpenInfo->pszFilename, "manifest.safe", nullptr);
1,228✔
782

783
        if (VSIStatL(osMDFilename, &sStat) == 0 && VSI_ISREG(sStat.st_mode))
614✔
784
        {
785
            GDALOpenInfo oOpenInfo(osMDFilename, GA_ReadOnly, nullptr);
6✔
786
            return Identify(&oOpenInfo);
3✔
787
        }
788
        return FALSE;
611✔
789
    }
790

791
    /* otherwise, do our normal stuff */
792
    if (!EQUAL(CPLGetFilename(poOpenInfo->pszFilename), "manifest.safe"))
60,321✔
793
        return FALSE;
60,308✔
794

795
    if (poOpenInfo->nHeaderBytes < 100)
13✔
796
        return FALSE;
×
797

798
    const char *pszHeader =
13✔
799
        reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
800
    if (!strstr(pszHeader, "<xfdu:XFDU"))
13✔
801
        return FALSE;
×
802

803
    // This driver doesn't handle Sentinel-2 or RCM (RADARSAT Constellation Mission) data
804
    if (strstr(pszHeader, "sentinel-2") ||
13✔
805
        strstr(pszHeader, "rcm_prod_manifest.xsd"))
13✔
806
        return FALSE;
1✔
807

808
    return TRUE;
12✔
809
}
810

811
/************************************************************************/
812
/*                                Open()                                */
813
/************************************************************************/
814

815
GDALDataset *SAFEDataset::Open(GDALOpenInfo *poOpenInfo)
12✔
816

817
{
818

819
    // Is this a SENTINEL-1 manifest.safe definition?
820
    if (!SAFEDataset::Identify(poOpenInfo))
12✔
821
    {
822
        return nullptr;
×
823
    }
824

825
    /* -------------------------------------------------------------------- */
826
    /*        Get subdataset information, if relevant                       */
827
    /* -------------------------------------------------------------------- */
828
    CPLString osMDFilename;
24✔
829
    bool bIsSubDS = false;
12✔
830
    bool bIsSLC = false;
12✔
831
    // Subdataset 1st level selection (ex: for swath selection)
832
    CPLString osSelectedSubDS1;
24✔
833
    // Subdataset 2nd level selection (ex: for polarization selection)
834
    CPLString osSelectedSubDS2;
24✔
835
    CPLString osSelectedSubDS3;
24✔
836
    // 0 for SIGMA , 1 for BETA, 2 for GAMMA and # for UNCALIB dataset
837
    SAFECalibratedRasterBand::CalibrationType eCalibrationType =
12✔
838
        SAFECalibratedRasterBand::SIGMA_NOUGHT;
839
    bool bCalibrated = false;
12✔
840

841
    // 0 for amplitude, 1 for complex (2 band : I , Q) and 2 for INTENSITY
842
    typedef enum
843
    {
844
        UNKNOWN = -1,
845
        AMPLITUDE,
846
        COMPLEX,
847
        INTENSITY
848
    } RequestDataType;
849

850
    RequestDataType eRequestType = UNKNOWN;
12✔
851
    // Calibration Information selection
852
    CPLString osSubdatasetName;
24✔
853

854
    if (STARTS_WITH_CI(poOpenInfo->pszFilename, "SENTINEL1_CALIB:"))
12✔
855
    {
856
        bIsSubDS = true;
6✔
857
        osMDFilename = poOpenInfo->pszFilename + strlen("SENTINEL1_CALIB:");
6✔
858
        const char *pszSelectionCalib = strchr(osMDFilename.c_str(), ':');
6✔
859
        if (pszSelectionCalib == nullptr ||
12✔
860
            pszSelectionCalib == osMDFilename.c_str())
6✔
861
        {
862
            CPLError(CE_Failure, CPLE_AppDefined,
×
863
                     "Invalid syntax for SENTINEL1_CALIB:");
864
            return nullptr;
1✔
865
        }
866

867
        CPLString osCalibrationValue = osMDFilename;
6✔
868
        osCalibrationValue.resize(pszSelectionCalib - osMDFilename.c_str());
6✔
869
        osMDFilename = pszSelectionCalib + strlen(":");
6✔
870
        if (EQUAL(osCalibrationValue.c_str(), "UNCALIB"))
6✔
871
        {
872
            bCalibrated = false;
3✔
873
        }
874
        else if (EQUAL(osCalibrationValue.c_str(), "SIGMA0"))
3✔
875
        {
876
            bCalibrated = true;
3✔
877
            eCalibrationType = SAFECalibratedRasterBand::SIGMA_NOUGHT;
3✔
878
        }
879
        else if (EQUAL(osCalibrationValue.c_str(), "BETA0"))
×
880
        {
881
            bCalibrated = true;
×
882
            eCalibrationType = SAFECalibratedRasterBand::BETA_NOUGHT;
×
883
        }
884
        else if (EQUAL(osCalibrationValue.c_str(), "GAMMA"))
×
885
        {
886
            bCalibrated = true;
×
887
            eCalibrationType = SAFECalibratedRasterBand::GAMMA;
×
888
        }
889
        else
890
        {
891
            CPLError(CE_Failure, CPLE_AppDefined,
×
892
                     "Invalid syntax for SENTINEL1_CALIB:");
893
            return nullptr;
×
894
        }
895

896
        const auto nSelectionUnitPos = osMDFilename.rfind(':');
6✔
897
        if (nSelectionUnitPos == std::string::npos || nSelectionUnitPos == 0)
6✔
898
        {
899
            CPLError(CE_Failure, CPLE_AppDefined,
×
900
                     "Invalid syntax for SENTINEL1_CALIB:");
901
            return nullptr;
×
902
        }
903

904
        CPLString osUnitValue = osMDFilename.substr(nSelectionUnitPos + 1);
6✔
905
        osMDFilename.resize(nSelectionUnitPos);
6✔
906
        if (EQUAL(osUnitValue.c_str(), "AMPLITUDE"))
6✔
907
            eRequestType = AMPLITUDE;
3✔
908
        else if (EQUAL(osUnitValue.c_str(), "COMPLEX"))
3✔
909
            eRequestType = COMPLEX;
×
910
        else if (EQUAL(osUnitValue.c_str(), "INTENSITY"))
3✔
911
            eRequestType = INTENSITY;
2✔
912
        else
913
        {
914
            CPLError(CE_Failure, CPLE_AppDefined,
1✔
915
                     "Invalid syntax for SENTINEL1_CALIB:");
916
            return nullptr;
1✔
917
        }
918

919
        const auto nSelection1Pos = osMDFilename.rfind(':');
5✔
920
        if (nSelection1Pos == std::string::npos || nSelection1Pos == 0)
5✔
921
        {
922
            CPLError(CE_Failure, CPLE_AppDefined,
×
923
                     "Invalid syntax for SENTINEL1_CALIB:");
924
            return nullptr;
×
925
        }
926
        osSelectedSubDS1 = osMDFilename.substr(nSelection1Pos + 1);
5✔
927
        osMDFilename.resize(nSelection1Pos);
5✔
928

929
        const auto nSelection2Pos = osSelectedSubDS1.find('_');
5✔
930
        if (nSelection2Pos != std::string::npos && nSelection2Pos != 0)
5✔
931
        {
932
            osSelectedSubDS2 = osSelectedSubDS1.substr(nSelection2Pos + 1);
4✔
933
            osSelectedSubDS1.resize(nSelection2Pos);
4✔
934
            const auto nSelection3Pos = osSelectedSubDS2.find('_');
4✔
935
            if (nSelection3Pos != std::string::npos && nSelection3Pos != 0)
4✔
936
            {
937
                osSelectedSubDS3 = osSelectedSubDS2.substr(nSelection3Pos + 1);
2✔
938
                osSelectedSubDS2.resize(nSelection3Pos);
2✔
939
            }
940
        }
941

942
        // update directory check:
943
        VSIStatBufL sStat;
944
        if (VSIStatL(osMDFilename.c_str(), &sStat) == 0)
5✔
945
            poOpenInfo->bIsDirectory = VSI_ISDIR(sStat.st_mode);
5✔
946
        if (!bCalibrated)
5✔
947
            osSubdatasetName = "UNCALIB";
3✔
948
        else if (eCalibrationType == SAFECalibratedRasterBand::SIGMA_NOUGHT)
2✔
949
            osSubdatasetName = "SIGMA0";
2✔
950
        else if (eCalibrationType == SAFECalibratedRasterBand::BETA_NOUGHT)
×
951
            osSubdatasetName = "BETA0";
×
952
        else if (eCalibrationType == SAFECalibratedRasterBand::GAMMA)
×
953
            osSubdatasetName = "GAMMA";
×
954
        osSubdatasetName += ":";
5✔
955
        if (!osUnitValue.empty())
5✔
956
        {
957
            osSubdatasetName += osUnitValue;
5✔
958
            osSubdatasetName += ":";
5✔
959
        }
960
        if (!osSelectedSubDS1.empty())
5✔
961
        {
962
            osSubdatasetName += osSelectedSubDS1;
5✔
963
            osSubdatasetName += ":";
5✔
964
        }
965
        if (!osSelectedSubDS2.empty())
5✔
966
        {
967
            osSubdatasetName += osSelectedSubDS2;
4✔
968
            osSubdatasetName += ":";
4✔
969
        }
970
        if (!osSelectedSubDS3.empty())
5✔
971
        {
972
            osSubdatasetName += osSelectedSubDS3;
2✔
973
            osSubdatasetName += ":";
2✔
974
        }
975
        if (!osSubdatasetName.empty())
5✔
976
        {
977
            if (osSubdatasetName.back() == ':')
5✔
978
                osSubdatasetName.pop_back();
5✔
979
        }
980
    }
981
    else
982
    {
983
        osMDFilename = poOpenInfo->pszFilename;
6✔
984
    }
985

986
    if (poOpenInfo->bIsDirectory)
11✔
987
    {
988
        osMDFilename = CPLFormCIFilenameSafe(osMDFilename.c_str(),
4✔
989
                                             "manifest.safe", nullptr);
2✔
990
    }
991

992
    /* -------------------------------------------------------------------- */
993
    /*      Ingest the manifest.safe file.                                  */
994
    /* -------------------------------------------------------------------- */
995

996
    auto psManifest = CPLXMLTreeCloser(CPLParseXMLFile(osMDFilename));
22✔
997
    if (psManifest == nullptr)
11✔
998
        return nullptr;
×
999

1000
    CPLString osPath(CPLGetPathSafe(osMDFilename));
22✔
1001

1002
    /* -------------------------------------------------------------------- */
1003
    /*      Confirm the requested access is supported.                      */
1004
    /* -------------------------------------------------------------------- */
1005
    if (poOpenInfo->eAccess == GA_Update)
11✔
1006
    {
1007
        ReportUpdateNotSupportedByDriver("SAFE");
×
1008
        return nullptr;
×
1009
    }
1010

1011
    /* -------------------------------------------------------------------- */
1012
    /*      Get contentUnit parent element.                                 */
1013
    /* -------------------------------------------------------------------- */
1014
    const CPLXMLNode *psContentUnits = CPLGetXMLNode(
11✔
1015
        psManifest.get(), "=xfdu:XFDU.informationPackageMap.xfdu:contentUnit");
1016
    if (psContentUnits == nullptr)
11✔
1017
    {
1018
        CPLError(CE_Failure, CPLE_OpenFailed,
×
1019
                 "Failed to find <xfdu:XFDU><informationPackageMap>"
1020
                 "<xfdu:contentUnit> in manifest file.");
1021
        return nullptr;
×
1022
    }
1023

1024
    /* -------------------------------------------------------------------- */
1025
    /*      Get Metadata Objects element.                                   */
1026
    /* -------------------------------------------------------------------- */
1027
    const CPLXMLNode *psMetaDataObjects =
1028
        CPLGetXMLNode(psManifest.get(), "=xfdu:XFDU.metadataSection");
11✔
1029
    if (psMetaDataObjects == nullptr)
11✔
1030
    {
1031
        CPLError(CE_Failure, CPLE_OpenFailed,
×
1032
                 "Failed to find <xfdu:XFDU><metadataSection>"
1033
                 "in manifest file.");
1034
        return nullptr;
×
1035
    }
1036

1037
    /* -------------------------------------------------------------------- */
1038
    /*      Get Data Objects element.                                       */
1039
    /* -------------------------------------------------------------------- */
1040
    const CPLXMLNode *psDataObjects =
1041
        CPLGetXMLNode(psManifest.get(), "=xfdu:XFDU.dataObjectSection");
11✔
1042
    if (psDataObjects == nullptr)
11✔
1043
    {
1044
        CPLError(CE_Failure, CPLE_OpenFailed,
×
1045
                 "Failed to find <xfdu:XFDU><dataObjectSection> in document.");
1046
        return nullptr;
×
1047
    }
1048

1049
    /* -------------------------------------------------------------------- */
1050
    /*      Create the dataset.                                             */
1051
    /* -------------------------------------------------------------------- */
1052
    auto poDS = std::make_unique<SAFEDataset>();
22✔
1053

1054
    poDS->psManifest = std::move(psManifest);
11✔
1055

1056
    /* -------------------------------------------------------------------- */
1057
    /*      Look for "Measurement Data Unit" contentUnit elements.          */
1058
    /* -------------------------------------------------------------------- */
1059
    // Map with all measures aggregated by swath
1060
    std::map<CPLString, std::set<CPLString>> oMapSwaths2Pols;
22✔
1061
    std::vector<CPLString> oImageNumberSwPol;
22✔
1062
    bool isWave = false;
11✔
1063

1064
    for (CPLXMLNode *psContentUnit = psContentUnits->psChild;
11✔
1065
         psContentUnit != nullptr; psContentUnit = psContentUnit->psNext)
374✔
1066
    {
1067
        if (psContentUnit->eType != CXT_Element ||
363✔
1068
            !(EQUAL(psContentUnit->pszValue, "xfdu:contentUnit")))
316✔
1069
        {
1070
            continue;
47✔
1071
        }
1072

1073
        const char *pszUnitType = CPLGetXMLValue(psContentUnit, "unitType", "");
316✔
1074

1075
        const char *pszAnnotation = nullptr;
316✔
1076
        const char *pszCalibration = nullptr;
316✔
1077
        const char *pszMeasurement = nullptr;
316✔
1078

1079
        if (EQUAL(pszUnitType, "Measurement Data Unit"))
316✔
1080
        {
1081
            /* Get dmdID and dataObjectID */
1082
            const char *pszDmdID = CPLGetXMLValue(psContentUnit, "dmdID", "");
30✔
1083
            const char *pszDataObjectID = CPLGetXMLValue(
30✔
1084
                psContentUnit, "dataObjectPointer.dataObjectID", "");
1085
            if (*pszDataObjectID == '\0' || *pszDmdID == '\0')
30✔
1086
                continue;
13✔
1087

1088
            const CPLXMLNode *psDataObject =
1089
                SAFEDataset::GetDataObject(psDataObjects, pszDataObjectID);
22✔
1090

1091
            const char *pszRepId = CPLGetXMLValue(psDataObject, "repID", "");
22✔
1092
            if (!EQUAL(pszRepId, "s1Level1MeasurementSchema"))
22✔
1093
                continue;
×
1094

1095
            pszMeasurement = CPLGetXMLValue(psDataObject,
22✔
1096
                                            "byteStream.fileLocation.href", "");
1097
            if (*pszMeasurement == '\0')
22✔
1098
                continue;
×
1099

1100
            char **papszTokens = CSLTokenizeString2(pszDmdID, " ",
22✔
1101
                                                    CSLT_ALLOWEMPTYTOKENS |
1102
                                                        CSLT_STRIPLEADSPACES |
1103
                                                        CSLT_STRIPENDSPACES);
1104

1105
            for (int j = 0; j < CSLCount(papszTokens); j++)
110✔
1106
            {
1107
                const char *pszId = papszTokens[j];
88✔
1108
                if (*pszId == '\0')
88✔
1109
                    continue;
22✔
1110

1111
                // Map the metadata ID to the object element
1112
                const CPLXMLNode *psDO = SAFEDataset::GetDataObject(
66✔
1113
                    psMetaDataObjects, psDataObjects, pszId);
1114
                if (psDO == nullptr)
66✔
1115
                    continue;
×
1116

1117
                // check object type
1118
                pszRepId = CPLGetXMLValue(psDO, "repID", "");
66✔
1119
                if (EQUAL(pszRepId, "s1Level1ProductSchema"))
66✔
1120
                {
1121
                    /* Get annotation filename */
1122
                    pszAnnotation = CPLGetXMLValue(
22✔
1123
                        psDO, "byteStream.fileLocation.href", "");
1124
                    if (*pszAnnotation == '\0')
22✔
1125
                        continue;
×
1126
                }
1127
                else if (EQUAL(pszRepId, "s1Level1CalibrationSchema"))
44✔
1128
                {
1129
                    pszCalibration = CPLGetXMLValue(
22✔
1130
                        psDO, "byteStream.fileLocation.href", "");
1131
                    if (*pszCalibration == '\0')
22✔
1132
                        continue;
×
1133
                }
1134
                else
1135
                {
1136
                    continue;
22✔
1137
                }
1138
            }
1139

1140
            CSLDestroy(papszTokens);
22✔
1141

1142
            if (pszAnnotation == nullptr || pszCalibration == nullptr)
22✔
1143
                continue;
×
1144

1145
            // open Annotation XML file
1146
            const CPLString osAnnotationFilePath =
1147
                CPLFormFilenameSafe(osPath, pszAnnotation, nullptr);
22✔
1148
            const CPLString osCalibrationFilePath =
1149
                CPLFormFilenameSafe(osPath, pszCalibration, nullptr);
22✔
1150

1151
            CPLXMLTreeCloser psAnnotation(
1152
                CPLParseXMLFile(osAnnotationFilePath));
22✔
1153
            if (psAnnotation.get() == nullptr)
22✔
1154
                continue;
×
1155
            CPLXMLTreeCloser psCalibration(
1156
                CPLParseXMLFile(osCalibrationFilePath));
22✔
1157
            if (psCalibration.get() == nullptr)
22✔
1158
                continue;
×
1159

1160
            /* --------------------------------------------------------------------
1161
             */
1162
            /*      Get overall image information. */
1163
            /* --------------------------------------------------------------------
1164
             */
1165
            const CPLString osProductType = CPLGetXMLValue(
1166
                psAnnotation.get(), "=product.adsHeader.productType", "UNK");
22✔
1167
            const CPLString osMissionId = CPLGetXMLValue(
1168
                psAnnotation.get(), "=product.adsHeader.missionId", "UNK");
22✔
1169
            const CPLString osPolarization = CPLGetXMLValue(
1170
                psAnnotation.get(), "=product.adsHeader.polarisation", "UNK");
22✔
1171
            const CPLString osMode = CPLGetXMLValue(
1172
                psAnnotation.get(), "=product.adsHeader.mode", "UNK");
22✔
1173
            const CPLString osSwath = CPLGetXMLValue(
1174
                psAnnotation.get(), "=product.adsHeader.swath", "UNK");
22✔
1175
            const CPLString osImageNumber = CPLGetXMLValue(
1176
                psAnnotation.get(), "=product.adsHeader.imageNumber", "UNK");
22✔
1177

1178
            oMapSwaths2Pols[osSwath].insert(osPolarization);
22✔
1179
            oImageNumberSwPol.push_back(osImageNumber + " " + osSwath + " " +
22✔
1180
                                        osPolarization);
1181
            if (EQUAL(osMode.c_str(), "WV"))
22✔
1182
                isWave = true;
6✔
1183

1184
            if (EQUAL(osProductType.c_str(), "SLC"))
22✔
1185
                bIsSLC = true;
6✔
1186

1187
            // if the dataunit is amplitude or complex and there is calibration
1188
            // applied it's not possible as calibrated datasets are intensity.
1189
            if (eRequestType != INTENSITY && bCalibrated)
22✔
1190
                continue;
×
1191

1192
            if (osSelectedSubDS1.empty())
22✔
1193
            {
1194
                // If not subdataset was selected,
1195
                // open the first one we can find.
1196
                osSelectedSubDS1 = osSwath;
6✔
1197
            }
1198

1199
            if (osSelectedSubDS3.empty() && isWave)
22✔
1200
            {
1201
                // If the selected mode is Wave mode (different file structure)
1202
                // open the first vignette in the dataset.
1203
                osSelectedSubDS3 = osImageNumber;
1✔
1204
            }
1205
            if (!EQUAL(osSelectedSubDS1.c_str(), osSwath.c_str()))
22✔
1206
            {
1207
                // do not mix swath, otherwise it does not work for SLC products
1208
                continue;
3✔
1209
            }
1210

1211
            if (!osSelectedSubDS2.empty() &&
25✔
1212
                (osSelectedSubDS2.find(osPolarization) == std::string::npos))
6✔
1213
            {
1214
                // Add only selected polarizations.
1215
                continue;
2✔
1216
            }
1217

1218
            if (!osSelectedSubDS3.empty() &&
20✔
1219
                !EQUAL(osSelectedSubDS3.c_str(), osImageNumber.c_str()))
3✔
1220
            {
1221
                // Add only selected image number (for Wave)
1222
                continue;
×
1223
            }
1224

1225
            // Changed the position of this code segment till nullptr
1226
            poDS->nRasterXSize = atoi(CPLGetXMLValue(
17✔
1227
                psAnnotation.get(),
17✔
1228
                "=product.imageAnnotation.imageInformation.numberOfSamples",
1229
                "-1"));
1230
            poDS->nRasterYSize = atoi(CPLGetXMLValue(
17✔
1231
                psAnnotation.get(),
17✔
1232
                "=product.imageAnnotation.imageInformation.numberOfLines",
1233
                "-1"));
1234
            if (poDS->nRasterXSize <= 1 || poDS->nRasterYSize <= 1)
17✔
1235
            {
1236
                CPLError(
×
1237
                    CE_Failure, CPLE_OpenFailed,
1238
                    "Non-sane raster dimensions provided in manifest.safe. "
1239
                    "If this is a valid SENTINEL-1 scene, please contact your "
1240
                    "data provider for a corrected dataset.");
1241
                return nullptr;
×
1242
            }
1243

1244
            poDS->SetMetadataItem("PRODUCT_TYPE", osProductType.c_str());
17✔
1245
            poDS->SetMetadataItem("MISSION_ID", osMissionId.c_str());
17✔
1246
            poDS->SetMetadataItem("MODE", osMode.c_str());
17✔
1247
            poDS->SetMetadataItem("SWATH", osSwath.c_str());
17✔
1248

1249
            /* --------------------------------------------------------------------
1250
             */
1251
            /*      Get dataType (so we can recognize complex data), and the */
1252
            /*      bitsPerSample. */
1253
            /* --------------------------------------------------------------------
1254
             */
1255

1256
            const char *pszDataType = CPLGetXMLValue(
17✔
1257
                psAnnotation.get(),
17✔
1258
                "=product.imageAnnotation.imageInformation.outputPixels", "");
1259

1260
            GDALDataType eDataType;
1261
            if (EQUAL(pszDataType, "16 bit Signed Integer"))
17✔
1262
                eDataType = GDT_CInt16;
3✔
1263
            else if (EQUAL(pszDataType, "16 bit Unsigned Integer"))
14✔
1264
                eDataType = GDT_UInt16;
14✔
1265
            else
1266
            {
1267
                CPLError(CE_Failure, CPLE_AppDefined,
×
1268
                         "dataType=%s: not a supported configuration.",
1269
                         pszDataType);
1270
                return nullptr;
×
1271
            }
1272

1273
            /* Extract pixel spacing information */
1274
            const char *pszPixelSpacing = CPLGetXMLValue(
17✔
1275
                psAnnotation.get(),
17✔
1276
                "=product.imageAnnotation.imageInformation.rangePixelSpacing",
1277
                "UNK");
1278
            poDS->SetMetadataItem("PIXEL_SPACING", pszPixelSpacing);
17✔
1279

1280
            const char *pszLineSpacing = CPLGetXMLValue(
17✔
1281
                psAnnotation.get(),
17✔
1282
                "=product.imageAnnotation.imageInformation.azimuthPixelSpacing",
1283
                "UNK");
1284
            poDS->SetMetadataItem("LINE_SPACING", pszLineSpacing);
17✔
1285

1286
            /* --------------------------------------------------------------------
1287
             */
1288
            /*      Form full filename (path of manifest.safe + measurement
1289
             * file).  */
1290
            /* --------------------------------------------------------------------
1291
             */
1292
            const std::string osFullFilename(
1293
                CPLFormFilenameSafe(osPath, pszMeasurement, nullptr));
17✔
1294

1295
            /* --------------------------------------------------------------------
1296
             */
1297
            /*      Try and open the file. */
1298
            /* --------------------------------------------------------------------
1299
             */
1300
            std::unique_ptr<GDALDataset> poBandFile;
×
1301
            {
1302
                CPLTurnFailureIntoWarningBackuper oErrorsToWarnings{};
17✔
1303
                poBandFile = std::unique_ptr<GDALDataset>(
34✔
1304
                    GDALDataset::Open(osFullFilename.c_str(),
1305
                                      GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR));
17✔
1306
            }
1307

1308
            if (poBandFile == nullptr)
17✔
1309
            {
1310
                // NOP
1311
            }
1312
            else if (poBandFile->GetRasterCount() == 0)
17✔
1313
            {
1314
                poBandFile.reset();
×
1315
            }
1316
            else
1317
            {
1318
                poDS->papszExtraFiles =
34✔
1319
                    CSLAddString(poDS->papszExtraFiles, osAnnotationFilePath);
17✔
1320
                poDS->papszExtraFiles =
34✔
1321
                    CSLAddString(poDS->papszExtraFiles, osCalibrationFilePath);
17✔
1322
                poDS->papszExtraFiles =
34✔
1323
                    CSLAddString(poDS->papszExtraFiles, osFullFilename.c_str());
17✔
1324
                /* --------------------------------------------------------------------
1325
                 */
1326
                /*      Collect Annotation Processing Information */
1327
                /* --------------------------------------------------------------------
1328
                 */
1329
                CPLXMLNode *psProcessingInfo = CPLGetXMLNode(
17✔
1330
                    psAnnotation.get(),
1331
                    "=product.imageAnnotation.processingInformation");
1332

1333
                if (psProcessingInfo != nullptr)
17✔
1334
                {
1335
                    OGRSpatialReference oLL, oPrj;
28✔
1336

1337
                    const char *pszEllipsoidName =
1338
                        CPLGetXMLValue(psProcessingInfo, "ellipsoidName", "");
14✔
1339
                    const double minor_axis = CPLAtof(CPLGetXMLValue(
14✔
1340
                        psProcessingInfo, "ellipsoidSemiMinorAxis", "0.0"));
1341
                    const double major_axis = CPLAtof(CPLGetXMLValue(
14✔
1342
                        psProcessingInfo, "ellipsoidSemiMajorAxis", "0.0"));
1343

1344
                    if (EQUAL(pszEllipsoidName, "") || (minor_axis == 0.0) ||
14✔
1345
                        (major_axis == 0.0))
1346
                    {
1347
                        CPLError(CE_Warning, CPLE_AppDefined,
×
1348
                                 "Warning- incomplete"
1349
                                 " ellipsoid information.  Using wgs-84 "
1350
                                 "parameters.\n");
1351
                        oLL.SetWellKnownGeogCS("WGS84");
×
1352
                        oPrj.SetWellKnownGeogCS("WGS84");
×
1353
                    }
1354
                    else if (EQUAL(pszEllipsoidName, "WGS84"))
14✔
1355
                    {
1356
                        oLL.SetWellKnownGeogCS("WGS84");
14✔
1357
                        oPrj.SetWellKnownGeogCS("WGS84");
14✔
1358
                    }
1359
                    else
1360
                    {
1361
                        const double inv_flattening =
×
1362
                            major_axis / (major_axis - minor_axis);
×
1363
                        oLL.SetGeogCS("", "", pszEllipsoidName, major_axis,
×
1364
                                      inv_flattening);
1365
                        oPrj.SetGeogCS("", "", pszEllipsoidName, major_axis,
×
1366
                                       inv_flattening);
1367
                    }
1368

1369
                    oLL.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
14✔
1370
                    poDS->m_oGCPSRS = std::move(oLL);
14✔
1371
                }
1372

1373
                /* --------------------------------------------------------------------
1374
                 */
1375
                /*      Collect GCPs. */
1376
                /* --------------------------------------------------------------------
1377
                 */
1378
                CPLXMLNode *psGeoGrid = CPLGetXMLNode(
17✔
1379
                    psAnnotation.get(),
1380
                    "=product.geolocationGrid.geolocationGridPointList");
1381

1382
                if (psGeoGrid != nullptr)
17✔
1383
                {
1384
                    if (poDS->nGCPCount > 0)
17✔
1385
                    {
1386
                        GDALDeinitGCPs(poDS->nGCPCount, poDS->pasGCPList);
6✔
1387
                        CPLFree(poDS->pasGCPList);
6✔
1388
                    }
1389

1390
                    /* count GCPs */
1391
                    poDS->nGCPCount = 0;
17✔
1392

1393
                    for (CPLXMLNode *psNode = psGeoGrid->psChild;
17✔
1394
                         psNode != nullptr; psNode = psNode->psNext)
52✔
1395
                    {
1396
                        if (EQUAL(psNode->pszValue, "geolocationGridPoint"))
35✔
1397
                            poDS->nGCPCount++;
18✔
1398
                    }
1399

1400
                    if (poDS->nGCPCount > 0)
17✔
1401
                    {
1402
                        poDS->pasGCPList = static_cast<GDAL_GCP *>(
34✔
1403
                            CPLCalloc(sizeof(GDAL_GCP), poDS->nGCPCount));
17✔
1404

1405
                        poDS->nGCPCount = 0;
17✔
1406

1407
                        for (CPLXMLNode *psNode = psGeoGrid->psChild;
17✔
1408
                             psNode != nullptr; psNode = psNode->psNext)
52✔
1409
                        {
1410
                            GDAL_GCP *psGCP =
1411
                                poDS->pasGCPList + poDS->nGCPCount;
35✔
1412

1413
                            if (!EQUAL(psNode->pszValue,
35✔
1414
                                       "geolocationGridPoint"))
1415
                                continue;
17✔
1416

1417
                            poDS->nGCPCount++;
18✔
1418

1419
                            char szID[32];
1420
                            snprintf(szID, sizeof(szID), "%d", poDS->nGCPCount);
18✔
1421
                            psGCP->pszId = CPLStrdup(szID);
18✔
1422
                            psGCP->pszInfo = CPLStrdup("");
18✔
1423
                            psGCP->dfGCPPixel =
18✔
1424
                                CPLAtof(CPLGetXMLValue(psNode, "pixel", "0"));
18✔
1425
                            psGCP->dfGCPLine =
18✔
1426
                                CPLAtof(CPLGetXMLValue(psNode, "line", "0"));
18✔
1427
                            psGCP->dfGCPX = CPLAtof(
18✔
1428
                                CPLGetXMLValue(psNode, "longitude", ""));
1429
                            psGCP->dfGCPY =
18✔
1430
                                CPLAtof(CPLGetXMLValue(psNode, "latitude", ""));
18✔
1431
                            psGCP->dfGCPZ =
18✔
1432
                                CPLAtof(CPLGetXMLValue(psNode, "height", ""));
18✔
1433
                        }
1434
                    }
1435
                }
1436

1437
                // Create bands
1438
                if (EQUAL(osProductType.c_str(), "SLC"))
17✔
1439
                {
1440
                    // only add bands if no subDS or uncalibrated subdataset
1441
                    // with complex data. (Calibrated will always be intensity
1442
                    // only)
1443
                    if (!bCalibrated &&
3✔
1444
                        (eRequestType == UNKNOWN || eRequestType == COMPLEX))
×
1445
                    {
1446
                        poBandFile->MarkAsShared();
1✔
1447
                        SAFESLCRasterBand *poBand0 = new SAFESLCRasterBand(
1448
                            poDS.get(), eDataType, osSwath, osPolarization,
1✔
1449
                            std::move(poBandFile), SAFESLCRasterBand::COMPLEX);
1✔
1450
                        poDS->SetBand(poDS->GetRasterCount() + 1, poBand0);
1✔
1451
                    }
1452
                    else if (eRequestType == INTENSITY)  // Intensity
2✔
1453
                    {
1454
                        SAFESLCRasterBand *poBand1 = new SAFESLCRasterBand(
1455
                            poDS.get(), eDataType, osSwath, osPolarization,
2✔
1456
                            std::move(poBandFile),
2✔
1457
                            SAFESLCRasterBand::INTENSITY);
2✔
1458
                        poDS->SetBand(poDS->GetRasterCount() + 1, poBand1);
2✔
1459
                    }
1460
                }
1461
                else if (!bCalibrated &&
14✔
1462
                         (eRequestType == UNKNOWN || eRequestType == AMPLITUDE))
4✔
1463
                {
1464
                    SAFERasterBand *poBand = new SAFERasterBand(
1465
                        poDS.get(), eDataType, osSwath, osPolarization,
14✔
1466
                        std::move(poBandFile));
14✔
1467
                    poDS->SetBand(poDS->GetRasterCount() + 1, poBand);
14✔
1468
                }
1469
                else if (bCalibrated &&
×
1470
                         (eRequestType == UNKNOWN || eRequestType == COMPLEX))
×
1471
                {
1472
                    auto poBand = std::make_unique<SAFECalibratedRasterBand>(
1473
                        poDS.get(), eDataType, osSwath, osPolarization,
×
1474
                        std::move(poBandFile), osCalibrationFilePath,
×
1475
                        eCalibrationType);
×
1476
                    if (!poBand->ReadLUT())
×
1477
                    {
1478
                        CPLError(CE_Failure, CPLE_OpenFailed,
×
1479
                                 "Reading calibration LUT(s) failed: %s.",
1480
                                 osCalibrationFilePath.c_str());
1481
                        return nullptr;
×
1482
                    }
1483
                    poDS->SetBand(poDS->GetRasterCount() + 1,
×
1484
                                  std::move(poBand));
×
1485
                }
1486
            }
1487
        }
1488
    }
1489

1490
    // loop through all Swath/pols to add subdatasets
1491
    if (!bIsSubDS)
11✔
1492
    {
1493
        const CPLString aosCalibrationValues[4] = {"SIGMA0", "BETA0", "GAMMA",
1494
                                                   "UNCALIB"};
36✔
1495
        const CPLString aosDataUnitValues[3] = {"AMPLITUDE", "COMPLEX",
1496
                                                "INTENSITY"};
30✔
1497
        if (!isWave)
6✔
1498
        {
1499
            for (const auto &iterSwath : oMapSwaths2Pols)
10✔
1500
            {
1501
                CPLString osSubDS1 = iterSwath.first;
10✔
1502
                CPLString osSubDS2;
10✔
1503

1504
                for (const auto &pol : iterSwath.second)
15✔
1505
                {
1506
                    if (!osSubDS2.empty())
10✔
1507
                        osSubDS2 += "+";
5✔
1508
                    osSubDS2 += pol;
10✔
1509
                    // Create single band or multiband complex SubDataset
1510
                    int i = 0;
10✔
1511
                    if (bIsSLC)
10✔
1512
                    {
1513
                        for (i = 0; i < 3; i++)
×
1514
                        {
1515
                            CPLString osCalibTemp = aosCalibrationValues[i];
×
1516
                            poDS->AddSubDataset(
×
1517
                                CPLSPrintf("SENTINEL1_CALIB:%s:%s:%s_%s:%s",
1518
                                           osCalibTemp.c_str(),
1519
                                           osMDFilename.c_str(),
1520
                                           osSubDS1.c_str(), pol.c_str(),
1521
                                           aosDataUnitValues[2].c_str()),
1522
                                CPLSPrintf("Single band with %s swath and %s "
1523
                                           "polarization and %s calibration",
1524
                                           osSubDS1.c_str(), pol.c_str(),
1525
                                           osCalibTemp.c_str()));
1526
                        }
1527

1528
                        CPLString osCalibTemp = aosCalibrationValues[i];
×
1529
                        poDS->AddSubDataset(
×
1530
                            CPLSPrintf("SENTINEL1_CALIB:%s:%s:%s_%s:%s",
1531
                                       osCalibTemp.c_str(),
1532
                                       osMDFilename.c_str(), osSubDS1.c_str(),
1533
                                       pol.c_str(),
1534
                                       aosDataUnitValues[1].c_str()),
1535
                            CPLSPrintf("Single band with %s swath and %s "
1536
                                       "polarization and %s calibration",
1537
                                       osSubDS1.c_str(), pol.c_str(),
1538
                                       osCalibTemp.c_str()));
1539
                        poDS->AddSubDataset(
×
1540
                            CPLSPrintf("SENTINEL1_CALIB:%s:%s:%s_%s:%s",
1541
                                       osCalibTemp.c_str(),
1542
                                       osMDFilename.c_str(), osSubDS1.c_str(),
1543
                                       pol.c_str(),
1544
                                       aosDataUnitValues[2].c_str()),
1545
                            CPLSPrintf("Single band with %s swath and %s "
1546
                                       "polarization and %s calibration",
1547
                                       osSubDS1.c_str(), pol.c_str(),
1548
                                       osCalibTemp.c_str()));
1549
                    }
1550
                    else
1551
                    {
1552
                        i = 3;
10✔
1553
                        CPLString osCalibTemp = aosCalibrationValues[i];
10✔
1554

1555
                        poDS->AddSubDataset(
10✔
1556
                            CPLSPrintf("SENTINEL1_CALIB:%s:%s:%s_%s:%s",
1557
                                       osCalibTemp.c_str(),
1558
                                       osMDFilename.c_str(), osSubDS1.c_str(),
1559
                                       pol.c_str(),
1560
                                       aosDataUnitValues[0].c_str()),
1561
                            CPLSPrintf("Single band with %s swath and %s "
1562
                                       "polarization and %s calibration",
1563
                                       osSubDS1.c_str(), pol.c_str(),
1564
                                       osCalibTemp.c_str()));
1565
                    }
1566
                }
1567

1568
                if (iterSwath.second.size() > 1)
5✔
1569
                {
1570
                    // Create single band subdataset with all polarizations
1571
                    int i = 0;
5✔
1572
                    if (bIsSLC)
5✔
1573
                    {
1574
                        for (i = 0; i < 3; i++)
×
1575
                        {
1576
                            CPLString osCalibTemp = aosCalibrationValues[i];
×
1577

1578
                            poDS->AddSubDataset(
×
1579
                                CPLSPrintf("SENTINEL1_CALIB:%s:%s:%s:%s",
1580
                                           osCalibTemp.c_str(),
1581
                                           osMDFilename.c_str(),
1582
                                           osSubDS1.c_str(),
1583
                                           aosDataUnitValues[2].c_str()),
1584
                                CPLSPrintf(
1585
                                    "%s swath with all polarizations (%s) as "
1586
                                    "bands and %s calibration",
1587
                                    osSubDS1.c_str(), osSubDS2.c_str(),
1588
                                    osCalibTemp.c_str()));
1589
                        }
1590

1591
                        CPLString osCalibTemp = aosCalibrationValues[i];
×
1592
                        poDS->AddSubDataset(
×
1593
                            CPLSPrintf("SENTINEL1_CALIB:%s:%s:%s:%s",
1594
                                       osCalibTemp.c_str(),
1595
                                       osMDFilename.c_str(), osSubDS1.c_str(),
1596
                                       aosDataUnitValues[1].c_str()),
1597
                            CPLSPrintf(
1598
                                "%s swath with all polarizations (%s) as "
1599
                                "bands and %s calibration",
1600
                                osSubDS1.c_str(), osSubDS2.c_str(),
1601
                                osCalibTemp.c_str()));
1602
                        poDS->AddSubDataset(
×
1603
                            CPLSPrintf("SENTINEL1_CALIB:%s:%s:%s:%s",
1604
                                       osCalibTemp.c_str(),
1605
                                       osMDFilename.c_str(), osSubDS1.c_str(),
1606
                                       aosDataUnitValues[2].c_str()),
1607
                            CPLSPrintf(
1608
                                "%s swath with all polarizations (%s) as "
1609
                                "bands and %s calibration",
1610
                                osSubDS1.c_str(), osSubDS2.c_str(),
1611
                                osCalibTemp.c_str()));
1612
                    }
1613
                    else
1614
                    {
1615
                        i = 3;
5✔
1616
                        CPLString osCalibTemp = aosCalibrationValues[i];
5✔
1617
                        poDS->AddSubDataset(
5✔
1618
                            CPLSPrintf("SENTINEL1_CALIB:%s:%s:%s:%s",
1619
                                       osCalibTemp.c_str(),
1620
                                       osMDFilename.c_str(), osSubDS1.c_str(),
1621
                                       aosDataUnitValues[0].c_str()),
1622
                            CPLSPrintf(
1623
                                "%s swath with all polarizations (%s) as "
1624
                                "bands and %s calibration",
1625
                                osSubDS1.c_str(), osSubDS2.c_str(),
1626
                                osCalibTemp.c_str()));
1627
                    }
1628
                }
1629
            }
1630
        }
1631
        else
1632
        {
1633
            for (const CPLString &osImgSwPol : oImageNumberSwPol)
3✔
1634
            {
1635
                CPLString osImgSwPolTmp = osImgSwPol;
4✔
1636
                const char *pszImage = strchr(osImgSwPolTmp.c_str(), ' ');
2✔
1637
                CPLString osImage, osSwath, osPolarization;
4✔
1638
                if (pszImage != nullptr)
2✔
1639
                {
1640
                    osImage = osImgSwPolTmp;
2✔
1641
                    osImage.resize(pszImage - osImgSwPolTmp.c_str());
2✔
1642
                    osImgSwPolTmp = pszImage + strlen(" ");
2✔
1643
                    const char *pszSwath = strchr(osImgSwPolTmp.c_str(), ' ');
2✔
1644
                    if (pszSwath != nullptr)
2✔
1645
                    {
1646
                        osSwath = osImgSwPolTmp;
2✔
1647
                        osSwath.resize(pszSwath - osImgSwPolTmp.c_str());
2✔
1648
                        osPolarization = pszSwath + strlen(" ");
2✔
1649
                        int i = 0;
2✔
1650

1651
                        if (bIsSLC)
2✔
1652
                        {
1653
                            for (i = 0; i < 3; i++)
8✔
1654
                            {
1655
                                CPLString osCalibTemp = aosCalibrationValues[i];
6✔
1656

1657
                                poDS->AddSubDataset(
6✔
1658
                                    CPLSPrintf(
1659
                                        "SENTINEL1_CALIB:%s:%s:%s_%s_%s:%s",
1660
                                        osCalibTemp.c_str(),
1661
                                        osMDFilename.c_str(), osSwath.c_str(),
1662
                                        osPolarization.c_str(), osImage.c_str(),
1663
                                        aosDataUnitValues[2].c_str()),
1664
                                    CPLSPrintf(
1665
                                        "Single band with %s swath and %s "
1666
                                        "polarization and %s calibration",
1667
                                        osSwath.c_str(), osPolarization.c_str(),
1668
                                        osCalibTemp.c_str()));
1669
                            }
1670

1671
                            CPLString osCalibTemp = aosCalibrationValues[i];
2✔
1672

1673
                            poDS->AddSubDataset(
2✔
1674
                                CPLSPrintf(
1675
                                    "SENTINEL1_CALIB:%s:%s:%s_%s_%s:%s",
1676
                                    osCalibTemp.c_str(), osMDFilename.c_str(),
1677
                                    osSwath.c_str(), osPolarization.c_str(),
1678
                                    osImage.c_str(),
1679
                                    aosDataUnitValues[1].c_str()),
1680
                                CPLSPrintf("Single band with %s swath and %s "
1681
                                           "polarization and %s calibration",
1682
                                           osSwath.c_str(),
1683
                                           osPolarization.c_str(),
1684
                                           osCalibTemp.c_str()));
1685

1686
                            poDS->AddSubDataset(
2✔
1687
                                CPLSPrintf(
1688
                                    "SENTINEL1_CALIB:%s:%s:%s_%s_%s:%s",
1689
                                    osCalibTemp.c_str(), osMDFilename.c_str(),
1690
                                    osSwath.c_str(), osPolarization.c_str(),
1691
                                    osImage.c_str(),
1692
                                    aosDataUnitValues[2].c_str()),
1693
                                CPLSPrintf("Single band with %s swath and %s "
1694
                                           "polarization and %s calibration",
1695
                                           osSwath.c_str(),
1696
                                           osPolarization.c_str(),
1697
                                           osCalibTemp.c_str()));
1698
                        }
1699
                        else
1700
                        {
1701
                            i = 3;
×
1702
                            CPLString osCalibTemp = aosCalibrationValues[i];
×
1703

1704
                            poDS->AddSubDataset(
×
1705
                                CPLSPrintf(
1706
                                    "SENTINEL1_CALIB:%s:%s:%s_%s_%s:%s",
1707
                                    osCalibTemp.c_str(), osMDFilename.c_str(),
1708
                                    osSwath.c_str(), osPolarization.c_str(),
1709
                                    osImage.c_str(),
1710
                                    aosDataUnitValues[0].c_str()),
1711
                                CPLSPrintf("Single band with %s swath and %s "
1712
                                           "polarization and %s calibration",
1713
                                           osSwath.c_str(),
1714
                                           osPolarization.c_str(),
1715
                                           osCalibTemp.c_str()));
1716
                        }
1717
                    }
1718
                }
1719
            }
1720
        }
1721
    }
1722
    if (poDS->GetRasterCount() == 0)
11✔
1723
    {
1724
        CPLError(CE_Failure, CPLE_OpenFailed, "Measurement bands not found.");
×
1725
        return nullptr;
×
1726
    }
1727

1728
    /* -------------------------------------------------------------------- */
1729
    /*      Collect more metadata elements                                  */
1730
    /* -------------------------------------------------------------------- */
1731

1732
    /* -------------------------------------------------------------------- */
1733
    /*      Platform information                                            */
1734
    /* -------------------------------------------------------------------- */
1735
    const CPLXMLNode *psPlatformAttrs =
1736
        SAFEDataset::GetMetaDataObject(psMetaDataObjects, "platform");
11✔
1737

1738
    if (psPlatformAttrs != nullptr)
11✔
1739
    {
1740
        const char *pszItem =
1741
            CPLGetXMLValue(psPlatformAttrs,
11✔
1742
                           "metadataWrap.xmlData.safe:platform"
1743
                           ".safe:familyName",
1744
                           "");
1745
        poDS->SetMetadataItem("SATELLITE_IDENTIFIER", pszItem);
11✔
1746

1747
        pszItem =
1748
            CPLGetXMLValue(psPlatformAttrs,
11✔
1749
                           "metadataWrap.xmlData.safe:platform"
1750
                           ".safe:instrument.safe:familyName.abbreviation",
1751
                           "");
1752
        poDS->SetMetadataItem("SENSOR_IDENTIFIER", pszItem);
11✔
1753

1754
        pszItem = CPLGetXMLValue(psPlatformAttrs,
11✔
1755
                                 "metadataWrap.xmlData.safe:platform"
1756
                                 ".safe:instrument.safe:extension"
1757
                                 ".s1sarl1:instrumentMode.s1sarl1:mode",
1758
                                 "UNK");
1759
        poDS->SetMetadataItem("BEAM_MODE", pszItem);
11✔
1760

1761
        pszItem = CPLGetXMLValue(psPlatformAttrs,
11✔
1762
                                 "metadataWrap.xmlData.safe:platform"
1763
                                 ".safe:instrument.safe:extension"
1764
                                 ".s1sarl1:instrumentMode.s1sarl1:swath",
1765
                                 "UNK");
1766
        poDS->SetMetadataItem("BEAM_SWATH", pszItem);
11✔
1767
    }
1768

1769
    /* -------------------------------------------------------------------- */
1770
    /*      Acquisition Period information                                  */
1771
    /* -------------------------------------------------------------------- */
1772
    const CPLXMLNode *psAcquisitionAttrs =
1773
        SAFEDataset::GetMetaDataObject(psMetaDataObjects, "acquisitionPeriod");
11✔
1774

1775
    if (psAcquisitionAttrs != nullptr)
11✔
1776
    {
1777
        const char *pszItem =
1778
            CPLGetXMLValue(psAcquisitionAttrs,
11✔
1779
                           "metadataWrap.xmlData.safe:acquisitionPeriod"
1780
                           ".safe:startTime",
1781
                           "UNK");
1782
        poDS->SetMetadataItem("ACQUISITION_START_TIME", pszItem);
11✔
1783
        pszItem = CPLGetXMLValue(psAcquisitionAttrs,
11✔
1784
                                 "metadataWrap.xmlData.safe:acquisitionPeriod"
1785
                                 ".safe:stopTime",
1786
                                 "UNK");
1787
        poDS->SetMetadataItem("ACQUISITION_STOP_TIME", pszItem);
11✔
1788
    }
1789

1790
    /* -------------------------------------------------------------------- */
1791
    /*      Processing information                                          */
1792
    /* -------------------------------------------------------------------- */
1793
    const CPLXMLNode *psProcessingAttrs =
1794
        SAFEDataset::GetMetaDataObject(psMetaDataObjects, "processing");
11✔
1795

1796
    if (psProcessingAttrs != nullptr)
11✔
1797
    {
1798
        const char *pszItem = CPLGetXMLValue(
11✔
1799
            psProcessingAttrs,
1800
            "metadataWrap.xmlData.safe:processing.safe:facility.name", "UNK");
1801
        poDS->SetMetadataItem("FACILITY_IDENTIFIER", pszItem);
11✔
1802
    }
1803

1804
    /* -------------------------------------------------------------------- */
1805
    /*      Measurement Orbit Reference information                         */
1806
    /* -------------------------------------------------------------------- */
1807
    const CPLXMLNode *psOrbitAttrs = SAFEDataset::GetMetaDataObject(
11✔
1808
        psMetaDataObjects, "measurementOrbitReference");
1809

1810
    if (psOrbitAttrs != nullptr)
11✔
1811
    {
1812
        const char *pszItem =
1813
            CPLGetXMLValue(psOrbitAttrs,
11✔
1814
                           "metadataWrap.xmlData.safe:orbitReference"
1815
                           ".safe:orbitNumber",
1816
                           "UNK");
1817
        poDS->SetMetadataItem("ORBIT_NUMBER", pszItem);
11✔
1818
        pszItem = CPLGetXMLValue(psOrbitAttrs,
11✔
1819
                                 "metadataWrap.xmlData.safe:orbitReference"
1820
                                 ".safe:extension.s1:orbitProperties.s1:pass",
1821
                                 "UNK");
1822
        poDS->SetMetadataItem("ORBIT_DIRECTION", pszItem);
11✔
1823
    }
1824

1825
    /* -------------------------------------------------------------------- */
1826
    /*      Footprint                                                       */
1827
    /* -------------------------------------------------------------------- */
1828
    const CPLXMLNode *psFrameSet = SAFEDataset::GetMetaDataObject(
11✔
1829
        psMetaDataObjects, "measurementFrameSet");
1830

1831
    if (psFrameSet)
11✔
1832
    {
1833
        const auto psFootPrint = CPLGetXMLNode(psFrameSet, "metadataWrap."
11✔
1834
                                                           "xmlData."
1835
                                                           "safe:frameSet."
1836
                                                           "safe:frame."
1837
                                                           "safe:footPrint");
1838
        if (psFootPrint)
11✔
1839
        {
1840
            const char *pszSRSName =
1841
                CPLGetXMLValue(psFootPrint, "srsName", nullptr);
11✔
1842
            const char *pszCoordinates =
1843
                CPLGetXMLValue(psFootPrint, "gml:coordinates", nullptr);
11✔
1844
            if (pszSRSName &&
11✔
1845
                EQUAL(pszSRSName,
11✔
1846
                      "http://www.opengis.net/gml/srs/epsg.xml#4326") &&
11✔
1847
                pszCoordinates)
1848
            {
1849
                const CPLStringList aosValues(
1850
                    CSLTokenizeString2(pszCoordinates, " ,", 0));
22✔
1851
                if (aosValues.size() == 8)
11✔
1852
                {
1853
                    poDS->SetMetadataItem(
22✔
1854
                        "FOOTPRINT",
1855
                        CPLSPrintf("POLYGON((%s %s,%s %s,%s %s,%s %s, %s %s))",
1856
                                   aosValues[1], aosValues[0], aosValues[3],
1857
                                   aosValues[2], aosValues[5], aosValues[4],
1858
                                   aosValues[7], aosValues[6], aosValues[1],
1859
                                   aosValues[0]));
11✔
1860
                }
1861
            }
1862
        }
1863
    }
1864

1865
    /* -------------------------------------------------------------------- */
1866
    /*      Initialize any PAM information.                                 */
1867
    /* -------------------------------------------------------------------- */
1868
    const CPLString osDescription = osMDFilename;
22✔
1869

1870
    /* -------------------------------------------------------------------- */
1871
    /*      Initialize any PAM information.                                 */
1872
    /* -------------------------------------------------------------------- */
1873
    poDS->SetDescription(osDescription);
11✔
1874

1875
    poDS->SetPhysicalFilename(osMDFilename);
11✔
1876
    if (!osSubdatasetName.empty())
11✔
1877
    {
1878
        poDS->SetDescription(poOpenInfo->pszFilename);
5✔
1879
        poDS->SetSubdatasetName(osSubdatasetName);
5✔
1880
    }
1881

1882
    poDS->TryLoadXML();
11✔
1883

1884
    /* -------------------------------------------------------------------- */
1885
    /*      Check for overviews.                                            */
1886
    /* -------------------------------------------------------------------- */
1887
    poDS->oOvManager.Initialize(poDS.get(), ":::VIRTUAL:::");
11✔
1888

1889
    return poDS.release();
11✔
1890
}
1891

1892
/************************************************************************/
1893
/*                            AddSubDataset()                           */
1894
/************************************************************************/
1895
void SAFEDataset::AddSubDataset(const CPLString &osName,
25✔
1896
                                const CPLString &osDesc)
1897
{
1898
    ++m_nSubDSNum;
25✔
1899
    papszSubDatasets = CSLAddNameValue(
25✔
1900
        papszSubDatasets, CPLSPrintf("SUBDATASET_%d_NAME", m_nSubDSNum),
1901
        osName.c_str());
1902
    papszSubDatasets = CSLAddNameValue(
25✔
1903
        papszSubDatasets, CPLSPrintf("SUBDATASET_%d_DESC", m_nSubDSNum),
1904
        osDesc.c_str());
1905
}
25✔
1906

1907
/************************************************************************/
1908
/*                            GetGCPCount()                             */
1909
/************************************************************************/
1910

1911
int SAFEDataset::GetGCPCount()
2✔
1912
{
1913
    return nGCPCount;
2✔
1914
}
1915

1916
/************************************************************************/
1917
/*                          GetGCPSpatialRef()                          */
1918
/************************************************************************/
1919

1920
const OGRSpatialReference *SAFEDataset::GetGCPSpatialRef() const
×
1921

1922
{
1923
    return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
×
1924
}
1925

1926
/************************************************************************/
1927
/*                               GetGCPs()                              */
1928
/************************************************************************/
1929

1930
const GDAL_GCP *SAFEDataset::GetGCPs()
2✔
1931

1932
{
1933
    return pasGCPList;
2✔
1934
}
1935

1936
/************************************************************************/
1937
/*                      GetMetadataDomainList()                         */
1938
/************************************************************************/
1939

1940
char **SAFEDataset::GetMetadataDomainList()
×
1941
{
1942
    return BuildMetadataDomainList(GDALDataset::GetMetadataDomainList(), TRUE,
×
1943
                                   "SUBDATASETS", nullptr);
×
1944
}
1945

1946
/************************************************************************/
1947
/*                            GetMetadata()                             */
1948
/************************************************************************/
1949

1950
char **SAFEDataset::GetMetadata(const char *pszDomain)
3✔
1951
{
1952
    if (pszDomain != nullptr && STARTS_WITH_CI(pszDomain, "SUBDATASETS"))
3✔
1953
        return papszSubDatasets;
3✔
1954

1955
    return GDALDataset::GetMetadata(pszDomain);
×
1956
}
1957

1958
/************************************************************************/
1959
/*                         GDALRegister_SAFE()                          */
1960
/************************************************************************/
1961

1962
void GDALRegister_SAFE()
1,911✔
1963
{
1964
    if (GDALGetDriverByName("SAFE") != nullptr)
1,911✔
1965
        return;
282✔
1966

1967
    GDALDriver *poDriver = new GDALDriver();
1,629✔
1968

1969
    poDriver->SetDescription("SAFE");
1,629✔
1970
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1,629✔
1971
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1,629✔
1972
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Sentinel-1 SAR SAFE Product");
1,629✔
1973
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/safe.html");
1,629✔
1974

1975
    poDriver->pfnOpen = SAFEDataset::Open;
1,629✔
1976
    poDriver->pfnIdentify = SAFEDataset::Identify;
1,629✔
1977

1978
    GetGDALDriverManager()->RegisterDriver(poDriver);
1,629✔
1979
}
1980

1981
/************************************************************************/
1982
/*                  Azimuth time handling functions                     */
1983
/************************************************************************/
1984

1985
SAFECalibratedRasterBand::TimePoint
1986
SAFECalibratedRasterBand::getTimePoint(const char *pszTime)
×
1987
{
1988
    int nYear, nMonth, nDay, nHour, nMinute, nSeconds;
1989
    long nMicroSeconds;
1990
    sscanf(pszTime, "%d-%d-%dT%d:%d:%d.%ld", &nYear, &nMonth, &nDay, &nHour,
×
1991
           &nMinute, &nSeconds, &nMicroSeconds);
1992

1993
    struct tm oTm;
1994
    oTm.tm_sec = nSeconds;
×
1995
    oTm.tm_min = nMinute;
×
1996
    oTm.tm_hour = nHour;
×
1997
    oTm.tm_mday = nDay;
×
1998
    oTm.tm_mon = nMonth - 1;
×
1999
    oTm.tm_year = nYear - 1900;
×
2000
    oTm.tm_isdst = -1;
×
2001

2002
    std::time_t oTt = static_cast<std::time_t>(CPLYMDHMSToUnixTime(&oTm));
×
2003

2004
    TimePoint oTp = std::chrono::system_clock::from_time_t(oTt);
×
2005
    TimePoint oTp1 = oTp + std::chrono::microseconds(nMicroSeconds);
×
2006
    return oTp1;
×
2007
}
2008

2009
double SAFECalibratedRasterBand::getTimeDiff(TimePoint oT1, TimePoint oT2)
×
2010
{
2011
    std::chrono::duration<double> oResult = (oT2 - oT1);
×
2012
    return oResult.count();
×
2013
}
2014

2015
SAFECalibratedRasterBand::TimePoint
2016
SAFECalibratedRasterBand::getazTime(TimePoint oStart, TimePoint oStop,
×
2017
                                    long nNumOfLines, int nOffset)
2018
{
2019
    double dfTemp = getTimeDiff(oStart, oStop);
×
2020
    dfTemp /= (nNumOfLines - 1);
×
2021
    unsigned long nTimeDiffMicro = static_cast<unsigned long>(dfTemp * 1000000);
×
2022
    TimePoint oResult =
2023
        oStart + (nOffset * std::chrono::microseconds(nTimeDiffMicro));
×
2024
    return oResult;
×
2025
}
2026

2027
/************************************************************************/
2028
/*                Utility functions used in interpolation              */
2029
/************************************************************************/
2030

2031
int SAFECalibratedRasterBand::getCalibrationVectorIndex(int nLineNo)
×
2032
{
2033
    for (size_t i = 1; i < m_anLineLUT.size(); i++)
×
2034
    {
2035
        if (nLineNo < m_anLineLUT[i])
×
2036
            return static_cast<int>(i - 1);
×
2037
    }
2038
    return 0;
×
2039
}
2040

2041
int SAFECalibratedRasterBand::getPixelIndex(int nPixelNo)
×
2042
{
2043
    for (int i = 1; i < m_nNumPixels; i++)
×
2044
    {
2045
        if (nPixelNo < m_anPixelLUT[i])
×
2046
            return i - 1;
×
2047
    }
2048
    return 0;
×
2049
}
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