Coverage Report

Created: 2026-08-14 09:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/jaxapalsar/jaxapalsardataset.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  PALSAR JAXA imagery reader
4
 * Purpose:  Support for PALSAR L1.1/1.5 imagery and appropriate metadata from
5
 *           JAXA and JAXA-supported ground stations (ASF, ESA, etc.). This
6
 *           driver does not support ERSDAC products.
7
 * Author:   Philippe Vachon <philippe@cowpig.ca>
8
 *
9
 ******************************************************************************
10
 * Copyright (c) 2007, Philippe P. Vachon <philippe@cowpig.ca>
11
 * Copyright (c) 2008-2011, Even Rouault <even dot rouault at spatialys.com>
12
 *
13
 * SPDX-License-Identifier: MIT
14
 ****************************************************************************/
15
16
#include "gdal_frmts.h"
17
#include "gdal_pam.h"
18
#include "gdal_driver.h"
19
#include "gdal_drivermanager.h"
20
#include "gdal_openinfo.h"
21
#include "gdal_cpp_functions.h"
22
23
#if defined(_WIN32)
24
#define SEP_STRING "\\"
25
#else
26
0
#define SEP_STRING "/"
27
#endif
28
29
/* read binary fields */
30
#ifdef CPL_LSB
31
#define READ_WORD(f, x)                                                        \
32
0
    do                                                                         \
33
0
    {                                                                          \
34
0
        VSIFReadL(&(x), 4, 1, (f));                                            \
35
0
        (x) = CPL_SWAP32((x));                                                 \
36
0
    } while (false);
37
#define READ_SHORT(f, x)                                                       \
38
    do                                                                         \
39
    {                                                                          \
40
        VSIFReadL(&(x), 2, 1, (f));                                            \
41
        (x) = CPL_SWAP16((x));                                                 \
42
    } while (false);
43
#else
44
#define READ_WORD(f, x)                                                        \
45
    do                                                                         \
46
    {                                                                          \
47
        VSIFReadL(&(x), 4, 1, (f));                                            \
48
    } while (false);
49
#define READ_SHORT(f, x)                                                       \
50
    do                                                                         \
51
    {                                                                          \
52
        VSIFReadL(&(x), 2, 1, (f));                                            \
53
    } while (false);
54
#endif /* def CPL_LSB */
55
#define READ_BYTE(f, x)                                                        \
56
0
    do                                                                         \
57
0
    {                                                                          \
58
0
        VSIFReadL(&(x), 1, 1, (f));                                            \
59
0
    } while (false);
60
61
/* read floating point value stored as ASCII */
62
#define READ_CHAR_FLOAT(n, l, f)                                               \
63
0
    do                                                                         \
64
0
    {                                                                          \
65
0
        char psBuf[(l + 1)];                                                   \
66
0
        psBuf[(l)] = '\0';                                                     \
67
0
        VSIFReadL(&psBuf, (l), 1, (f));                                        \
68
0
        (n) = CPLAtof(psBuf);                                                  \
69
0
    } while (false);
70
71
/* read numbers stored as ASCII */
72
#define READ_CHAR_VAL(x, n, f)                                                 \
73
0
    do                                                                         \
74
0
    {                                                                          \
75
0
        char psBuf[(n + 1)];                                                   \
76
0
        psBuf[(n)] = '\0';                                                     \
77
0
        VSIFReadL(&psBuf, (n), 1, (f));                                        \
78
0
        (x) = atoi(psBuf);                                                     \
79
0
    } while (false);
80
81
/* read string fields
82
 * note: string must be size of field to be extracted + 1
83
 */
84
#define READ_STRING(s, n, f)                                                   \
85
0
    do                                                                         \
86
0
    {                                                                          \
87
0
        VSIFReadL(&(s), 1, (n), (f));                                          \
88
0
        (s)[(n)] = '\0';                                                       \
89
0
    } while (false);
90
91
/*************************************************************************/
92
/* a few key offsets in the volume directory file */
93
#define VOL_DESC_RECORD_LENGTH 360
94
#define FILE_PTR_RECORD_LENGTH 360
95
#define NUM_RECORDS_OFFSET 160
96
97
/* a few key offsets and values within the File Pointer record */
98
#define REF_FILE_CLASS_CODE_OFFSET 66
99
#define REF_FILE_CLASS_CODE_LENGTH 4
100
#define FILE_NAME_OFFSET 310
101
102
/* some image option descriptor records */
103
0
#define BITS_PER_SAMPLE_OFFSET 216
104
#define BITS_PER_SAMPLE_LENGTH 4
105
#define SAMPLES_PER_GROUP_OFFSET 220
106
#define SAMPLES_PER_GROUP_LENGTH 4
107
0
#define NUMBER_LINES_OFFSET 236
108
#define NUMBER_LINES_LENGTH 8
109
0
#define SAR_DATA_RECORD_LENGTH_OFFSET 186
110
#define SAR_DATA_RECORD_LENGTH_LENGTH 6
111
112
0
#define IMAGE_OPT_DESC_LENGTH 720
113
114
0
#define SIG_DAT_REC_OFFSET 412
115
0
#define PROC_DAT_REC_OFFSET 192
116
117
/* metadata to be extracted from the leader file */
118
0
#define LEADER_FILE_DESCRIPTOR_LENGTH 720
119
0
#define DATA_SET_SUMMARY_LENGTH 4096
120
121
/* relative to end of leader file descriptor */
122
0
#define EFFECTIVE_LOOKS_AZIMUTH_OFFSET 1174 /* floating point text */
123
#define EFFECTIVE_LOOKS_AZIMUTH_LENGTH 16
124
125
/* relative to leader file descriptor + dataset summary length */
126
0
#define PIXEL_SPACING_OFFSET 92
127
#define LINE_SPACING_OFFSET 108
128
0
#define ALPHANUMERIC_PROJECTION_NAME_OFFSET 412
129
0
#define TOP_LEFT_LAT_OFFSET 1072
130
#define TOP_LEFT_LON_OFFSET 1088
131
#define TOP_RIGHT_LAT_OFFSET 1104
132
#define TOP_RIGHT_LON_OFFSET 1120
133
#define BOTTOM_RIGHT_LAT_OFFSET 1136
134
#define BOTTOM_RIGHT_LON_OFFSET 1152
135
#define BOTTOM_LEFT_LAT_OFFSET 1168
136
#define BOTTOM_LEFT_LON_OFFSET 1184
137
138
namespace gdal::PSALSARJaxa
139
{
140
/* a few useful enums */
141
enum eFileType
142
{
143
    level_11 = 0,
144
    level_15,
145
    level_10,
146
    level_unknown = 999,
147
};
148
149
enum ePolarization
150
{
151
    hh = 0,
152
    hv,
153
    vh,
154
    vv
155
};
156
}  // namespace gdal::PSALSARJaxa
157
158
using namespace gdal::PSALSARJaxa;
159
160
/************************************************************************/
161
/* ==================================================================== */
162
/*                        PALSARJaxaDataset                             */
163
/* ==================================================================== */
164
/************************************************************************/
165
166
class PALSARJaxaRasterBand;
167
168
class PALSARJaxaDataset final : public GDALPamDataset
169
{
170
    friend class PALSARJaxaRasterBand;
171
172
  private:
173
    GDAL_GCP *pasGCPList;
174
    int nGCPCount;
175
    eFileType nFileType;
176
177
  public:
178
    PALSARJaxaDataset();
179
    ~PALSARJaxaDataset() override;
180
181
    int GetGCPCount() override;
182
    const GDAL_GCP *GetGCPs() override;
183
184
    static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
185
    static int Identify(GDALOpenInfo *poOpenInfo);
186
    static void ReadMetadata(PALSARJaxaDataset *poDS, VSILFILE *fp);
187
};
188
189
PALSARJaxaDataset::PALSARJaxaDataset()
190
0
    : pasGCPList(nullptr), nGCPCount(0), nFileType(level_unknown)
191
0
{
192
0
}
193
194
PALSARJaxaDataset::~PALSARJaxaDataset()
195
0
{
196
0
    if (nGCPCount > 0)
197
0
    {
198
0
        GDALDeinitGCPs(nGCPCount, pasGCPList);
199
0
        CPLFree(pasGCPList);
200
0
    }
201
0
}
202
203
/************************************************************************/
204
/* ==================================================================== */
205
/*                        PALSARJaxaRasterBand                          */
206
/* ==================================================================== */
207
/************************************************************************/
208
209
class PALSARJaxaRasterBand final : public GDALRasterBand
210
{
211
    VSILFILE *fp;
212
    ePolarization nPolarization;
213
    eFileType nFileType;
214
    int nBitsPerSample;
215
    int nSamplesPerGroup;
216
    int nRecordSize;
217
218
  public:
219
    PALSARJaxaRasterBand(PALSARJaxaDataset *poDS, int nBand, VSILFILE *fp);
220
    ~PALSARJaxaRasterBand() override;
221
222
    CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage) override;
223
};
224
225
/************************************************************************/
226
/*                        PALSARJaxaRasterBand()                        */
227
/************************************************************************/
228
229
PALSARJaxaRasterBand::PALSARJaxaRasterBand(PALSARJaxaDataset *poDSIn,
230
                                           int nBandIn, VSILFILE *fpIn)
231
0
    : fp(fpIn), nPolarization(hh), nBitsPerSample(0), nSamplesPerGroup(0),
232
0
      nRecordSize(0)
233
0
{
234
0
    poDS = poDSIn;
235
0
    nBand = nBandIn;
236
237
    /* Read image options record to determine the type of data */
238
0
    VSIFSeekL(fp, BITS_PER_SAMPLE_OFFSET, SEEK_SET);
239
0
    READ_CHAR_VAL(nBitsPerSample, BITS_PER_SAMPLE_LENGTH, fp);
240
0
    READ_CHAR_VAL(nSamplesPerGroup, SAMPLES_PER_GROUP_LENGTH, fp);
241
242
0
    if (nBitsPerSample == 32 && nSamplesPerGroup == 2)
243
0
    {
244
0
        eDataType = GDT_CFloat32;
245
0
        nFileType = level_11;
246
0
    }
247
0
    else if (nBitsPerSample == 8 && nSamplesPerGroup == 2)
248
0
    {
249
0
        eDataType = GDT_CInt16; /* should be 2 x signed byte */
250
0
        nFileType = level_10;
251
0
    }
252
0
    else
253
0
    {
254
0
        eDataType = GDT_UInt16;
255
0
        nFileType = level_15;
256
0
    }
257
258
0
    poDSIn->nFileType = nFileType;
259
260
    /* Read number of range/azimuth lines */
261
0
    VSIFSeekL(fp, NUMBER_LINES_OFFSET, SEEK_SET);
262
0
    READ_CHAR_VAL(nRasterYSize, NUMBER_LINES_LENGTH, fp);
263
0
    VSIFSeekL(fp, SAR_DATA_RECORD_LENGTH_OFFSET, SEEK_SET);
264
0
    READ_CHAR_VAL(nRecordSize, SAR_DATA_RECORD_LENGTH_LENGTH, fp);
265
0
    const int nDenom = ((nBitsPerSample / 8) * nSamplesPerGroup);
266
0
    if (nDenom != 0)
267
0
        nRasterXSize =
268
0
            (nRecordSize - (nFileType != level_15 ? SIG_DAT_REC_OFFSET
269
0
                                                  : PROC_DAT_REC_OFFSET)) /
270
0
            nDenom;
271
272
0
    poDSIn->nRasterXSize = nRasterXSize;
273
0
    poDSIn->nRasterYSize = nRasterYSize;
274
275
    /* Polarization */
276
0
    switch (nBand)
277
0
    {
278
0
        case 0:
279
0
            nPolarization = hh;
280
0
            SetMetadataItem("POLARIMETRIC_INTERP", "HH");
281
0
            break;
282
0
        case 1:
283
0
            nPolarization = hv;
284
0
            SetMetadataItem("POLARIMETRIC_INTERP", "HV");
285
0
            break;
286
0
        case 2:
287
0
            nPolarization = vh;
288
0
            SetMetadataItem("POLARIMETRIC_INTERP", "VH");
289
0
            break;
290
0
        case 3:
291
0
            nPolarization = vv;
292
0
            SetMetadataItem("POLARIMETRIC_INTERP", "VV");
293
0
            break;
294
            // TODO: What about the default?
295
0
    }
296
297
    /* size of block we can read */
298
0
    nBlockXSize = nRasterXSize;
299
0
    nBlockYSize = 1;
300
301
    /* set the file pointer to the first SAR data record */
302
0
    VSIFSeekL(fp, IMAGE_OPT_DESC_LENGTH, SEEK_SET);
303
0
}
304
305
/************************************************************************/
306
/*                       ~PALSARJaxaRasterBand()                        */
307
/************************************************************************/
308
309
PALSARJaxaRasterBand::~PALSARJaxaRasterBand()
310
0
{
311
0
    if (fp)
312
0
        VSIFCloseL(fp);
313
0
}
314
315
/************************************************************************/
316
/*                             IReadBlock()                             */
317
/************************************************************************/
318
319
CPLErr PALSARJaxaRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff,
320
                                        int nBlockYOff, void *pImage)
321
0
{
322
0
    int nNumBytes = 0;
323
0
    if (nFileType == level_11)
324
0
    {
325
0
        nNumBytes = 8;
326
0
    }
327
0
    else
328
0
    {
329
0
        nNumBytes = 2;
330
0
    }
331
332
0
    const vsi_l_offset nOffset =
333
0
        IMAGE_OPT_DESC_LENGTH +
334
0
        (static_cast<vsi_l_offset>(nBlockYOff - 1) * nRecordSize) +
335
0
        (nFileType == level_11 ? SIG_DAT_REC_OFFSET : PROC_DAT_REC_OFFSET);
336
337
0
    VSIFSeekL(fp, nOffset, SEEK_SET);
338
0
    VSIFReadL(pImage, nNumBytes, nRasterXSize, fp);
339
340
0
#ifdef CPL_LSB
341
0
    if (nFileType == level_11)
342
0
        GDALSwapWords(pImage, 4, nBlockXSize * 2, 4);
343
0
    else
344
0
        GDALSwapWords(pImage, 2, nBlockXSize, 2);
345
0
#endif
346
347
0
    return CE_None;
348
0
}
349
350
/************************************************************************/
351
/* ==================================================================== */
352
/*                      PALSARJaxaDataset                               */
353
/* ==================================================================== */
354
/************************************************************************/
355
356
/************************************************************************/
357
/*                            ReadMetadata()                            */
358
/************************************************************************/
359
360
int PALSARJaxaDataset::GetGCPCount()
361
0
{
362
0
    return nGCPCount;
363
0
}
364
365
/************************************************************************/
366
/*                              GetGCPs()                               */
367
/************************************************************************/
368
369
const GDAL_GCP *PALSARJaxaDataset::GetGCPs()
370
0
{
371
0
    return pasGCPList;
372
0
}
373
374
/************************************************************************/
375
/*                            ReadMetadata()                            */
376
/************************************************************************/
377
378
void PALSARJaxaDataset::ReadMetadata(PALSARJaxaDataset *poDS, VSILFILE *fp)
379
0
{
380
    /* seek to the end of the leader file descriptor */
381
0
    VSIFSeekL(fp, LEADER_FILE_DESCRIPTOR_LENGTH, SEEK_SET);
382
0
    if (poDS->nFileType == level_10)
383
0
    {
384
0
        poDS->SetMetadataItem("PRODUCT_LEVEL", "1.0");
385
0
        poDS->SetMetadataItem("AZIMUTH_LOOKS", "1.0");
386
0
    }
387
0
    else if (poDS->nFileType == level_11)
388
0
    {
389
0
        poDS->SetMetadataItem("PRODUCT_LEVEL", "1.1");
390
0
        poDS->SetMetadataItem("AZIMUTH_LOOKS", "1.0");
391
0
    }
392
0
    else
393
0
    {
394
0
        poDS->SetMetadataItem("PRODUCT_LEVEL", "1.5");
395
        /* extract equivalent number of looks */
396
0
        VSIFSeekL(
397
0
            fp, LEADER_FILE_DESCRIPTOR_LENGTH + EFFECTIVE_LOOKS_AZIMUTH_OFFSET,
398
0
            SEEK_SET);
399
0
        char szENL[17];
400
0
        double dfENL;
401
0
        READ_CHAR_FLOAT(dfENL, 16, fp);
402
0
        snprintf(szENL, sizeof(szENL), "%-16.1f", dfENL);
403
0
        poDS->SetMetadataItem("AZIMUTH_LOOKS", szENL);
404
405
        /* extract pixel spacings */
406
0
        VSIFSeekL(fp,
407
0
                  LEADER_FILE_DESCRIPTOR_LENGTH + DATA_SET_SUMMARY_LENGTH +
408
0
                      PIXEL_SPACING_OFFSET,
409
0
                  SEEK_SET);
410
0
        double dfPixelSpacing;
411
0
        double dfLineSpacing;
412
0
        char szPixelSpacing[33];
413
0
        char szLineSpacing[33];
414
0
        READ_CHAR_FLOAT(dfPixelSpacing, 16, fp);
415
0
        READ_CHAR_FLOAT(dfLineSpacing, 16, fp);
416
0
        snprintf(szPixelSpacing, sizeof(szPixelSpacing), "%-32.1f",
417
0
                 dfPixelSpacing);
418
0
        snprintf(szLineSpacing, sizeof(szLineSpacing), "%-32.1f",
419
0
                 dfLineSpacing);
420
0
        poDS->SetMetadataItem("PIXEL_SPACING", szPixelSpacing);
421
0
        poDS->SetMetadataItem("LINE_SPACING", szPixelSpacing);
422
423
        /* Alphanumeric projection name */
424
0
        VSIFSeekL(fp,
425
0
                  LEADER_FILE_DESCRIPTOR_LENGTH + DATA_SET_SUMMARY_LENGTH +
426
0
                      ALPHANUMERIC_PROJECTION_NAME_OFFSET,
427
0
                  SEEK_SET);
428
0
        char szProjName[33];
429
0
        READ_STRING(szProjName, 32, fp);
430
0
        poDS->SetMetadataItem("PROJECTION_NAME", szProjName);
431
432
        /* Extract corner GCPs */
433
0
        poDS->nGCPCount = 4;
434
0
        poDS->pasGCPList =
435
0
            (GDAL_GCP *)CPLCalloc(sizeof(GDAL_GCP), poDS->nGCPCount);
436
0
        GDALInitGCPs(poDS->nGCPCount, poDS->pasGCPList);
437
438
        /* setup the GCPs */
439
0
        int i;
440
0
        for (i = 0; i < poDS->nGCPCount; i++)
441
0
        {
442
0
            char szID[30];
443
0
            snprintf(szID, sizeof(szID), "%d", i + 1);
444
0
            CPLFree(poDS->pasGCPList[i].pszId);
445
0
            poDS->pasGCPList[i].pszId = CPLStrdup(szID);
446
0
            poDS->pasGCPList[i].dfGCPZ = 0.0;
447
0
        }
448
449
0
        double dfTemp = 0.0;
450
        /* seek to start of GCPs */
451
0
        VSIFSeekL(fp,
452
0
                  LEADER_FILE_DESCRIPTOR_LENGTH + DATA_SET_SUMMARY_LENGTH +
453
0
                      TOP_LEFT_LAT_OFFSET,
454
0
                  SEEK_SET);
455
456
        /* top-left GCP */
457
0
        READ_CHAR_FLOAT(dfTemp, 16, fp);
458
0
        poDS->pasGCPList[0].dfGCPY = dfTemp;
459
0
        READ_CHAR_FLOAT(dfTemp, 16, fp);
460
0
        poDS->pasGCPList[0].dfGCPX = dfTemp;
461
0
        poDS->pasGCPList[0].dfGCPLine = 0.5;
462
0
        poDS->pasGCPList[0].dfGCPPixel = 0.5;
463
464
        /* top right GCP */
465
0
        READ_CHAR_FLOAT(dfTemp, 16, fp);
466
0
        poDS->pasGCPList[1].dfGCPY = dfTemp;
467
0
        READ_CHAR_FLOAT(dfTemp, 16, fp);
468
0
        poDS->pasGCPList[1].dfGCPX = dfTemp;
469
0
        poDS->pasGCPList[1].dfGCPLine = 0.5;
470
0
        poDS->pasGCPList[1].dfGCPPixel = poDS->nRasterYSize - 0.5;
471
472
        /* bottom right GCP */
473
0
        READ_CHAR_FLOAT(dfTemp, 16, fp);
474
0
        poDS->pasGCPList[2].dfGCPY = dfTemp;
475
0
        READ_CHAR_FLOAT(dfTemp, 16, fp);
476
0
        poDS->pasGCPList[2].dfGCPX = dfTemp;
477
0
        poDS->pasGCPList[2].dfGCPLine = poDS->nRasterYSize - 0.5;
478
0
        poDS->pasGCPList[2].dfGCPPixel = poDS->nRasterYSize - 0.5;
479
480
        /* bottom left GCP */
481
0
        READ_CHAR_FLOAT(dfTemp, 16, fp);
482
0
        poDS->pasGCPList[3].dfGCPY = dfTemp;
483
0
        READ_CHAR_FLOAT(dfTemp, 16, fp);
484
0
        poDS->pasGCPList[3].dfGCPX = dfTemp;
485
0
        poDS->pasGCPList[3].dfGCPLine = poDS->nRasterYSize - 0.5;
486
0
        poDS->pasGCPList[3].dfGCPPixel = 0.5;
487
0
    }
488
489
    /* some generic metadata items */
490
0
    poDS->SetMetadataItem("SENSOR_BAND", "L"); /* PALSAR is L-band */
491
0
    poDS->SetMetadataItem("RANGE_LOOKS", "1.0");
492
493
    /* Check if this is a PolSAR dataset */
494
0
    if (poDS->GetRasterCount() == 4)
495
0
    {
496
        /* PALSAR data is only available from JAXA in Scattering Matrix form */
497
0
        poDS->SetMetadataItem("MATRIX_REPRESENTATION", "SCATTERING");
498
0
    }
499
0
}
500
501
/************************************************************************/
502
/*                              Identify()                              */
503
/************************************************************************/
504
505
static void ReadWord(VSILFILE *fp, int *pVal)
506
0
{
507
0
    READ_WORD(fp, *pVal);
508
0
}
509
510
static void ReadByte(VSILFILE *fp, int *pVal)
511
0
{
512
0
    READ_BYTE(fp, *pVal);
513
0
}
514
515
int PALSARJaxaDataset::Identify(GDALOpenInfo *poOpenInfo)
516
579k
{
517
579k
    if (poOpenInfo->nHeaderBytes < 360 || poOpenInfo->fpL == nullptr)
518
478k
        return 0;
519
520
    /* First, check that this is a PALSAR image indeed */
521
100k
    if (!STARTS_WITH_CI((char *)(poOpenInfo->pabyHeader + 60), "AL"))
522
100k
    {
523
100k
        return 0;
524
100k
    }
525
97
    const std::string osBasename = CPLGetBasenameSafe(poOpenInfo->pszFilename);
526
97
    if (osBasename.size() < 9 ||
527
56
        !STARTS_WITH_CI(osBasename.c_str() + 4, "ALPSR"))
528
97
    {
529
97
        return 0;
530
97
    }
531
532
    /* Check that this is a volume directory file */
533
0
    int nRecordSeq = 0;
534
0
    int nRecordSubtype = 0;
535
0
    int nRecordType = 0;
536
0
    int nSecondSubtype = 0;
537
0
    int nThirdSubtype = 0;
538
0
    int nLengthRecord = 0;
539
540
0
    VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET);
541
542
0
    ReadWord(poOpenInfo->fpL, &nRecordSeq);
543
0
    ReadByte(poOpenInfo->fpL, &nRecordSubtype);
544
0
    ReadByte(poOpenInfo->fpL, &nRecordType);
545
0
    ReadByte(poOpenInfo->fpL, &nSecondSubtype);
546
0
    ReadByte(poOpenInfo->fpL, &nThirdSubtype);
547
0
    ReadWord(poOpenInfo->fpL, &nLengthRecord);
548
549
0
    VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET);
550
551
    /* Check that we have the right record */
552
0
    if (nRecordSeq == 1 && nRecordSubtype == 192 && nRecordType == 192 &&
553
0
        nSecondSubtype == 18 && nThirdSubtype == 18 && nLengthRecord == 360)
554
0
    {
555
0
        return 1;
556
0
    }
557
558
0
    return 0;
559
0
}
560
561
/************************************************************************/
562
/*                                Open()                                */
563
/************************************************************************/
564
GDALDataset *PALSARJaxaDataset::Open(GDALOpenInfo *poOpenInfo)
565
0
{
566
    /* Check that this actually is a JAXA PALSAR product */
567
0
    if (!PALSARJaxaDataset::Identify(poOpenInfo))
568
0
        return nullptr;
569
570
    /* -------------------------------------------------------------------- */
571
    /*      Confirm the requested access is supported.                      */
572
    /* -------------------------------------------------------------------- */
573
0
    if (poOpenInfo->eAccess == GA_Update)
574
0
    {
575
0
        ReportUpdateNotSupportedByDriver("JAXAPALSAR");
576
0
        return nullptr;
577
0
    }
578
579
0
    PALSARJaxaDataset *poDS = new PALSARJaxaDataset();
580
581
    /* Get the suffix of the filename, we'll need this */
582
0
    char *pszSuffix =
583
0
        VSIStrdup((char *)(CPLGetFilename(poOpenInfo->pszFilename) + 3));
584
585
    /* Try to read each of the polarizations */
586
0
    const size_t nImgFileLen =
587
0
        CPLGetDirnameSafe(poOpenInfo->pszFilename).size() + strlen(pszSuffix) +
588
0
        8;
589
0
    char *pszImgFile = (char *)CPLMalloc(nImgFileLen);
590
591
0
    int nBandNum = 1;
592
593
    /* HH */
594
0
    snprintf(pszImgFile, nImgFileLen, "%s%sIMG-HH%s",
595
0
             CPLGetDirnameSafe(poOpenInfo->pszFilename).c_str(), SEP_STRING,
596
0
             pszSuffix);
597
0
    VSILFILE *fpHH = VSIFOpenL(pszImgFile, "rb");
598
0
    if (fpHH != nullptr)
599
0
    {
600
0
        poDS->SetBand(nBandNum, new PALSARJaxaRasterBand(poDS, 0, fpHH));
601
0
        nBandNum++;
602
0
    }
603
604
    /* HV */
605
0
    snprintf(pszImgFile, nImgFileLen, "%s%sIMG-HV%s",
606
0
             CPLGetDirnameSafe(poOpenInfo->pszFilename).c_str(), SEP_STRING,
607
0
             pszSuffix);
608
0
    VSILFILE *fpHV = VSIFOpenL(pszImgFile, "rb");
609
0
    if (fpHV != nullptr)
610
0
    {
611
0
        poDS->SetBand(nBandNum, new PALSARJaxaRasterBand(poDS, 1, fpHV));
612
0
        nBandNum++;
613
0
    }
614
615
    /* VH */
616
0
    snprintf(pszImgFile, nImgFileLen, "%s%sIMG-VH%s",
617
0
             CPLGetDirnameSafe(poOpenInfo->pszFilename).c_str(), SEP_STRING,
618
0
             pszSuffix);
619
0
    VSILFILE *fpVH = VSIFOpenL(pszImgFile, "rb");
620
0
    if (fpVH != nullptr)
621
0
    {
622
0
        poDS->SetBand(nBandNum, new PALSARJaxaRasterBand(poDS, 2, fpVH));
623
0
        nBandNum++;
624
0
    }
625
626
    /* VV */
627
0
    snprintf(pszImgFile, nImgFileLen, "%s%sIMG-VV%s",
628
0
             CPLGetDirnameSafe(poOpenInfo->pszFilename).c_str(), SEP_STRING,
629
0
             pszSuffix);
630
0
    VSILFILE *fpVV = VSIFOpenL(pszImgFile, "rb");
631
0
    if (fpVV != nullptr)
632
0
    {
633
0
        poDS->SetBand(nBandNum, new PALSARJaxaRasterBand(poDS, 3, fpVV));
634
        /* nBandNum++; */
635
0
    }
636
637
0
    VSIFree(pszImgFile);
638
639
    /* did we get at least one band? */
640
0
    if (fpVV == nullptr && fpVH == nullptr && fpHV == nullptr &&
641
0
        fpHH == nullptr)
642
0
    {
643
0
        CPLError(
644
0
            CE_Failure, CPLE_AppDefined,
645
0
            "Unable to find any image data. Aborting opening as PALSAR image.");
646
0
        delete poDS;
647
0
        VSIFree(pszSuffix);
648
0
        return nullptr;
649
0
    }
650
651
    /* Level 1.0 products are not supported */
652
0
    if (poDS->nFileType == level_10)
653
0
    {
654
0
        CPLError(CE_Failure, CPLE_AppDefined,
655
0
                 "ALOS PALSAR Level 1.0 products are not supported. Aborting "
656
0
                 "opening as PALSAR image.");
657
0
        delete poDS;
658
0
        VSIFree(pszSuffix);
659
0
        return nullptr;
660
0
    }
661
662
    /* read metadata from Leader file. */
663
0
    const size_t nLeaderFilenameLen =
664
0
        strlen(CPLGetDirnameSafe(poOpenInfo->pszFilename).c_str()) +
665
0
        strlen(pszSuffix) + 5;
666
0
    char *pszLeaderFilename = (char *)CPLMalloc(nLeaderFilenameLen);
667
0
    snprintf(pszLeaderFilename, nLeaderFilenameLen, "%s%sLED%s",
668
0
             CPLGetDirnameSafe(poOpenInfo->pszFilename).c_str(), SEP_STRING,
669
0
             pszSuffix);
670
671
0
    VSILFILE *fpLeader = VSIFOpenL(pszLeaderFilename, "rb");
672
    /* check if the leader is actually present */
673
0
    if (fpLeader != nullptr)
674
0
    {
675
0
        ReadMetadata(poDS, fpLeader);
676
0
        VSIFCloseL(fpLeader);
677
0
    }
678
679
0
    VSIFree(pszLeaderFilename);
680
681
0
    VSIFree(pszSuffix);
682
683
    /* -------------------------------------------------------------------- */
684
    /*      Initialize any PAM information.                                 */
685
    /* -------------------------------------------------------------------- */
686
0
    poDS->SetDescription(poOpenInfo->pszFilename);
687
0
    poDS->TryLoadXML();
688
689
    /* -------------------------------------------------------------------- */
690
    /*      Check for overviews.                                            */
691
    /* -------------------------------------------------------------------- */
692
0
    poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
693
694
0
    return poDS;
695
0
}
696
697
/************************************************************************/
698
/*                      GDALRegister_PALSARJaxa()                       */
699
/************************************************************************/
700
701
void GDALRegister_PALSARJaxa()
702
703
22
{
704
22
    if (GDALGetDriverByName("JAXAPALSAR") != nullptr)
705
0
        return;
706
707
22
    GDALDriver *poDriver = new GDALDriver();
708
709
22
    poDriver->SetDescription("JAXAPALSAR");
710
22
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
711
22
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
712
22
                              "JAXA PALSAR Product Reader (Level 1.1/1.5)");
713
22
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/palsar.html");
714
715
22
    poDriver->pfnOpen = PALSARJaxaDataset::Open;
716
22
    poDriver->pfnIdentify = PALSARJaxaDataset::Identify;
717
22
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
718
719
22
    GetGDALDriverManager()->RegisterDriver(poDriver);
720
22
}