Coverage Report

Created: 2025-06-09 07:43

/src/gdal/frmts/ceos2/sar_ceosdataset.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  ASI CEOS Translator
4
 * Purpose:  GDALDataset driver for CEOS translator.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2000, Atlantis Scientific Inc.
9
 * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "ceos.h"
15
#include "cpl_string.h"
16
#include "gdal_frmts.h"
17
#include "gdal_priv.h"
18
#include "rawdataset.h"
19
#include "ogr_srs_api.h"
20
21
#include <algorithm>
22
23
static GInt16 CastToGInt16(float val)
24
0
{
25
0
    if (val < -32768.0)
26
0
        val = -32768.0;
27
28
0
    if (val > 32767)
29
0
        val = 32767.0;
30
31
0
    return static_cast<GInt16>(val);
32
0
}
33
34
static const char *const CeosExtension[][6] = {
35
    {"vol", "led", "img", "trl", "nul", "ext"},
36
    {"vol", "lea", "img", "trl", "nul", "ext"},
37
    {"vol", "led", "img", "tra", "nul", "ext"},
38
    {"vol", "lea", "img", "tra", "nul", "ext"},
39
    {"vdf", "slf", "sdf", "stf", "nvd", "ext"},
40
41
    {"vdf", "ldr", "img", "tra", "nul", "ext2"},
42
43
    /* Jers from Japan- not sure if this is generalized as much as it could be
44
     */
45
    {"VOLD", "Sarl_01", "Imop_%02d", "Sart_01", "NULL", "base"},
46
47
    /* Radarsat: basename, not extension */
48
    {"vdf_dat", "lea_%02d", "dat_%02d", "tra_%02d", "nul_vdf", "base"},
49
50
    /* Ers-1: basename, not extension */
51
    {"vdf_dat", "lea_%02d", "dat_%02d", "tra_%02d", "nul_dat", "base"},
52
53
    /* Ers-2 from Telaviv */
54
    {"volume", "leader", "image", "trailer", "nul_dat", "whole"},
55
56
    /* Ers-1 from D-PAF */
57
    {"VDF", "LF", "SLC", "", "", "ext"},
58
59
    /* Radarsat-1 per #2051 */
60
    {"vol", "sarl", "sard", "sart", "nvol", "ext"},
61
62
    /* Radarsat-1 ASF */
63
    {"", "L", "D", "", "", "ext"},
64
65
    /* end marker */
66
    {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}};
67
68
static int ProcessData(VSILFILE *fp, int fileid, CeosSARVolume_t *sar,
69
                       int max_records, vsi_l_offset max_bytes);
70
71
static CeosTypeCode_t QuadToTC(int a, int b, int c, int d)
72
170
{
73
170
    CeosTypeCode_t abcd;
74
75
170
    abcd.UCharCode.Subtype1 = (unsigned char)a;
76
170
    abcd.UCharCode.Type = (unsigned char)b;
77
170
    abcd.UCharCode.Subtype2 = (unsigned char)c;
78
170
    abcd.UCharCode.Subtype3 = (unsigned char)d;
79
80
170
    return abcd;
81
170
}
82
83
20
#define LEADER_DATASET_SUMMARY_TC QuadToTC(18, 10, 18, 20)
84
10
#define LEADER_DATASET_SUMMARY_ERS2_TC QuadToTC(10, 10, 31, 20)
85
10
#define LEADER_RADIOMETRIC_COMPENSATION_TC QuadToTC(18, 51, 18, 20)
86
10
#define VOLUME_DESCRIPTOR_RECORD_TC QuadToTC(192, 192, 18, 18)
87
10
#define IMAGE_HEADER_RECORD_TC QuadToTC(63, 192, 18, 18)
88
20
#define LEADER_RADIOMETRIC_DATA_RECORD_TC QuadToTC(18, 50, 18, 20)
89
5
#define LEADER_MAP_PROJ_RECORD_TC QuadToTC(10, 20, 31, 20)
90
91
// TODO: recond?
92
/* JERS from Japan has MAP_PROJ recond with different identifiers */
93
/* see CEOS-SAR-CCT Iss/Rev: 2/0 February 10, 1989 */
94
5
#define LEADER_MAP_PROJ_RECORD_JERS_TC QuadToTC(18, 20, 18, 20)
95
96
/* Leader from ASF has different identifiers */
97
5
#define LEADER_MAP_PROJ_RECORD_ASF_TC QuadToTC(10, 20, 18, 20)
98
10
#define LEADER_DATASET_SUMMARY_ASF_TC QuadToTC(10, 10, 18, 20)
99
5
#define LEADER_FACILITY_ASF_TC QuadToTC(90, 210, 18, 61)
100
101
/* For ERS calibration and incidence angle information */
102
10
#define ERS_GENERAL_FACILITY_DATA_TC QuadToTC(10, 200, 31, 50)
103
10
#define ERS_GENERAL_FACILITY_DATA_ALT_TC QuadToTC(10, 216, 31, 50)
104
105
20
#define RSAT_PROC_PARAM_TC QuadToTC(18, 120, 18, 20)
106
107
/************************************************************************/
108
/* ==================================================================== */
109
/*                              SAR_CEOSDataset                         */
110
/* ==================================================================== */
111
/************************************************************************/
112
113
class SAR_CEOSRasterBand;
114
class CCPRasterBand;
115
class PALSARRasterBand;
116
117
class SAR_CEOSDataset final : public GDALPamDataset
118
{
119
    friend class SAR_CEOSRasterBand;
120
    friend class CCPRasterBand;
121
    friend class PALSARRasterBand;
122
123
    CeosSARVolume_t sVolume;
124
125
    VSILFILE *fpImage;
126
127
    char **papszTempMD;
128
129
    OGRSpatialReference m_oSRS{};
130
    int nGCPCount;
131
    GDAL_GCP *pasGCPList;
132
133
    void ScanForGCPs();
134
    void ScanForMetadata();
135
    int ScanForMapProjection();
136
    char **papszExtraFiles;
137
138
  public:
139
    SAR_CEOSDataset();
140
    ~SAR_CEOSDataset() override;
141
142
    int GetGCPCount() override;
143
    const OGRSpatialReference *GetGCPSpatialRef() const override;
144
    const GDAL_GCP *GetGCPs() override;
145
146
    char **GetMetadataDomainList() override;
147
    char **GetMetadata(const char *pszDomain) override;
148
149
    static GDALDataset *Open(GDALOpenInfo *);
150
    virtual char **GetFileList(void) override;
151
};
152
153
/************************************************************************/
154
/* ==================================================================== */
155
/*                          CCPRasterBand                               */
156
/* ==================================================================== */
157
/************************************************************************/
158
159
class CCPRasterBand final : public GDALPamRasterBand
160
{
161
    friend class SAR_CEOSDataset;
162
163
  public:
164
    CCPRasterBand(SAR_CEOSDataset *, int, GDALDataType);
165
166
    CPLErr IReadBlock(int, int, void *) override;
167
};
168
169
/************************************************************************/
170
/* ==================================================================== */
171
/*                        PALSARRasterBand                              */
172
/* ==================================================================== */
173
/************************************************************************/
174
175
class PALSARRasterBand final : public GDALPamRasterBand
176
{
177
    friend class SAR_CEOSDataset;
178
179
  public:
180
    PALSARRasterBand(SAR_CEOSDataset *, int);
181
182
    CPLErr IReadBlock(int, int, void *) override;
183
};
184
185
/************************************************************************/
186
/* ==================================================================== */
187
/*                       SAR_CEOSRasterBand                             */
188
/* ==================================================================== */
189
/************************************************************************/
190
191
class SAR_CEOSRasterBand final : public GDALPamRasterBand
192
{
193
    friend class SAR_CEOSDataset;
194
195
  public:
196
    SAR_CEOSRasterBand(SAR_CEOSDataset *, int, GDALDataType);
197
198
    CPLErr IReadBlock(int, int, void *) override;
199
};
200
201
/************************************************************************/
202
/*                         SAR_CEOSRasterBand()                         */
203
/************************************************************************/
204
205
SAR_CEOSRasterBand::SAR_CEOSRasterBand(SAR_CEOSDataset *poGDSIn, int nBandIn,
206
                                       GDALDataType eType)
207
208
0
{
209
0
    poDS = poGDSIn;
210
0
    nBand = nBandIn;
211
212
0
    eDataType = eType;
213
214
0
    nBlockXSize = poGDSIn->nRasterXSize;
215
0
    nBlockYSize = 1;
216
0
}
217
218
/************************************************************************/
219
/*                             IReadBlock()                             */
220
/************************************************************************/
221
222
CPLErr SAR_CEOSRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff,
223
                                      void *pImage)
224
0
{
225
0
    SAR_CEOSDataset *poGDS = cpl::down_cast<SAR_CEOSDataset *>(poDS);
226
227
0
    struct CeosSARImageDesc *ImageDesc = &(poGDS->sVolume.ImageDesc);
228
229
0
    int offset;
230
0
    CalcCeosSARImageFilePosition(&(poGDS->sVolume), nBand, nBlockYOff + 1,
231
0
                                 nullptr, &offset);
232
233
0
    offset += ImageDesc->ImageDataStart;
234
235
    /* -------------------------------------------------------------------- */
236
    /*      Load all the pixel data associated with this scanline.          */
237
    /*      Ensure we handle multiple record scanlines properly.            */
238
    /* -------------------------------------------------------------------- */
239
0
    int nPixelsRead = 0;
240
241
0
    GByte *pabyRecord =
242
0
        (GByte *)VSI_MALLOC2_VERBOSE(ImageDesc->BytesPerPixel, nBlockXSize);
243
0
    if (!pabyRecord)
244
0
        return CE_Failure;
245
246
0
    for (int iRecord = 0; iRecord < ImageDesc->RecordsPerLine; iRecord++)
247
0
    {
248
0
        int nPixelsToRead;
249
250
0
        if (nPixelsRead + ImageDesc->PixelsPerRecord > nBlockXSize)
251
0
            nPixelsToRead = nBlockXSize - nPixelsRead;
252
0
        else
253
0
            nPixelsToRead = ImageDesc->PixelsPerRecord;
254
255
0
        CPL_IGNORE_RET_VAL(VSIFSeekL(poGDS->fpImage, offset, SEEK_SET));
256
0
        CPL_IGNORE_RET_VAL(VSIFReadL(
257
0
            pabyRecord +
258
0
                static_cast<size_t>(nPixelsRead) * ImageDesc->BytesPerPixel,
259
0
            1, static_cast<size_t>(nPixelsToRead) * ImageDesc->BytesPerPixel,
260
0
            poGDS->fpImage));
261
262
0
        nPixelsRead += nPixelsToRead;
263
0
        offset += ImageDesc->BytesPerRecord;
264
0
    }
265
266
    /* -------------------------------------------------------------------- */
267
    /*      Copy the desired band out based on the size of the type, and    */
268
    /*      the interleaving mode.                                          */
269
    /* -------------------------------------------------------------------- */
270
0
    const int nBytesPerSample = GDALGetDataTypeSizeBytes(eDataType);
271
272
0
    if (ImageDesc->ChannelInterleaving == CEOS_IL_PIXEL)
273
0
    {
274
0
        GDALCopyWords(pabyRecord + (nBand - 1) * nBytesPerSample, eDataType,
275
0
                      ImageDesc->BytesPerPixel, pImage, eDataType,
276
0
                      nBytesPerSample, nBlockXSize);
277
0
    }
278
0
    else if (ImageDesc->ChannelInterleaving == CEOS_IL_LINE)
279
0
    {
280
0
        GDALCopyWords(pabyRecord + (nBand - 1) * nBytesPerSample * nBlockXSize,
281
0
                      eDataType, nBytesPerSample, pImage, eDataType,
282
0
                      nBytesPerSample, nBlockXSize);
283
0
    }
284
0
    else if (ImageDesc->ChannelInterleaving == CEOS_IL_BAND)
285
0
    {
286
0
        memcpy(pImage, pabyRecord,
287
0
               static_cast<size_t>(nBytesPerSample) * nBlockXSize);
288
0
    }
289
290
0
#ifdef CPL_LSB
291
0
    GDALSwapWords(pImage, nBytesPerSample, nBlockXSize, nBytesPerSample);
292
0
#endif
293
294
0
    CPLFree(pabyRecord);
295
296
0
    return CE_None;
297
0
}
298
299
/************************************************************************/
300
/* ==================================================================== */
301
/*                              CCPRasterBand                           */
302
/* ==================================================================== */
303
/************************************************************************/
304
305
/************************************************************************/
306
/*                           CCPRasterBand()                            */
307
/************************************************************************/
308
309
CCPRasterBand::CCPRasterBand(SAR_CEOSDataset *poGDSIn, int nBandIn,
310
                             GDALDataType eType)
311
312
0
{
313
0
    poDS = poGDSIn;
314
0
    nBand = nBandIn;
315
316
0
    eDataType = eType;
317
318
0
    nBlockXSize = poGDSIn->nRasterXSize;
319
0
    nBlockYSize = 1;
320
321
0
    if (nBand == 1)
322
0
        SetMetadataItem("POLARIMETRIC_INTERP", "HH");
323
0
    else if (nBand == 2)
324
0
        SetMetadataItem("POLARIMETRIC_INTERP", "HV");
325
0
    else if (nBand == 3)
326
0
        SetMetadataItem("POLARIMETRIC_INTERP", "VH");
327
0
    else if (nBand == 4)
328
0
        SetMetadataItem("POLARIMETRIC_INTERP", "VV");
329
0
}
330
331
/************************************************************************/
332
/*                             IReadBlock()                             */
333
/************************************************************************/
334
335
/* From: http://southport.jpl.nasa.gov/software/dcomp/dcomp.html
336
337
ysca = sqrt{ [ (Byte(2) / 254 ) + 1.5] 2Byte(1) }
338
339
Re(SHH) = byte(3) ysca/127
340
341
Im(SHH) = byte(4) ysca/127
342
343
Re(SHV) = byte(5) ysca/127
344
345
Im(SHV) = byte(6) ysca/127
346
347
Re(SVH) = byte(7) ysca/127
348
349
Im(SVH) = byte(8) ysca/127
350
351
Re(SVV) = byte(9) ysca/127
352
353
Im(SVV) = byte(10) ysca/127
354
355
*/
356
357
CPLErr CCPRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
358
                                 void *pImage)
359
0
{
360
0
    SAR_CEOSDataset *poGDS = cpl::down_cast<SAR_CEOSDataset *>(poDS);
361
362
0
    struct CeosSARImageDesc *ImageDesc = &(poGDS->sVolume.ImageDesc);
363
364
0
    int offset = ImageDesc->FileDescriptorLength +
365
0
                 ImageDesc->BytesPerRecord * nBlockYOff +
366
0
                 ImageDesc->ImageDataStart;
367
368
    /* -------------------------------------------------------------------- */
369
    /*      Load all the pixel data associated with this scanline.          */
370
    /* -------------------------------------------------------------------- */
371
0
    const int nBytesToRead = ImageDesc->BytesPerPixel * nBlockXSize;
372
373
0
    GByte *pabyRecord = (GByte *)CPLMalloc(nBytesToRead);
374
375
0
    if (VSIFSeekL(poGDS->fpImage, offset, SEEK_SET) != 0 ||
376
0
        (int)VSIFReadL(pabyRecord, 1, nBytesToRead, poGDS->fpImage) !=
377
0
            nBytesToRead)
378
0
    {
379
0
        CPLError(CE_Failure, CPLE_FileIO,
380
0
                 "Error reading %d bytes of CEOS record data at offset %d.\n"
381
0
                 "Reading file %s failed.",
382
0
                 nBytesToRead, offset, poGDS->GetDescription());
383
0
        CPLFree(pabyRecord);
384
0
        return CE_Failure;
385
0
    }
386
387
    /* -------------------------------------------------------------------- */
388
    /*      Initialize our power table if this is our first time through.   */
389
    /* -------------------------------------------------------------------- */
390
0
    static float afPowTable[256];
391
0
    static bool bPowTableInitialized = false;
392
393
0
    if (!bPowTableInitialized)
394
0
    {
395
0
        bPowTableInitialized = true;
396
397
0
        for (int i = 0; i < 256; i++)
398
0
        {
399
0
            afPowTable[i] = (float)pow(2.0, i - 128);
400
0
        }
401
0
    }
402
403
    /* -------------------------------------------------------------------- */
404
    /*      Copy the desired band out based on the size of the type, and    */
405
    /*      the interleaving mode.                                          */
406
    /* -------------------------------------------------------------------- */
407
0
    for (int iX = 0; iX < nBlockXSize; iX++)
408
0
    {
409
0
        unsigned char *pabyGroup = pabyRecord + iX * ImageDesc->BytesPerPixel;
410
0
        signed char *Byte =
411
0
            (signed char *)pabyGroup - 1; /* A ones based alias */
412
0
        double dfReSHH, dfImSHH, dfReSHV, dfImSHV, dfReSVH, dfImSVH, dfReSVV,
413
0
            dfImSVV;
414
415
0
        const double dfScale =
416
0
            sqrt((Byte[2] / 254.0 + 1.5) * afPowTable[Byte[1] + 128]);
417
418
0
        if (nBand == 1)
419
0
        {
420
0
            dfReSHH = Byte[3] * dfScale / 127.0;
421
0
            dfImSHH = Byte[4] * dfScale / 127.0;
422
423
0
            ((float *)pImage)[iX * 2] = (float)dfReSHH;
424
0
            ((float *)pImage)[iX * 2 + 1] = (float)dfImSHH;
425
0
        }
426
0
        else if (nBand == 2)
427
0
        {
428
0
            dfReSHV = Byte[5] * dfScale / 127.0;
429
0
            dfImSHV = Byte[6] * dfScale / 127.0;
430
431
0
            ((float *)pImage)[iX * 2] = (float)dfReSHV;
432
0
            ((float *)pImage)[iX * 2 + 1] = (float)dfImSHV;
433
0
        }
434
0
        else if (nBand == 3)
435
0
        {
436
0
            dfReSVH = Byte[7] * dfScale / 127.0;
437
0
            dfImSVH = Byte[8] * dfScale / 127.0;
438
439
0
            ((float *)pImage)[iX * 2] = (float)dfReSVH;
440
0
            ((float *)pImage)[iX * 2 + 1] = (float)dfImSVH;
441
0
        }
442
0
        else if (nBand == 4)
443
0
        {
444
0
            dfReSVV = Byte[9] * dfScale / 127.0;
445
0
            dfImSVV = Byte[10] * dfScale / 127.0;
446
447
0
            ((float *)pImage)[iX * 2] = (float)dfReSVV;
448
0
            ((float *)pImage)[iX * 2 + 1] = (float)dfImSVV;
449
0
        }
450
0
    }
451
452
0
    CPLFree(pabyRecord);
453
454
0
    return CE_None;
455
0
}
456
457
/************************************************************************/
458
/* ==================================================================== */
459
/*                            PALSARRasterBand                          */
460
/* ==================================================================== */
461
/************************************************************************/
462
463
/************************************************************************/
464
/*                           PALSARRasterBand()                         */
465
/************************************************************************/
466
467
PALSARRasterBand::PALSARRasterBand(SAR_CEOSDataset *poGDSIn, int nBandIn)
468
469
0
{
470
0
    poDS = poGDSIn;
471
0
    nBand = nBandIn;
472
473
0
    eDataType = GDT_CInt16;
474
475
0
    nBlockXSize = poGDSIn->nRasterXSize;
476
0
    nBlockYSize = 1;
477
478
0
    if (nBand == 1)
479
0
        SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_11");
480
0
    else if (nBand == 2)
481
0
        SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_22");
482
0
    else if (nBand == 3)
483
0
        SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_33");
484
0
    else if (nBand == 4)
485
0
        SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_12");
486
0
    else if (nBand == 5)
487
0
        SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_13");
488
0
    else if (nBand == 6)
489
0
        SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_23");
490
0
}
491
492
/************************************************************************/
493
/*                             IReadBlock()                             */
494
/*                                                                      */
495
/*      Based on ERSDAC-VX-CEOS-004                                     */
496
/************************************************************************/
497
498
CPLErr PALSARRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff,
499
                                    void *pImage)
500
0
{
501
0
    SAR_CEOSDataset *poGDS = cpl::down_cast<SAR_CEOSDataset *>(poDS);
502
503
0
    struct CeosSARImageDesc *ImageDesc = &(poGDS->sVolume.ImageDesc);
504
505
0
    int offset = ImageDesc->FileDescriptorLength +
506
0
                 ImageDesc->BytesPerRecord * nBlockYOff +
507
0
                 ImageDesc->ImageDataStart;
508
509
    /* -------------------------------------------------------------------- */
510
    /*      Load all the pixel data associated with this scanline.          */
511
    /* -------------------------------------------------------------------- */
512
0
    const int nBytesToRead = ImageDesc->BytesPerPixel * nBlockXSize;
513
514
0
    GByte *pabyRecord = (GByte *)CPLMalloc(nBytesToRead);
515
516
0
    if (VSIFSeekL(poGDS->fpImage, offset, SEEK_SET) != 0 ||
517
0
        (int)VSIFReadL(pabyRecord, 1, nBytesToRead, poGDS->fpImage) !=
518
0
            nBytesToRead)
519
0
    {
520
0
        CPLError(CE_Failure, CPLE_FileIO,
521
0
                 "Error reading %d bytes of CEOS record data at offset %d.\n"
522
0
                 "Reading file %s failed.",
523
0
                 nBytesToRead, offset, poGDS->GetDescription());
524
0
        CPLFree(pabyRecord);
525
0
        return CE_Failure;
526
0
    }
527
528
    /* -------------------------------------------------------------------- */
529
    /*      Copy the desired band out based on the size of the type, and    */
530
    /*      the interleaving mode.                                          */
531
    /* -------------------------------------------------------------------- */
532
0
    if (nBand == 1 || nBand == 2 || nBand == 3)
533
0
    {
534
        // we need to pre-initialize things to set the imaginary component to 0
535
0
        memset(pImage, 0, nBlockXSize * 4);
536
537
0
        GDALCopyWords(pabyRecord + 4 * (nBand - 1), GDT_Int16, 18, pImage,
538
0
                      GDT_Int16, 4, nBlockXSize);
539
0
#ifdef CPL_LSB
540
0
        GDALSwapWords(pImage, 2, nBlockXSize, 4);
541
0
#endif
542
0
    }
543
0
    else
544
0
    {
545
0
        GDALCopyWords(pabyRecord + 6 + 4 * (nBand - 4), GDT_CInt16, 18, pImage,
546
0
                      GDT_CInt16, 4, nBlockXSize);
547
0
#ifdef CPL_LSB
548
0
        GDALSwapWords(pImage, 2, nBlockXSize * 2, 2);
549
0
#endif
550
0
    }
551
0
    CPLFree(pabyRecord);
552
553
    /* -------------------------------------------------------------------- */
554
    /*      Convert the values into covariance form as per:                 */
555
    /* -------------------------------------------------------------------- */
556
    /*
557
    ** 1) PALSAR- adjust so that it reads bands as a covariance matrix, and
558
    ** set polarimetric interpretation accordingly:
559
    **
560
    ** Covariance_11=HH*conj(HH): already there
561
    ** Covariance_22=2*HV*conj(HV): need a factor of 2
562
    ** Covariance_33=VV*conj(VV): already there
563
    ** Covariance_12=sqrt(2)*HH*conj(HV): need the sqrt(2) factor
564
    ** Covariance_13=HH*conj(VV): already there
565
    ** Covariance_23=sqrt(2)*HV*conj(VV): need to take the conjugate, then
566
    **               multiply by sqrt(2)
567
    **
568
    */
569
570
0
    if (nBand == 2)
571
0
    {
572
0
        GInt16 *panLine = (GInt16 *)pImage;
573
574
0
        for (int i = 0; i < nBlockXSize * 2; i++)
575
0
        {
576
0
            panLine[i] = (GInt16)CastToGInt16((float)2.0 * panLine[i]);
577
0
        }
578
0
    }
579
0
    else if (nBand == 4)
580
0
    {
581
0
        const double sqrt_2 = pow(2.0, 0.5);
582
0
        GInt16 *panLine = (GInt16 *)pImage;
583
584
0
        for (int i = 0; i < nBlockXSize * 2; i++)
585
0
        {
586
0
            panLine[i] =
587
0
                (GInt16)CastToGInt16((float)floor(panLine[i] * sqrt_2 + 0.5));
588
0
        }
589
0
    }
590
0
    else if (nBand == 6)
591
0
    {
592
0
        GInt16 *panLine = (GInt16 *)pImage;
593
0
        const double sqrt_2 = pow(2.0, 0.5);
594
595
        // real portion - just multiple by sqrt(2)
596
0
        for (int i = 0; i < nBlockXSize * 2; i += 2)
597
0
        {
598
0
            panLine[i] =
599
0
                (GInt16)CastToGInt16((float)floor(panLine[i] * sqrt_2 + 0.5));
600
0
        }
601
602
        // imaginary portion - conjugate and multiply
603
0
        for (int i = 1; i < nBlockXSize * 2; i += 2)
604
0
        {
605
0
            panLine[i] =
606
0
                (GInt16)CastToGInt16((float)floor(-panLine[i] * sqrt_2 + 0.5));
607
0
        }
608
0
    }
609
610
0
    return CE_None;
611
0
}
612
613
/************************************************************************/
614
/* ==================================================================== */
615
/*                              SAR_CEOSDataset                         */
616
/* ==================================================================== */
617
/************************************************************************/
618
619
/************************************************************************/
620
/*                          SAR_CEOSDataset()                           */
621
/************************************************************************/
622
623
SAR_CEOSDataset::SAR_CEOSDataset()
624
27
    : fpImage(nullptr), papszTempMD(nullptr), nGCPCount(0), pasGCPList(nullptr),
625
27
      papszExtraFiles(nullptr)
626
27
{
627
27
    m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
628
27
    m_oSRS.importFromWkt(SRS_WKT_WGS84_LAT_LONG);
629
630
27
    sVolume.Flavor = 0;
631
27
    sVolume.Sensor = 0;
632
27
    sVolume.ProductType = 0;
633
27
    sVolume.FileNamingConvention = 0;
634
635
27
    sVolume.VolumeDirectoryFile = 0;
636
27
    sVolume.SARLeaderFile = 0;
637
27
    sVolume.ImagryOptionsFile = 0;
638
27
    sVolume.SARTrailerFile = 0;
639
27
    sVolume.NullVolumeDirectoryFile = 0;
640
641
27
    sVolume.ImageDesc.ImageDescValid = 0;
642
27
    sVolume.ImageDesc.NumChannels = 0;
643
27
    sVolume.ImageDesc.ChannelInterleaving = 0;
644
27
    sVolume.ImageDesc.DataType = 0;
645
27
    sVolume.ImageDesc.BytesPerRecord = 0;
646
27
    sVolume.ImageDesc.Lines = 0;
647
27
    sVolume.ImageDesc.TopBorderPixels = 0;
648
27
    sVolume.ImageDesc.BottomBorderPixels = 0;
649
27
    sVolume.ImageDesc.PixelsPerLine = 0;
650
27
    sVolume.ImageDesc.LeftBorderPixels = 0;
651
27
    sVolume.ImageDesc.RightBorderPixels = 0;
652
27
    sVolume.ImageDesc.BytesPerPixel = 0;
653
27
    sVolume.ImageDesc.RecordsPerLine = 0;
654
27
    sVolume.ImageDesc.PixelsPerRecord = 0;
655
27
    sVolume.ImageDesc.ImageDataStart = 0;
656
27
    sVolume.ImageDesc.ImageSuffixData = 0;
657
27
    sVolume.ImageDesc.FileDescriptorLength = 0;
658
27
    sVolume.ImageDesc.PixelOrder = 0;
659
27
    sVolume.ImageDesc.LineOrder = 0;
660
27
    sVolume.ImageDesc.PixelDataBytesPerRecord = 0;
661
662
27
    sVolume.RecordList = nullptr;
663
27
}
664
665
/************************************************************************/
666
/*                          ~SAR_CEOSDataset()                          */
667
/************************************************************************/
668
669
SAR_CEOSDataset::~SAR_CEOSDataset()
670
671
27
{
672
27
    FlushCache(true);
673
674
27
    CSLDestroy(papszTempMD);
675
676
27
    if (fpImage != nullptr)
677
27
        CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
678
679
27
    if (nGCPCount > 0)
680
5
    {
681
5
        GDALDeinitGCPs(nGCPCount, pasGCPList);
682
5
    }
683
27
    CPLFree(pasGCPList);
684
685
27
    if (sVolume.RecordList)
686
25
    {
687
495
        for (Link_t *Links = sVolume.RecordList; Links != nullptr;
688
470
             Links = Links->next)
689
470
        {
690
470
            if (Links->object)
691
470
            {
692
470
                DeleteCeosRecord((CeosRecord_t *)Links->object);
693
470
                Links->object = nullptr;
694
470
            }
695
470
        }
696
25
        DestroyList(sVolume.RecordList);
697
25
    }
698
27
    FreeRecipes();
699
27
    CSLDestroy(papszExtraFiles);
700
27
}
701
702
/************************************************************************/
703
/*                            GetGCPCount()                             */
704
/************************************************************************/
705
706
int SAR_CEOSDataset::GetGCPCount()
707
708
10
{
709
10
    return nGCPCount;
710
10
}
711
712
/************************************************************************/
713
/*                          GetGCPSpatialRef()                          */
714
/************************************************************************/
715
716
const OGRSpatialReference *SAR_CEOSDataset::GetGCPSpatialRef() const
717
718
10
{
719
10
    if (nGCPCount > 0)
720
5
        return &m_oSRS;
721
722
5
    return nullptr;
723
10
}
724
725
/************************************************************************/
726
/*                               GetGCP()                               */
727
/************************************************************************/
728
729
const GDAL_GCP *SAR_CEOSDataset::GetGCPs()
730
731
10
{
732
10
    return pasGCPList;
733
10
}
734
735
/************************************************************************/
736
/*                      GetMetadataDomainList()                         */
737
/************************************************************************/
738
739
char **SAR_CEOSDataset::GetMetadataDomainList()
740
0
{
741
0
    return CSLAddString(GDALDataset::GetMetadataDomainList(),
742
0
                        "ceos-FFF-n-n-n-n:r");
743
0
}
744
745
/************************************************************************/
746
/*                            GetMetadata()                             */
747
/*                                                                      */
748
/*      We provide our own GetMetadata() so that we can override        */
749
/*      behavior for some very specialized domain names intended to     */
750
/*      give us access to raw record data.                              */
751
/*                                                                      */
752
/*      The domain must look like:                                      */
753
/*        ceos-FFF-n-n-n-n:r                                            */
754
/*                                                                      */
755
/*        FFF - The file id - one of vol, lea, img, trl or nul.         */
756
/*        n-n-n-n - the record type code such as 18-10-18-20 for the    */
757
/*        dataset summary record in the leader file.                    */
758
/*        :r - The zero based record number to fetch (optional)         */
759
/*                                                                      */
760
/*      Note that only records that are pre-loaded will be              */
761
/*      accessible, and this normally means that most image records     */
762
/*      are not available.                                              */
763
/************************************************************************/
764
765
char **SAR_CEOSDataset::GetMetadata(const char *pszDomain)
766
767
21
{
768
21
    if (pszDomain == nullptr || !STARTS_WITH_CI(pszDomain, "ceos-"))
769
21
        return GDALDataset::GetMetadata(pszDomain);
770
771
    /* -------------------------------------------------------------------- */
772
    /*      Identify which file to fetch the file from.                     */
773
    /* -------------------------------------------------------------------- */
774
0
    int nFileId = -1;
775
776
0
    if (STARTS_WITH_CI(pszDomain, "ceos-vol"))
777
0
    {
778
0
        nFileId = CEOS_VOLUME_DIR_FILE;
779
0
    }
780
0
    else if (STARTS_WITH_CI(pszDomain, "ceos-lea"))
781
0
    {
782
0
        nFileId = CEOS_LEADER_FILE;
783
0
    }
784
0
    else if (STARTS_WITH_CI(pszDomain, "ceos-img"))
785
0
    {
786
0
        nFileId = CEOS_IMAGRY_OPT_FILE;
787
0
    }
788
0
    else if (STARTS_WITH_CI(pszDomain, "ceos-trl"))
789
0
    {
790
0
        nFileId = CEOS_TRAILER_FILE;
791
0
    }
792
0
    else if (STARTS_WITH_CI(pszDomain, "ceos-nul"))
793
0
    {
794
0
        nFileId = CEOS_NULL_VOL_FILE;
795
0
    }
796
0
    else
797
0
        return nullptr;
798
799
0
    pszDomain += 8;
800
801
    /* -------------------------------------------------------------------- */
802
    /*      Identify the record type.                                       */
803
    /* -------------------------------------------------------------------- */
804
0
    int a, b, c, d, nRecordIndex = -1;
805
806
0
    if (sscanf(pszDomain, "-%d-%d-%d-%d:%d", &a, &b, &c, &d, &nRecordIndex) !=
807
0
            5 &&
808
0
        sscanf(pszDomain, "-%d-%d-%d-%d", &a, &b, &c, &d) != 4)
809
0
    {
810
0
        return nullptr;
811
0
    }
812
813
0
    CeosTypeCode_t sTypeCode = QuadToTC(a, b, c, d);
814
815
    /* -------------------------------------------------------------------- */
816
    /*      Try to fetch the record.                                        */
817
    /* -------------------------------------------------------------------- */
818
0
    CeosRecord_t *record = FindCeosRecord(sVolume.RecordList, sTypeCode,
819
0
                                          nFileId, -1, nRecordIndex);
820
821
0
    if (record == nullptr)
822
0
        return nullptr;
823
824
    /* -------------------------------------------------------------------- */
825
    /*      Massage the data into a safe textual format.  The RawRecord     */
826
    /*      just has zero bytes turned into spaces while the                */
827
    /*      EscapedRecord has regular backslash escaping applied to zero    */
828
    /*      chars, double quotes, and backslashes.                          */
829
    /*      just turn zero bytes into spaces.                               */
830
    /* -------------------------------------------------------------------- */
831
832
0
    CSLDestroy(papszTempMD);
833
834
    // Escaped version
835
0
    char *pszSafeCopy = CPLEscapeString((char *)record->Buffer, record->Length,
836
0
                                        CPLES_BackslashQuotable);
837
0
    papszTempMD = CSLSetNameValue(nullptr, "EscapedRecord", pszSafeCopy);
838
0
    CPLFree(pszSafeCopy);
839
840
    // Copy with '\0' replaced by spaces.
841
842
0
    pszSafeCopy = (char *)CPLCalloc(1, record->Length + 1);
843
0
    memcpy(pszSafeCopy, record->Buffer, record->Length);
844
845
0
    for (int i = 0; i < record->Length; i++)
846
0
        if (pszSafeCopy[i] == '\0')
847
0
            pszSafeCopy[i] = ' ';
848
849
0
    papszTempMD = CSLSetNameValue(papszTempMD, "RawRecord", pszSafeCopy);
850
851
0
    CPLFree(pszSafeCopy);
852
853
0
    return papszTempMD;
854
0
}
855
856
/************************************************************************/
857
/*                          ScanForMetadata()                           */
858
/************************************************************************/
859
860
void SAR_CEOSDataset::ScanForMetadata()
861
862
10
{
863
    /* -------------------------------------------------------------------- */
864
    /*      Get the volume id (with the sensor name)                        */
865
    /* -------------------------------------------------------------------- */
866
10
    CeosRecord_t *record =
867
10
        FindCeosRecord(sVolume.RecordList, VOLUME_DESCRIPTOR_RECORD_TC,
868
10
                       CEOS_VOLUME_DIR_FILE, -1, -1);
869
870
10
    char szVolId[128];
871
10
    szVolId[0] = '\0';
872
10
    char szField[128];
873
10
    szField[0] = '\0';
874
10
    if (record != nullptr)
875
0
    {
876
0
        szVolId[16] = '\0';
877
878
0
        GetCeosField(record, 61, "A16", szVolId);
879
880
0
        SetMetadataItem("CEOS_LOGICAL_VOLUME_ID", szVolId);
881
882
        /* --------------------------------------------------------------------
883
         */
884
        /*      Processing facility */
885
        /* --------------------------------------------------------------------
886
         */
887
0
        szField[0] = '\0';
888
0
        szField[12] = '\0';
889
890
0
        GetCeosField(record, 149, "A12", szField);
891
892
0
        if (!STARTS_WITH_CI(szField, "            "))
893
0
            SetMetadataItem("CEOS_PROCESSING_FACILITY", szField);
894
895
        /* --------------------------------------------------------------------
896
         */
897
        /*      Agency */
898
        /* --------------------------------------------------------------------
899
         */
900
0
        szField[8] = '\0';
901
902
0
        GetCeosField(record, 141, "A8", szField);
903
904
0
        if (!STARTS_WITH_CI(szField, "            "))
905
0
            SetMetadataItem("CEOS_PROCESSING_AGENCY", szField);
906
907
        /* --------------------------------------------------------------------
908
         */
909
        /*      Country */
910
        /* --------------------------------------------------------------------
911
         */
912
0
        szField[12] = '\0';
913
914
0
        GetCeosField(record, 129, "A12", szField);
915
916
0
        if (!STARTS_WITH_CI(szField, "            "))
917
0
            SetMetadataItem("CEOS_PROCESSING_COUNTRY", szField);
918
919
        /* --------------------------------------------------------------------
920
         */
921
        /*      software id. */
922
        /* --------------------------------------------------------------------
923
         */
924
0
        szField[12] = '\0';
925
926
0
        GetCeosField(record, 33, "A12", szField);
927
928
0
        if (!STARTS_WITH_CI(szField, "            "))
929
0
            SetMetadataItem("CEOS_SOFTWARE_ID", szField);
930
931
        /* --------------------------------------------------------------------
932
         */
933
        /*      product identifier. */
934
        /* --------------------------------------------------------------------
935
         */
936
0
        szField[8] = '\0';
937
938
0
        GetCeosField(record, 261, "A8", szField);
939
940
0
        if (!STARTS_WITH_CI(szField, "        "))
941
0
            SetMetadataItem("CEOS_PRODUCT_ID", szField);
942
943
        /* --------------------------------------------------------------------
944
         */
945
        /*      volume identifier. */
946
        /* --------------------------------------------------------------------
947
         */
948
0
        szField[16] = '\0';
949
950
0
        GetCeosField(record, 77, "A16", szField);
951
952
0
        if (!STARTS_WITH_CI(szField, "                "))
953
0
            SetMetadataItem("CEOS_VOLSET_ID", szField);
954
0
    }
955
956
    /* ==================================================================== */
957
    /*      Dataset summary record.                                         */
958
    /* ==================================================================== */
959
10
    record = FindCeosRecord(sVolume.RecordList, LEADER_DATASET_SUMMARY_TC,
960
10
                            CEOS_LEADER_FILE, -1, -1);
961
962
10
    if (record == nullptr)
963
10
        record =
964
10
            FindCeosRecord(sVolume.RecordList, LEADER_DATASET_SUMMARY_ASF_TC,
965
10
                           CEOS_LEADER_FILE, -1, -1);
966
967
10
    if (record == nullptr)
968
10
        record = FindCeosRecord(sVolume.RecordList, LEADER_DATASET_SUMMARY_TC,
969
10
                                CEOS_TRAILER_FILE, -1, -1);
970
971
10
    if (record == nullptr)
972
10
        record =
973
10
            FindCeosRecord(sVolume.RecordList, LEADER_DATASET_SUMMARY_ERS2_TC,
974
10
                           CEOS_LEADER_FILE, -1, -1);
975
976
10
    if (record != nullptr)
977
0
    {
978
        /* --------------------------------------------------------------------
979
         */
980
        /*      Get the acquisition date. */
981
        /* --------------------------------------------------------------------
982
         */
983
0
        szField[0] = '\0';
984
0
        szField[32] = '\0';
985
986
0
        GetCeosField(record, 69, "A32", szField);
987
988
0
        SetMetadataItem("CEOS_ACQUISITION_TIME", szField);
989
990
        /* --------------------------------------------------------------------
991
         */
992
        /*      Ascending/Descending */
993
        /* --------------------------------------------------------------------
994
         */
995
0
        GetCeosField(record, 101, "A16", szField);
996
0
        szField[16] = '\0';
997
998
0
        if (strstr(szVolId, "RSAT") != nullptr &&
999
0
            !STARTS_WITH_CI(szField, "                "))
1000
0
            SetMetadataItem("CEOS_ASC_DES", szField);
1001
1002
        /* --------------------------------------------------------------------
1003
         */
1004
        /*      True heading - at least for ERS2. */
1005
        /* --------------------------------------------------------------------
1006
         */
1007
0
        GetCeosField(record, 149, "A16", szField);
1008
0
        szField[16] = '\0';
1009
1010
0
        if (!STARTS_WITH_CI(szField, "                "))
1011
0
            SetMetadataItem("CEOS_TRUE_HEADING", szField);
1012
1013
        /* --------------------------------------------------------------------
1014
         */
1015
        /*      Ellipsoid */
1016
        /* --------------------------------------------------------------------
1017
         */
1018
0
        GetCeosField(record, 165, "A16", szField);
1019
0
        szField[16] = '\0';
1020
1021
0
        if (!STARTS_WITH_CI(szField, "                "))
1022
0
            SetMetadataItem("CEOS_ELLIPSOID", szField);
1023
1024
        /* --------------------------------------------------------------------
1025
         */
1026
        /*      Semimajor, semiminor axis */
1027
        /* --------------------------------------------------------------------
1028
         */
1029
0
        GetCeosField(record, 181, "A16", szField);
1030
0
        szField[16] = '\0';
1031
1032
0
        if (!STARTS_WITH_CI(szField, "                "))
1033
0
            SetMetadataItem("CEOS_SEMI_MAJOR", szField);
1034
1035
0
        GetCeosField(record, 197, "A16", szField);
1036
0
        szField[16] = '\0';
1037
1038
0
        if (!STARTS_WITH_CI(szField, "                "))
1039
0
            SetMetadataItem("CEOS_SEMI_MINOR", szField);
1040
1041
        /* --------------------------------------------------------------------
1042
         */
1043
        /*      SCENE LENGTH KM */
1044
        /* --------------------------------------------------------------------
1045
         */
1046
0
        GetCeosField(record, 341, "A16", szField);
1047
0
        szField[16] = '\0';
1048
1049
0
        if (!STARTS_WITH_CI(szField, "                "))
1050
0
            SetMetadataItem("CEOS_SCENE_LENGTH_KM", szField);
1051
1052
        /* --------------------------------------------------------------------
1053
         */
1054
        /*      SCENE WIDTH KM */
1055
        /* --------------------------------------------------------------------
1056
         */
1057
0
        GetCeosField(record, 357, "A16", szField);
1058
0
        szField[16] = '\0';
1059
1060
0
        if (!STARTS_WITH_CI(szField, "                "))
1061
0
            SetMetadataItem("CEOS_SCENE_WIDTH_KM", szField);
1062
1063
        /* --------------------------------------------------------------------
1064
         */
1065
        /*      MISSION ID */
1066
        /* --------------------------------------------------------------------
1067
         */
1068
0
        GetCeosField(record, 397, "A16", szField);
1069
0
        szField[16] = '\0';
1070
1071
0
        if (!STARTS_WITH_CI(szField, "                "))
1072
0
            SetMetadataItem("CEOS_MISSION_ID", szField);
1073
1074
        /* --------------------------------------------------------------------
1075
         */
1076
        /*      SENSOR ID */
1077
        /* --------------------------------------------------------------------
1078
         */
1079
0
        GetCeosField(record, 413, "A32", szField);
1080
0
        szField[32] = '\0';
1081
1082
0
        if (!STARTS_WITH_CI(szField, "                                "))
1083
0
            SetMetadataItem("CEOS_SENSOR_ID", szField);
1084
1085
        /* --------------------------------------------------------------------
1086
         */
1087
        /*      ORBIT NUMBER */
1088
        /* --------------------------------------------------------------------
1089
         */
1090
0
        GetCeosField(record, 445, "A8", szField);
1091
0
        szField[8] = '\0';
1092
1093
0
        if (!STARTS_WITH_CI(szField, "        "))
1094
0
            SetMetadataItem("CEOS_ORBIT_NUMBER", szField);
1095
1096
        /* --------------------------------------------------------------------
1097
         */
1098
        /*      Platform latitude */
1099
        /* --------------------------------------------------------------------
1100
         */
1101
0
        GetCeosField(record, 453, "A8", szField);
1102
0
        szField[8] = '\0';
1103
1104
0
        if (!STARTS_WITH_CI(szField, "        "))
1105
0
            SetMetadataItem("CEOS_PLATFORM_LATITUDE", szField);
1106
1107
        /* --------------------------------------------------------------------
1108
         */
1109
        /*      Platform longitude */
1110
        /* --------------------------------------------------------------------
1111
         */
1112
0
        GetCeosField(record, 461, "A8", szField);
1113
0
        szField[8] = '\0';
1114
1115
0
        if (!STARTS_WITH_CI(szField, "        "))
1116
0
            SetMetadataItem("CEOS_PLATFORM_LONGITUDE", szField);
1117
1118
        /* --------------------------------------------------------------------
1119
         */
1120
        /*      Platform heading - at least for ERS2. */
1121
        /* --------------------------------------------------------------------
1122
         */
1123
0
        GetCeosField(record, 469, "A8", szField);
1124
0
        szField[8] = '\0';
1125
1126
0
        if (!STARTS_WITH_CI(szField, "        "))
1127
0
            SetMetadataItem("CEOS_PLATFORM_HEADING", szField);
1128
1129
        /* --------------------------------------------------------------------
1130
         */
1131
        /*      Look Angle. */
1132
        /* --------------------------------------------------------------------
1133
         */
1134
0
        GetCeosField(record, 477, "A8", szField);
1135
0
        szField[8] = '\0';
1136
1137
0
        if (!STARTS_WITH_CI(szField, "        "))
1138
0
            SetMetadataItem("CEOS_SENSOR_CLOCK_ANGLE", szField);
1139
1140
        /* --------------------------------------------------------------------
1141
         */
1142
        /*      Incidence angle */
1143
        /* --------------------------------------------------------------------
1144
         */
1145
0
        GetCeosField(record, 485, "A8", szField);
1146
0
        szField[8] = '\0';
1147
1148
0
        if (!STARTS_WITH_CI(szField, "        "))
1149
0
            SetMetadataItem("CEOS_INC_ANGLE", szField);
1150
1151
        /* --------------------------------------------------------------------
1152
         */
1153
        /*      Facility */
1154
        /* --------------------------------------------------------------------
1155
         */
1156
0
        GetCeosField(record, 1047, "A16", szField);
1157
0
        szField[16] = '\0';
1158
1159
0
        if (!STARTS_WITH_CI(szField, "                "))
1160
0
            SetMetadataItem("CEOS_FACILITY", szField);
1161
        /* --------------------------------------------------------------------
1162
         */
1163
        /*      Pixel time direction indicator */
1164
        /* --------------------------------------------------------------------
1165
         */
1166
0
        GetCeosField(record, 1527, "A8", szField);
1167
0
        szField[8] = '\0';
1168
1169
0
        if (!STARTS_WITH_CI(szField, "        "))
1170
0
            SetMetadataItem("CEOS_PIXEL_TIME_DIR", szField);
1171
1172
        /* --------------------------------------------------------------------
1173
         */
1174
        /*      Line spacing */
1175
        /* --------------------------------------------------------------------
1176
         */
1177
0
        GetCeosField(record, 1687, "A16", szField);
1178
0
        szField[16] = '\0';
1179
1180
0
        if (!STARTS_WITH_CI(szField, "                "))
1181
0
            SetMetadataItem("CEOS_LINE_SPACING_METERS", szField);
1182
        /* --------------------------------------------------------------------
1183
         */
1184
        /*      Pixel spacing */
1185
        /* --------------------------------------------------------------------
1186
         */
1187
0
        GetCeosField(record, 1703, "A16", szField);
1188
0
        szField[16] = '\0';
1189
1190
0
        if (!STARTS_WITH_CI(szField, "                "))
1191
0
            SetMetadataItem("CEOS_PIXEL_SPACING_METERS", szField);
1192
0
    }
1193
1194
    /* -------------------------------------------------------------------- */
1195
    /*      Get the beam mode, for radarsat.                                */
1196
    /* -------------------------------------------------------------------- */
1197
10
    record =
1198
10
        FindCeosRecord(sVolume.RecordList, LEADER_RADIOMETRIC_COMPENSATION_TC,
1199
10
                       CEOS_LEADER_FILE, -1, -1);
1200
1201
10
    if (strstr(szVolId, "RSAT") != nullptr && record != nullptr)
1202
0
    {
1203
0
        szField[16] = '\0';
1204
1205
0
        GetCeosField(record, 4189, "A16", szField);
1206
1207
0
        SetMetadataItem("CEOS_BEAM_TYPE", szField);
1208
0
    }
1209
1210
    /* ==================================================================== */
1211
    /*      ERS calibration and incidence angle info                        */
1212
    /* ==================================================================== */
1213
10
    record = FindCeosRecord(sVolume.RecordList, ERS_GENERAL_FACILITY_DATA_TC,
1214
10
                            CEOS_LEADER_FILE, -1, -1);
1215
1216
10
    if (record == nullptr)
1217
10
        record =
1218
10
            FindCeosRecord(sVolume.RecordList, ERS_GENERAL_FACILITY_DATA_ALT_TC,
1219
10
                           CEOS_LEADER_FILE, -1, -1);
1220
1221
10
    if (record != nullptr)
1222
0
    {
1223
0
        GetCeosField(record, 13, "A64", szField);
1224
0
        szField[64] = '\0';
1225
1226
        /* Avoid PCS records, which don't contain necessary info */
1227
0
        if (strstr(szField, "GENERAL") == nullptr)
1228
0
            record = nullptr;
1229
0
    }
1230
1231
10
    if (record != nullptr)
1232
0
    {
1233
0
        GetCeosField(record, 583, "A16", szField);
1234
0
        szField[16] = '\0';
1235
1236
0
        if (!STARTS_WITH_CI(szField, "                "))
1237
0
            SetMetadataItem("CEOS_INC_ANGLE_FIRST_RANGE", szField);
1238
1239
0
        GetCeosField(record, 599, "A16", szField);
1240
0
        szField[16] = '\0';
1241
1242
0
        if (!STARTS_WITH_CI(szField, "                "))
1243
0
            SetMetadataItem("CEOS_INC_ANGLE_CENTRE_RANGE", szField);
1244
1245
0
        GetCeosField(record, 615, "A16", szField);
1246
0
        szField[16] = '\0';
1247
1248
0
        if (!STARTS_WITH_CI(szField, "                "))
1249
0
            SetMetadataItem("CEOS_INC_ANGLE_LAST_RANGE", szField);
1250
1251
0
        GetCeosField(record, 663, "A16", szField);
1252
0
        szField[16] = '\0';
1253
1254
0
        if (!STARTS_WITH_CI(szField, "                "))
1255
0
            SetMetadataItem("CEOS_CALIBRATION_CONSTANT_K", szField);
1256
1257
0
        GetCeosField(record, 1855, "A20", szField);
1258
0
        szField[20] = '\0';
1259
1260
0
        if (!STARTS_WITH_CI(szField, "                    "))
1261
0
            SetMetadataItem("CEOS_GROUND_TO_SLANT_C0", szField);
1262
1263
0
        GetCeosField(record, 1875, "A20", szField);
1264
0
        szField[20] = '\0';
1265
1266
0
        if (!STARTS_WITH_CI(szField, "                    "))
1267
0
            SetMetadataItem("CEOS_GROUND_TO_SLANT_C1", szField);
1268
1269
0
        GetCeosField(record, 1895, "A20", szField);
1270
0
        szField[20] = '\0';
1271
1272
0
        if (!STARTS_WITH_CI(szField, "                    "))
1273
0
            SetMetadataItem("CEOS_GROUND_TO_SLANT_C2", szField);
1274
1275
0
        GetCeosField(record, 1915, "A20", szField);
1276
0
        szField[20] = '\0';
1277
1278
0
        if (!STARTS_WITH_CI(szField, "                    "))
1279
0
            SetMetadataItem("CEOS_GROUND_TO_SLANT_C3", szField);
1280
0
    }
1281
    /* -------------------------------------------------------------------- */
1282
    /*      Detailed Processing Parameters (Radarsat)                       */
1283
    /* -------------------------------------------------------------------- */
1284
10
    record = FindCeosRecord(sVolume.RecordList, RSAT_PROC_PARAM_TC,
1285
10
                            CEOS_LEADER_FILE, -1, -1);
1286
1287
10
    if (record == nullptr)
1288
10
        record = FindCeosRecord(sVolume.RecordList, RSAT_PROC_PARAM_TC,
1289
10
                                CEOS_TRAILER_FILE, -1, -1);
1290
1291
10
    if (record != nullptr)
1292
0
    {
1293
0
        GetCeosField(record, 192, "A21", szField);
1294
0
        szField[21] = '\0';
1295
1296
0
        if (!STARTS_WITH_CI(szField, "                     "))
1297
0
            SetMetadataItem("CEOS_PROC_START", szField);
1298
1299
0
        GetCeosField(record, 213, "A21", szField);
1300
0
        szField[21] = '\0';
1301
1302
0
        if (!STARTS_WITH_CI(szField, "                     "))
1303
0
            SetMetadataItem("CEOS_PROC_STOP", szField);
1304
1305
0
        GetCeosField(record, 4649, "A16", szField);
1306
0
        szField[16] = '\0';
1307
1308
0
        if (!STARTS_WITH_CI(szField, "                "))
1309
0
            SetMetadataItem("CEOS_EPH_ORB_DATA_0", szField);
1310
1311
0
        GetCeosField(record, 4665, "A16", szField);
1312
0
        szField[16] = '\0';
1313
1314
0
        if (!STARTS_WITH_CI(szField, "                "))
1315
0
            SetMetadataItem("CEOS_EPH_ORB_DATA_1", szField);
1316
1317
0
        GetCeosField(record, 4681, "A16", szField);
1318
0
        szField[16] = '\0';
1319
1320
0
        if (!STARTS_WITH_CI(szField, "                "))
1321
0
            SetMetadataItem("CEOS_EPH_ORB_DATA_2", szField);
1322
1323
0
        GetCeosField(record, 4697, "A16", szField);
1324
0
        szField[16] = '\0';
1325
1326
0
        if (!STARTS_WITH_CI(szField, "                "))
1327
0
            SetMetadataItem("CEOS_EPH_ORB_DATA_3", szField);
1328
1329
0
        GetCeosField(record, 4713, "A16", szField);
1330
0
        szField[16] = '\0';
1331
1332
0
        if (!STARTS_WITH_CI(szField, "                "))
1333
0
            SetMetadataItem("CEOS_EPH_ORB_DATA_4", szField);
1334
1335
0
        GetCeosField(record, 4729, "A16", szField);
1336
0
        szField[16] = '\0';
1337
1338
0
        if (!STARTS_WITH_CI(szField, "                "))
1339
0
            SetMetadataItem("CEOS_EPH_ORB_DATA_5", szField);
1340
1341
0
        GetCeosField(record, 4745, "A16", szField);
1342
0
        szField[16] = '\0';
1343
1344
0
        if (!STARTS_WITH_CI(szField, "                "))
1345
0
            SetMetadataItem("CEOS_EPH_ORB_DATA_6", szField);
1346
1347
0
        GetCeosField(record, 4908, "A16", szField);
1348
0
        szField[16] = '\0';
1349
1350
0
        if (!STARTS_WITH_CI(szField, "                "))
1351
0
            SetMetadataItem("CEOS_GROUND_TO_SLANT_C0", szField);
1352
1353
0
        GetCeosField(record, 4924, "A16", szField);
1354
0
        szField[16] = '\0';
1355
1356
0
        if (!STARTS_WITH_CI(szField, "                "))
1357
0
            SetMetadataItem("CEOS_GROUND_TO_SLANT_C1", szField);
1358
1359
0
        GetCeosField(record, 4940, "A16", szField);
1360
0
        szField[16] = '\0';
1361
1362
0
        if (!STARTS_WITH_CI(szField, "                "))
1363
0
            SetMetadataItem("CEOS_GROUND_TO_SLANT_C2", szField);
1364
1365
0
        GetCeosField(record, 4956, "A16", szField);
1366
0
        szField[16] = '\0';
1367
1368
0
        if (!STARTS_WITH_CI(szField, "                "))
1369
0
            SetMetadataItem("CEOS_GROUND_TO_SLANT_C3", szField);
1370
1371
0
        GetCeosField(record, 4972, "A16", szField);
1372
0
        szField[16] = '\0';
1373
1374
0
        if (!STARTS_WITH_CI(szField, "                "))
1375
0
            SetMetadataItem("CEOS_GROUND_TO_SLANT_C4", szField);
1376
1377
0
        GetCeosField(record, 4988, "A16", szField);
1378
0
        szField[16] = '\0';
1379
1380
0
        if (!STARTS_WITH_CI(szField, "                "))
1381
0
            SetMetadataItem("CEOS_GROUND_TO_SLANT_C5", szField);
1382
1383
0
        GetCeosField(record, 7334, "A16", szField);
1384
0
        szField[16] = '\0';
1385
1386
0
        if (!STARTS_WITH_CI(szField, "                "))
1387
0
            SetMetadataItem("CEOS_INC_ANGLE_FIRST_RANGE", szField);
1388
1389
0
        GetCeosField(record, 7350, "A16", szField);
1390
0
        szField[16] = '\0';
1391
1392
0
        if (!STARTS_WITH_CI(szField, "                "))
1393
0
            SetMetadataItem("CEOS_INC_ANGLE_LAST_RANGE", szField);
1394
0
    }
1395
    /* -------------------------------------------------------------------- */
1396
    /*      Get process-to-raw data coordinate translation values.  These   */
1397
    /*      are likely specific to Atlantis APP products.                   */
1398
    /* -------------------------------------------------------------------- */
1399
10
    record = FindCeosRecord(sVolume.RecordList, IMAGE_HEADER_RECORD_TC,
1400
10
                            CEOS_IMAGRY_OPT_FILE, -1, -1);
1401
1402
10
    if (record != nullptr)
1403
10
    {
1404
10
        GetCeosField(record, 449, "A4", szField);
1405
10
        szField[4] = '\0';
1406
1407
10
        if (!STARTS_WITH_CI(szField, "    "))
1408
1
            SetMetadataItem("CEOS_DM_CORNER", szField);
1409
1410
10
        GetCeosField(record, 453, "A4", szField);
1411
10
        szField[4] = '\0';
1412
1413
10
        if (!STARTS_WITH_CI(szField, "    "))
1414
1
            SetMetadataItem("CEOS_DM_TRANSPOSE", szField);
1415
1416
10
        GetCeosField(record, 457, "A4", szField);
1417
10
        szField[4] = '\0';
1418
1419
10
        if (!STARTS_WITH_CI(szField, "    "))
1420
1
            SetMetadataItem("CEOS_DM_START_SAMPLE", szField);
1421
1422
10
        GetCeosField(record, 461, "A5", szField);
1423
10
        szField[5] = '\0';
1424
1425
10
        if (!STARTS_WITH_CI(szField, "     "))
1426
1
            SetMetadataItem("CEOS_DM_START_PULSE", szField);
1427
1428
10
        GetCeosField(record, 466, "A16", szField);
1429
10
        szField[16] = '\0';
1430
1431
10
        if (!STARTS_WITH_CI(szField, "                "))
1432
1
            SetMetadataItem("CEOS_DM_FAST_ALPHA", szField);
1433
1434
10
        GetCeosField(record, 482, "A16", szField);
1435
10
        szField[16] = '\0';
1436
1437
10
        if (!STARTS_WITH_CI(szField, "                "))
1438
1
            SetMetadataItem("CEOS_DM_FAST_BETA", szField);
1439
1440
10
        GetCeosField(record, 498, "A16", szField);
1441
10
        szField[16] = '\0';
1442
1443
10
        if (!STARTS_WITH_CI(szField, "                "))
1444
1
            SetMetadataItem("CEOS_DM_SLOW_ALPHA", szField);
1445
1446
10
        GetCeosField(record, 514, "A16", szField);
1447
10
        szField[16] = '\0';
1448
1449
10
        if (!STARTS_WITH_CI(szField, "                "))
1450
1
            SetMetadataItem("CEOS_DM_SLOW_BETA", szField);
1451
1452
10
        GetCeosField(record, 530, "A16", szField);
1453
10
        szField[16] = '\0';
1454
1455
10
        if (!STARTS_WITH_CI(szField, "                "))
1456
1
            SetMetadataItem("CEOS_DM_FAST_ALPHA_2", szField);
1457
10
    }
1458
1459
    /* -------------------------------------------------------------------- */
1460
    /*      Try to find calibration information from Radiometric Data       */
1461
    /*      Record.                                                         */
1462
    /* -------------------------------------------------------------------- */
1463
10
    record =
1464
10
        FindCeosRecord(sVolume.RecordList, LEADER_RADIOMETRIC_DATA_RECORD_TC,
1465
10
                       CEOS_LEADER_FILE, -1, -1);
1466
1467
10
    if (record == nullptr)
1468
10
        record = FindCeosRecord(sVolume.RecordList,
1469
10
                                LEADER_RADIOMETRIC_DATA_RECORD_TC,
1470
10
                                CEOS_TRAILER_FILE, -1, -1);
1471
1472
10
    if (record != nullptr)
1473
0
    {
1474
0
        GetCeosField(record, 8317, "A16", szField);
1475
0
        szField[16] = '\0';
1476
1477
0
        if (!STARTS_WITH_CI(szField, "                "))
1478
0
            SetMetadataItem("CEOS_CALIBRATION_OFFSET", szField);
1479
0
    }
1480
1481
    /* -------------------------------------------------------------------- */
1482
    /*      For ERS Standard Format Landsat scenes we pick up the           */
1483
    /*      calibration offset and gain from the Radiometric Ancillary      */
1484
    /*      Record.                                                         */
1485
    /* -------------------------------------------------------------------- */
1486
10
    record =
1487
10
        FindCeosRecord(sVolume.RecordList, QuadToTC(0x3f, 0x24, 0x12, 0x09),
1488
10
                       CEOS_LEADER_FILE, -1, -1);
1489
10
    if (record != nullptr)
1490
0
    {
1491
0
        GetCeosField(record, 29, "A20", szField);
1492
0
        szField[20] = '\0';
1493
1494
0
        if (!STARTS_WITH_CI(szField, "                    "))
1495
0
            SetMetadataItem("CEOS_OFFSET_A0", szField);
1496
1497
0
        GetCeosField(record, 49, "A20", szField);
1498
0
        szField[20] = '\0';
1499
1500
0
        if (!STARTS_WITH_CI(szField, "                    "))
1501
0
            SetMetadataItem("CEOS_GAIN_A1", szField);
1502
0
    }
1503
1504
    /* -------------------------------------------------------------------- */
1505
    /*      For ERS Standard Format Landsat scenes we pick up the           */
1506
    /*      gain setting from the Scene Header Record.                      */
1507
    /* -------------------------------------------------------------------- */
1508
10
    record =
1509
10
        FindCeosRecord(sVolume.RecordList, QuadToTC(0x12, 0x12, 0x12, 0x09),
1510
10
                       CEOS_LEADER_FILE, -1, -1);
1511
10
    if (record != nullptr)
1512
0
    {
1513
0
        GetCeosField(record, 1486, "A1", szField);
1514
0
        szField[1] = '\0';
1515
1516
0
        if (szField[0] == 'H' || szField[0] == 'V')
1517
0
            SetMetadataItem("CEOS_GAIN_SETTING", szField);
1518
0
    }
1519
10
}
1520
1521
/************************************************************************/
1522
/*                        ScanForMapProjection()                        */
1523
/*                                                                      */
1524
/*      Try to find a map projection record, and read corner points     */
1525
/*      from it.  This has only been tested with ERS products.          */
1526
/************************************************************************/
1527
1528
int SAR_CEOSDataset::ScanForMapProjection()
1529
1530
5
{
1531
    /* -------------------------------------------------------------------- */
1532
    /*      Find record, and try to determine if it has useful GCPs.        */
1533
    /* -------------------------------------------------------------------- */
1534
1535
5
    CeosRecord_t *record =
1536
5
        FindCeosRecord(sVolume.RecordList, LEADER_MAP_PROJ_RECORD_TC,
1537
5
                       CEOS_LEADER_FILE, -1, -1);
1538
1539
5
    int gcp_ordering_mode = CEOS_STD_MAPREC_GCP_ORDER;
1540
    /* JERS from Japan */
1541
5
    if (record == nullptr)
1542
5
        record =
1543
5
            FindCeosRecord(sVolume.RecordList, LEADER_MAP_PROJ_RECORD_JERS_TC,
1544
5
                           CEOS_LEADER_FILE, -1, -1);
1545
1546
5
    if (record == nullptr)
1547
5
    {
1548
5
        record =
1549
5
            FindCeosRecord(sVolume.RecordList, LEADER_MAP_PROJ_RECORD_ASF_TC,
1550
5
                           CEOS_LEADER_FILE, -1, -1);
1551
5
        gcp_ordering_mode = CEOS_ASF_MAPREC_GCP_ORDER;
1552
5
    }
1553
5
    if (record == nullptr)
1554
5
    {
1555
5
        record = FindCeosRecord(sVolume.RecordList, LEADER_FACILITY_ASF_TC,
1556
5
                                CEOS_LEADER_FILE, -1, -1);
1557
5
        gcp_ordering_mode = CEOS_ASF_FACREC_GCP_ORDER;
1558
5
    }
1559
1560
5
    if (record == nullptr)
1561
5
        return FALSE;
1562
1563
0
    char szField[100];
1564
0
    memset(szField, 0, 17);
1565
0
    GetCeosField(record, 29, "A16", szField);
1566
1567
0
    int GCPFieldSize = 16;
1568
0
    int GCPOffset = 1073;
1569
1570
0
    if (!STARTS_WITH_CI(szField, "Slant Range") &&
1571
0
        !STARTS_WITH_CI(szField, "Ground Range") &&
1572
0
        !STARTS_WITH_CI(szField, "GEOCODED"))
1573
0
    {
1574
        /* detect ASF map projection record */
1575
0
        GetCeosField(record, 1079, "A7", szField);
1576
0
        if (!STARTS_WITH_CI(szField, "Slant") &&
1577
0
            !STARTS_WITH_CI(szField, "Ground"))
1578
0
        {
1579
0
            return FALSE;
1580
0
        }
1581
0
        else
1582
0
        {
1583
0
            GCPFieldSize = 17;
1584
0
            GCPOffset = 157;
1585
0
        }
1586
0
    }
1587
1588
0
    char FieldSize[4];
1589
0
    snprintf(FieldSize, sizeof(FieldSize), "A%d", GCPFieldSize);
1590
1591
0
    GetCeosField(record, GCPOffset, FieldSize, szField);
1592
0
    if (STARTS_WITH_CI(szField, "        "))
1593
0
        return FALSE;
1594
1595
    /* -------------------------------------------------------------------- */
1596
    /*      Read corner points.                                             */
1597
    /* -------------------------------------------------------------------- */
1598
0
    nGCPCount = 4;
1599
0
    pasGCPList = (GDAL_GCP *)CPLCalloc(sizeof(GDAL_GCP), nGCPCount);
1600
1601
0
    GDALInitGCPs(nGCPCount, pasGCPList);
1602
1603
0
    for (int i = 0; i < nGCPCount; i++)
1604
0
    {
1605
0
        char szId[32];
1606
1607
0
        snprintf(szId, sizeof(szId), "%d", i + 1);
1608
0
        CPLFree(pasGCPList[i].pszId);
1609
0
        pasGCPList[i].pszId = CPLStrdup(szId);
1610
1611
0
        GetCeosField(record, GCPOffset + (GCPFieldSize * 2) * i, FieldSize,
1612
0
                     szField);
1613
0
        pasGCPList[i].dfGCPY = CPLAtof(szField);
1614
0
        GetCeosField(record, GCPOffset + GCPFieldSize + (GCPFieldSize * 2) * i,
1615
0
                     FieldSize, szField);
1616
0
        pasGCPList[i].dfGCPX = CPLAtof(szField);
1617
0
        pasGCPList[i].dfGCPZ = 0.0;
1618
0
    }
1619
1620
    /* Map Projection Record has the order UL UR LR LL
1621
     ASF Facility Data Record has the order UL,LL,UR,LR
1622
     ASF Map Projection Record has the order LL, LR, UR, UL */
1623
1624
0
    pasGCPList[0].dfGCPLine = 0.5;
1625
0
    pasGCPList[0].dfGCPPixel = 0.5;
1626
1627
0
    switch (gcp_ordering_mode)
1628
0
    {
1629
0
        case CEOS_ASF_FACREC_GCP_ORDER:
1630
0
            pasGCPList[1].dfGCPLine = nRasterYSize - 0.5;
1631
0
            pasGCPList[1].dfGCPPixel = 0.5;
1632
1633
0
            pasGCPList[2].dfGCPLine = 0.5;
1634
0
            pasGCPList[2].dfGCPPixel = nRasterXSize - 0.5;
1635
1636
0
            pasGCPList[3].dfGCPLine = nRasterYSize - 0.5;
1637
0
            pasGCPList[3].dfGCPPixel = nRasterXSize - 0.5;
1638
0
            break;
1639
0
        case CEOS_STD_MAPREC_GCP_ORDER:
1640
0
            pasGCPList[1].dfGCPLine = 0.5;
1641
0
            pasGCPList[1].dfGCPPixel = nRasterXSize - 0.5;
1642
1643
0
            pasGCPList[2].dfGCPLine = nRasterYSize - 0.5;
1644
0
            pasGCPList[2].dfGCPPixel = nRasterXSize - 0.5;
1645
1646
0
            pasGCPList[3].dfGCPLine = nRasterYSize - 0.5;
1647
0
            pasGCPList[3].dfGCPPixel = 0.5;
1648
0
            break;
1649
0
        case CEOS_ASF_MAPREC_GCP_ORDER:
1650
0
            pasGCPList[0].dfGCPLine = nRasterYSize - 0.5;
1651
0
            pasGCPList[0].dfGCPPixel = 0.5;
1652
1653
0
            pasGCPList[1].dfGCPLine = nRasterYSize - 0.5;
1654
0
            pasGCPList[1].dfGCPPixel = nRasterXSize - 0.5;
1655
1656
0
            pasGCPList[2].dfGCPLine = 0.5;
1657
0
            pasGCPList[2].dfGCPPixel = nRasterXSize - 0.5;
1658
1659
0
            pasGCPList[3].dfGCPLine = 0.5;
1660
0
            pasGCPList[3].dfGCPPixel = 0.5;
1661
0
            break;
1662
0
    }
1663
1664
0
    return TRUE;
1665
0
}
1666
1667
/************************************************************************/
1668
/*                            ScanForGCPs()                             */
1669
/************************************************************************/
1670
1671
void SAR_CEOSDataset::ScanForGCPs()
1672
1673
10
{
1674
    /* -------------------------------------------------------------------- */
1675
    /*      Do we have a standard 180 bytes of prefix data (192 bytes       */
1676
    /*      including the record marker information)?  If not, it is        */
1677
    /*      unlikely that the GCPs are available.                           */
1678
    /* -------------------------------------------------------------------- */
1679
10
    if (sVolume.ImageDesc.ImageDataStart < 192)
1680
0
    {
1681
0
        ScanForMapProjection();
1682
0
        return;
1683
0
    }
1684
1685
    /* ASF L1 products do not have valid data
1686
       in the lat/long first/mid/last fields */
1687
10
    const char *pszValue = GetMetadataItem("CEOS_FACILITY");
1688
10
    if ((pszValue != nullptr) && (strncmp(pszValue, "ASF", 3) == 0))
1689
0
    {
1690
0
        ScanForMapProjection();
1691
0
        return;
1692
0
    }
1693
1694
    /* -------------------------------------------------------------------- */
1695
    /*      Just sample fix scanlines through the image for GCPs, to        */
1696
    /*      return 15 GCPs.  That is an adequate coverage for most          */
1697
    /*      purposes.  A GCP is collected from the beginning, middle and    */
1698
    /*      end of each scanline.                                           */
1699
    /* -------------------------------------------------------------------- */
1700
10
    nGCPCount = 0;
1701
10
    int nGCPMax = 15;
1702
10
    pasGCPList = (GDAL_GCP *)CPLCalloc(sizeof(GDAL_GCP), nGCPMax);
1703
1704
10
    int nStep = (GetRasterYSize() - 1) / (nGCPMax / 3 - 1);
1705
41
    for (int iScanline = 0; iScanline < GetRasterYSize(); iScanline += nStep)
1706
40
    {
1707
40
        if (nGCPCount > nGCPMax - 3)
1708
0
            break;
1709
1710
40
        int nFileOffset;
1711
40
        CalcCeosSARImageFilePosition(&sVolume, 1, iScanline + 1, nullptr,
1712
40
                                     &nFileOffset);
1713
1714
40
        GInt32 anRecord[192 / 4];
1715
40
        if (VSIFSeekL(fpImage, nFileOffset, SEEK_SET) != 0 ||
1716
40
            VSIFReadL(anRecord, 1, 192, fpImage) != 192)
1717
9
            break;
1718
1719
        /* loop over first, middle and last pixel gcps */
1720
1721
124
        for (int iGCP = 0; iGCP < 3; iGCP++)
1722
93
        {
1723
93
            const int nLat = CPL_MSBWORD32(anRecord[132 / 4 + iGCP]);
1724
93
            const int nLong = CPL_MSBWORD32(anRecord[144 / 4 + iGCP]);
1725
1726
93
            if (nLat != 0 || nLong != 0)
1727
31
            {
1728
31
                GDALInitGCPs(1, pasGCPList + nGCPCount);
1729
1730
31
                CPLFree(pasGCPList[nGCPCount].pszId);
1731
1732
31
                char szId[32];
1733
31
                snprintf(szId, sizeof(szId), "%d", nGCPCount + 1);
1734
31
                pasGCPList[nGCPCount].pszId = CPLStrdup(szId);
1735
1736
31
                pasGCPList[nGCPCount].dfGCPX = nLong / 1000000.0;
1737
31
                pasGCPList[nGCPCount].dfGCPY = nLat / 1000000.0;
1738
31
                pasGCPList[nGCPCount].dfGCPZ = 0.0;
1739
1740
31
                pasGCPList[nGCPCount].dfGCPLine = iScanline + 0.5;
1741
1742
31
                if (iGCP == 0)
1743
11
                    pasGCPList[nGCPCount].dfGCPPixel = 0.5;
1744
20
                else if (iGCP == 1)
1745
10
                    pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize() / 2.0;
1746
10
                else
1747
10
                    pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize() - 0.5;
1748
1749
31
                nGCPCount++;
1750
31
            }
1751
93
        }
1752
31
    }
1753
    /* If general GCP's were not found, look for Map Projection (e.g. JERS) */
1754
10
    if (nGCPCount == 0)
1755
5
    {
1756
5
        CPLFree(pasGCPList);
1757
5
        pasGCPList = nullptr;
1758
5
        ScanForMapProjection();
1759
5
        return;
1760
5
    }
1761
10
}
1762
1763
/************************************************************************/
1764
/*                                Open()                                */
1765
/************************************************************************/
1766
1767
GDALDataset *SAR_CEOSDataset::Open(GDALOpenInfo *poOpenInfo)
1768
1769
193k
{
1770
    /* -------------------------------------------------------------------- */
1771
    /*      Does this appear to be a valid ceos leader record?              */
1772
    /* -------------------------------------------------------------------- */
1773
193k
    if (poOpenInfo->nHeaderBytes < CEOS_HEADER_LENGTH ||
1774
193k
        poOpenInfo->fpL == nullptr)
1775
183k
        return nullptr;
1776
1777
9.84k
    if ((poOpenInfo->pabyHeader[4] != 0x3f &&
1778
9.84k
         poOpenInfo->pabyHeader[4] != 0x32) ||
1779
9.84k
        poOpenInfo->pabyHeader[5] != 0xc0 ||
1780
9.84k
        poOpenInfo->pabyHeader[6] != 0x12 || poOpenInfo->pabyHeader[7] != 0x12)
1781
9.80k
        return nullptr;
1782
1783
    // some products (#1862) have byte swapped record length/number
1784
    // values and will blow stuff up -- explicitly ignore if record index
1785
    // value appears to be little endian.
1786
34
    if (poOpenInfo->pabyHeader[0] != 0)
1787
7
        return nullptr;
1788
1789
    /* -------------------------------------------------------------------- */
1790
    /*      Confirm the requested access is supported.                      */
1791
    /* -------------------------------------------------------------------- */
1792
27
    if (poOpenInfo->eAccess == GA_Update)
1793
0
    {
1794
0
        ReportUpdateNotSupportedByDriver("SAR_CEOS");
1795
0
        return nullptr;
1796
0
    }
1797
1798
    /* -------------------------------------------------------------------- */
1799
    /*      Create a corresponding GDALDataset.                             */
1800
    /* -------------------------------------------------------------------- */
1801
1802
27
    auto poDS = std::make_unique<SAR_CEOSDataset>();
1803
27
    std::swap(poDS->fpImage, poOpenInfo->fpL);
1804
1805
27
    CeosSARVolume_t *psVolume = &(poDS->sVolume);
1806
27
    InitCeosSARVolume(psVolume, 0);
1807
1808
    /* -------------------------------------------------------------------- */
1809
    /*      Try to read the current file as an imagery file.                */
1810
    /* -------------------------------------------------------------------- */
1811
1812
27
    psVolume->ImagryOptionsFile = TRUE;
1813
27
    if (ProcessData(poDS->fpImage, CEOS_IMAGRY_OPT_FILE, psVolume, 4,
1814
27
                    VSI_L_OFFSET_MAX) != CE_None)
1815
9
    {
1816
9
        return nullptr;
1817
9
    }
1818
1819
    /* -------------------------------------------------------------------- */
1820
    /*      Try the various filenames.                                      */
1821
    /* -------------------------------------------------------------------- */
1822
18
    char *pszPath = CPLStrdup(CPLGetPathSafe(poOpenInfo->pszFilename).c_str());
1823
18
    char *pszBasename =
1824
18
        CPLStrdup(CPLGetBasenameSafe(poOpenInfo->pszFilename).c_str());
1825
18
    char *pszExtension =
1826
18
        CPLStrdup(CPLGetExtensionSafe(poOpenInfo->pszFilename).c_str());
1827
1828
18
    int nBand;
1829
18
    if (strlen(pszBasename) > 4)
1830
0
        nBand = atoi(pszBasename + 4);
1831
18
    else
1832
18
        nBand = 0;
1833
1834
108
    for (int iFile = 0; iFile < 5; iFile++)
1835
90
    {
1836
        /* skip image file ... we already did it */
1837
90
        if (iFile == 2)
1838
18
            continue;
1839
1840
72
        int e = 0;
1841
966
        while (CeosExtension[e][iFile] != nullptr)
1842
912
        {
1843
912
            std::string osFilename;
1844
1845
            /* build filename */
1846
912
            if (EQUAL(CeosExtension[e][5], "base"))
1847
216
            {
1848
216
                char szMadeBasename[32];
1849
1850
216
                snprintf(szMadeBasename, sizeof(szMadeBasename),
1851
216
                         CeosExtension[e][iFile], nBand);
1852
216
                osFilename =
1853
216
                    CPLFormFilenameSafe(pszPath, szMadeBasename, pszExtension);
1854
216
            }
1855
696
            else if (EQUAL(CeosExtension[e][5], "ext"))
1856
552
            {
1857
552
                osFilename = CPLFormFilenameSafe(pszPath, pszBasename,
1858
552
                                                 CeosExtension[e][iFile]);
1859
552
            }
1860
144
            else if (EQUAL(CeosExtension[e][5], "whole"))
1861
72
            {
1862
72
                osFilename =
1863
72
                    CPLFormFilenameSafe(pszPath, CeosExtension[e][iFile], "");
1864
72
            }
1865
1866
            // This is for SAR SLC as per the SAR Toolbox (from ASF).
1867
72
            else if (EQUAL(CeosExtension[e][5], "ext2"))
1868
72
            {
1869
72
                char szThisExtension[32];
1870
1871
72
                if (strlen(pszExtension) > 3)
1872
0
                    snprintf(szThisExtension, sizeof(szThisExtension), "%s%s",
1873
0
                             CeosExtension[e][iFile], pszExtension + 3);
1874
72
                else
1875
72
                    snprintf(szThisExtension, sizeof(szThisExtension), "%s",
1876
72
                             CeosExtension[e][iFile]);
1877
1878
72
                osFilename =
1879
72
                    CPLFormFilenameSafe(pszPath, pszBasename, szThisExtension);
1880
72
            }
1881
1882
            /* try to open */
1883
912
            VSILFILE *process_fp = VSIFOpenL(osFilename.c_str(), "rb");
1884
1885
            /* try upper case */
1886
912
            if (process_fp == nullptr)
1887
834
            {
1888
834
                for (int i = static_cast<int>(osFilename.size()) - 1;
1889
6.99k
                     i >= 0 && osFilename[i] != '/' && osFilename[i] != '\\';
1890
6.15k
                     i--)
1891
6.15k
                {
1892
6.15k
                    if (osFilename[i] >= 'a' && osFilename[i] <= 'z')
1893
4.90k
                        osFilename[i] = osFilename[i] - 'a' + 'A';
1894
6.15k
                }
1895
1896
834
                process_fp = VSIFOpenL(osFilename.c_str(), "rb");
1897
834
            }
1898
1899
912
            if (process_fp != nullptr)
1900
78
            {
1901
78
                CPLDebug("CEOS", "Opened %s.\n", osFilename.c_str());
1902
1903
78
                poDS->papszExtraFiles =
1904
78
                    CSLAddString(poDS->papszExtraFiles, osFilename.c_str());
1905
1906
78
                CPL_IGNORE_RET_VAL(VSIFSeekL(process_fp, 0, SEEK_END));
1907
78
                if (ProcessData(process_fp, iFile, psVolume, -1,
1908
78
                                VSIFTellL(process_fp)) == 0)
1909
18
                {
1910
18
                    switch (iFile)
1911
18
                    {
1912
6
                        case 0:
1913
6
                            psVolume->VolumeDirectoryFile = TRUE;
1914
6
                            break;
1915
0
                        case 1:
1916
0
                            psVolume->SARLeaderFile = TRUE;
1917
0
                            break;
1918
6
                        case 3:
1919
6
                            psVolume->SARTrailerFile = TRUE;
1920
6
                            break;
1921
6
                        case 4:
1922
6
                            psVolume->NullVolumeDirectoryFile = TRUE;
1923
6
                            break;
1924
18
                    }
1925
1926
18
                    CPL_IGNORE_RET_VAL(VSIFCloseL(process_fp));
1927
18
                    break; /* Exit the while loop, we have this data type*/
1928
18
                }
1929
1930
60
                CPL_IGNORE_RET_VAL(VSIFCloseL(process_fp));
1931
60
            }
1932
1933
894
            e++;
1934
894
        }
1935
72
    }
1936
1937
18
    CPLFree(pszPath);
1938
18
    CPLFree(pszBasename);
1939
18
    CPLFree(pszExtension);
1940
1941
    /* -------------------------------------------------------------------- */
1942
    /*      Check that we have an image description.                        */
1943
    /* -------------------------------------------------------------------- */
1944
18
    GetCeosSARImageDesc(psVolume);
1945
18
    struct CeosSARImageDesc *psImageDesc = &(psVolume->ImageDesc);
1946
18
    if (!psImageDesc->ImageDescValid)
1947
8
    {
1948
8
        CPLDebug("CEOS",
1949
8
                 "Unable to extract CEOS image description\n"
1950
8
                 "from %s.",
1951
8
                 poOpenInfo->pszFilename);
1952
1953
8
        return nullptr;
1954
8
    }
1955
1956
    /* -------------------------------------------------------------------- */
1957
    /*      Establish image type.                                           */
1958
    /* -------------------------------------------------------------------- */
1959
10
    GDALDataType eType;
1960
1961
10
    switch (psImageDesc->DataType)
1962
10
    {
1963
0
        case CEOS_TYP_CHAR:
1964
9
        case CEOS_TYP_UCHAR:
1965
9
            eType = GDT_Byte;
1966
9
            break;
1967
1968
0
        case CEOS_TYP_SHORT:
1969
0
            eType = GDT_Int16;
1970
0
            break;
1971
1972
0
        case CEOS_TYP_COMPLEX_SHORT:
1973
0
        case CEOS_TYP_PALSAR_COMPLEX_SHORT:
1974
0
            eType = GDT_CInt16;
1975
0
            break;
1976
1977
1
        case CEOS_TYP_USHORT:
1978
1
            eType = GDT_UInt16;
1979
1
            break;
1980
1981
0
        case CEOS_TYP_LONG:
1982
0
            eType = GDT_Int32;
1983
0
            break;
1984
1985
0
        case CEOS_TYP_ULONG:
1986
0
            eType = GDT_UInt32;
1987
0
            break;
1988
1989
0
        case CEOS_TYP_FLOAT:
1990
0
            eType = GDT_Float32;
1991
0
            break;
1992
1993
0
        case CEOS_TYP_DOUBLE:
1994
0
            eType = GDT_Float64;
1995
0
            break;
1996
1997
0
        case CEOS_TYP_COMPLEX_FLOAT:
1998
0
        case CEOS_TYP_CCP_COMPLEX_FLOAT:
1999
0
            eType = GDT_CFloat32;
2000
0
            break;
2001
2002
0
        default:
2003
0
            CPLError(CE_Failure, CPLE_AppDefined,
2004
0
                     "Unsupported CEOS image data type %d.\n",
2005
0
                     psImageDesc->DataType);
2006
0
            return nullptr;
2007
10
    }
2008
2009
    /* -------------------------------------------------------------------- */
2010
    /*      Capture some information from the file that is of interest.     */
2011
    /* -------------------------------------------------------------------- */
2012
10
    poDS->nRasterXSize = psImageDesc->PixelsPerLine +
2013
10
                         psImageDesc->LeftBorderPixels +
2014
10
                         psImageDesc->RightBorderPixels;
2015
10
    poDS->nRasterYSize = psImageDesc->Lines;
2016
2017
    /* -------------------------------------------------------------------- */
2018
    /*      Special case for compressed cross products.                     */
2019
    /* -------------------------------------------------------------------- */
2020
10
    if (psImageDesc->DataType == CEOS_TYP_CCP_COMPLEX_FLOAT)
2021
0
    {
2022
0
        for (int iBand = 0; iBand < psImageDesc->NumChannels; iBand++)
2023
0
        {
2024
0
            poDS->SetBand(
2025
0
                poDS->nBands + 1,
2026
0
                new CCPRasterBand(poDS.get(), poDS->nBands + 1, eType));
2027
0
        }
2028
2029
        /* mark this as a Scattering Matrix product */
2030
0
        if (poDS->GetRasterCount() == 4)
2031
0
        {
2032
0
            poDS->SetMetadataItem("MATRIX_REPRESENTATION", "SCATTERING");
2033
0
        }
2034
0
    }
2035
2036
    /* -------------------------------------------------------------------- */
2037
    /*      Special case for PALSAR data.                                   */
2038
    /* -------------------------------------------------------------------- */
2039
10
    else if (psImageDesc->DataType == CEOS_TYP_PALSAR_COMPLEX_SHORT)
2040
0
    {
2041
0
        for (int iBand = 0; iBand < psImageDesc->NumChannels; iBand++)
2042
0
        {
2043
0
            poDS->SetBand(poDS->nBands + 1,
2044
0
                          new PALSARRasterBand(poDS.get(), poDS->nBands + 1));
2045
0
        }
2046
2047
        /* mark this as a Symmetrized Covariance product if appropriate */
2048
0
        if (poDS->GetRasterCount() == 6)
2049
0
        {
2050
0
            poDS->SetMetadataItem("MATRIX_REPRESENTATION",
2051
0
                                  "SYMMETRIZED_COVARIANCE");
2052
0
        }
2053
0
    }
2054
2055
    /* -------------------------------------------------------------------- */
2056
    /*      Roll our own ...                                                */
2057
    /* -------------------------------------------------------------------- */
2058
10
    else if (psImageDesc->RecordsPerLine > 1 ||
2059
10
             psImageDesc->DataType == CEOS_TYP_CHAR ||
2060
10
             psImageDesc->DataType == CEOS_TYP_LONG ||
2061
10
             psImageDesc->DataType == CEOS_TYP_ULONG ||
2062
10
             psImageDesc->DataType == CEOS_TYP_DOUBLE)
2063
0
    {
2064
0
        for (int iBand = 0; iBand < psImageDesc->NumChannels; iBand++)
2065
0
        {
2066
0
            poDS->SetBand(
2067
0
                poDS->nBands + 1,
2068
0
                new SAR_CEOSRasterBand(poDS.get(), poDS->nBands + 1, eType));
2069
0
        }
2070
0
    }
2071
2072
    /* -------------------------------------------------------------------- */
2073
    /*      Use raw services for well behaved files.                        */
2074
    /* -------------------------------------------------------------------- */
2075
10
    else
2076
10
    {
2077
10
        int StartData;
2078
10
        CalcCeosSARImageFilePosition(psVolume, 1, 1, nullptr, &StartData);
2079
2080
        /*StartData += psImageDesc->ImageDataStart; */
2081
2082
10
        int nLineSize, nLineSize2;
2083
10
        CalcCeosSARImageFilePosition(psVolume, 1, 1, nullptr, &nLineSize);
2084
10
        CalcCeosSARImageFilePosition(psVolume, 1, 2, nullptr, &nLineSize2);
2085
2086
10
        nLineSize = nLineSize2 - nLineSize;
2087
2088
21
        for (int iBand = 0; iBand < psImageDesc->NumChannels; iBand++)
2089
11
        {
2090
11
            int nStartData, nPixelOffset, nLineOffset;
2091
2092
11
            if (psImageDesc->ChannelInterleaving == CEOS_IL_PIXEL)
2093
0
            {
2094
0
                CalcCeosSARImageFilePosition(psVolume, 1, 1, nullptr,
2095
0
                                             &nStartData);
2096
2097
0
                nStartData += psImageDesc->ImageDataStart;
2098
0
                nStartData += psImageDesc->BytesPerPixel * iBand;
2099
2100
0
                nPixelOffset =
2101
0
                    psImageDesc->BytesPerPixel * psImageDesc->NumChannels;
2102
0
                nLineOffset = nLineSize;
2103
0
            }
2104
11
            else if (psImageDesc->ChannelInterleaving == CEOS_IL_LINE)
2105
0
            {
2106
0
                CalcCeosSARImageFilePosition(psVolume, iBand + 1, 1, nullptr,
2107
0
                                             &nStartData);
2108
2109
0
                nStartData += psImageDesc->ImageDataStart;
2110
0
                nPixelOffset = psImageDesc->BytesPerPixel;
2111
0
                nLineOffset = nLineSize * psImageDesc->NumChannels;
2112
0
            }
2113
11
            else if (psImageDesc->ChannelInterleaving == CEOS_IL_BAND)
2114
11
            {
2115
11
                CalcCeosSARImageFilePosition(psVolume, iBand + 1, 1, nullptr,
2116
11
                                             &nStartData);
2117
2118
11
                nStartData += psImageDesc->ImageDataStart;
2119
11
                nPixelOffset = psImageDesc->BytesPerPixel;
2120
11
                nLineOffset = nLineSize;
2121
11
            }
2122
0
            else
2123
0
            {
2124
0
                CPLAssert(false);
2125
0
                return nullptr;
2126
0
            }
2127
2128
11
            auto poBand = RawRasterBand::Create(
2129
11
                poDS.get(), poDS->nBands + 1, poDS->fpImage, nStartData,
2130
11
                nPixelOffset, nLineOffset, eType,
2131
11
                RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
2132
11
                RawRasterBand::OwnFP::NO);
2133
11
            if (!poBand)
2134
0
                return nullptr;
2135
11
            poDS->SetBand(poDS->nBands + 1, std::move(poBand));
2136
11
        }
2137
10
    }
2138
2139
    /* -------------------------------------------------------------------- */
2140
    /*      Collect metadata.                                               */
2141
    /* -------------------------------------------------------------------- */
2142
10
    poDS->ScanForMetadata();
2143
2144
    /* -------------------------------------------------------------------- */
2145
    /*      Check for GCPs.                                                 */
2146
    /* -------------------------------------------------------------------- */
2147
10
    poDS->ScanForGCPs();
2148
2149
    /* -------------------------------------------------------------------- */
2150
    /*      Initialize any PAM information.                                 */
2151
    /* -------------------------------------------------------------------- */
2152
10
    poDS->SetDescription(poOpenInfo->pszFilename);
2153
10
    poDS->TryLoadXML();
2154
2155
    /* -------------------------------------------------------------------- */
2156
    /*      Open overviews.                                                 */
2157
    /* -------------------------------------------------------------------- */
2158
10
    poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
2159
2160
10
    return poDS.release();
2161
10
}
2162
2163
/************************************************************************/
2164
/*                            ProcessData()                             */
2165
/************************************************************************/
2166
static int ProcessData(VSILFILE *fp, int fileid, CeosSARVolume_t *sar,
2167
                       int max_records, vsi_l_offset max_bytes)
2168
2169
105
{
2170
105
    unsigned char temp_buffer[CEOS_HEADER_LENGTH];
2171
105
    unsigned char *temp_body = nullptr;
2172
105
    int start = 0;
2173
105
    int CurrentBodyLength = 0;
2174
105
    int CurrentType = 0;
2175
105
    int CurrentSequence = 0;
2176
105
    int iThisRecord = 0;
2177
2178
575
    while (max_records != 0 && max_bytes != 0)
2179
539
    {
2180
539
        iThisRecord++;
2181
2182
539
        if (VSIFSeekL(fp, start, SEEK_SET) != 0 ||
2183
539
            VSIFReadL(temp_buffer, 1, CEOS_HEADER_LENGTH, fp) !=
2184
539
                CEOS_HEADER_LENGTH)
2185
5
        {
2186
5
            CPLError(CE_Failure, CPLE_AppDefined,
2187
5
                     "Corrupt CEOS File - cannot read record %d.", iThisRecord);
2188
5
            CPLFree(temp_body);
2189
5
            return CE_Failure;
2190
5
        }
2191
534
        CeosRecord_t *record = (CeosRecord_t *)CPLMalloc(sizeof(CeosRecord_t));
2192
534
        record->Length = DetermineCeosRecordBodyLength(temp_buffer);
2193
2194
534
        CeosToNative(&(record->Sequence), temp_buffer, 4, 4);
2195
2196
534
        if (iThisRecord != record->Sequence)
2197
45
        {
2198
45
            if (fileid == CEOS_IMAGRY_OPT_FILE && iThisRecord == 2)
2199
3
            {
2200
3
                CPLDebug("SAR_CEOS",
2201
3
                         "Ignoring CEOS file with wrong second record sequence "
2202
3
                         "number - likely it has padded records.");
2203
3
                CPLFree(record);
2204
3
                CPLFree(temp_body);
2205
3
                return CE_Warning;
2206
3
            }
2207
42
            else
2208
42
            {
2209
42
                CPLError(CE_Failure, CPLE_AppDefined,
2210
42
                         "Corrupt CEOS File - got record seq# %d instead of "
2211
42
                         "the expected %d.",
2212
42
                         record->Sequence, iThisRecord);
2213
42
                CPLFree(record);
2214
42
                CPLFree(temp_body);
2215
42
                return CE_Failure;
2216
42
            }
2217
45
        }
2218
2219
489
        if (record->Length <= CEOS_HEADER_LENGTH)
2220
1
        {
2221
1
            CPLError(CE_Failure, CPLE_AppDefined,
2222
1
                     "Corrupt CEOS File - cannot read record %d.", iThisRecord);
2223
1
            CPLFree(record);
2224
1
            CPLFree(temp_body);
2225
1
            return CE_Failure;
2226
1
        }
2227
2228
488
        if (record->Length > CurrentBodyLength)
2229
189
        {
2230
189
            unsigned char *temp_body_new =
2231
189
                (unsigned char *)VSI_REALLOC_VERBOSE(temp_body, record->Length);
2232
189
            if (temp_body_new == nullptr)
2233
0
            {
2234
0
                CPLFree(record);
2235
0
                CPLFree(temp_body);
2236
0
                return CE_Failure;
2237
0
            }
2238
189
            temp_body = temp_body_new;
2239
189
            CurrentBodyLength = record->Length;
2240
189
        }
2241
2242
488
        int nToRead = record->Length - CEOS_HEADER_LENGTH;
2243
488
        if ((int)VSIFReadL(temp_body, 1, nToRead, fp) != nToRead)
2244
18
        {
2245
18
            CPLError(CE_Failure, CPLE_AppDefined,
2246
18
                     "Corrupt CEOS File - cannot read record %d.", iThisRecord);
2247
18
            CPLFree(record);
2248
18
            CPLFree(temp_body);
2249
18
            return CE_Failure;
2250
18
        }
2251
2252
470
        InitCeosRecordWithHeader(record, temp_buffer, temp_body);
2253
470
        if (record->Length == 0)
2254
0
        {
2255
0
            CPLError(CE_Failure, CPLE_AppDefined,
2256
0
                     "Corrupt CEOS File - invalid record %d.", iThisRecord);
2257
0
            CPLFree(record);
2258
0
            CPLFree(temp_body);
2259
0
            return CE_Failure;
2260
0
        }
2261
2262
470
        if (CurrentType == record->TypeCode.Int32Code)
2263
139
            record->Subsequence = ++CurrentSequence;
2264
331
        else
2265
331
        {
2266
331
            CurrentType = record->TypeCode.Int32Code;
2267
331
            record->Subsequence = 0;
2268
331
            CurrentSequence = 0;
2269
331
        }
2270
2271
470
        record->FileId = fileid;
2272
2273
470
        Link_t *TheLink = ceos2CreateLink(record);
2274
2275
470
        if (sar->RecordList == nullptr)
2276
25
            sar->RecordList = TheLink;
2277
445
        else
2278
445
            sar->RecordList = InsertLink(sar->RecordList, TheLink);
2279
2280
470
        start += record->Length;
2281
2282
470
        if (max_records > 0)
2283
85
            max_records--;
2284
470
        if (max_bytes > 0)
2285
470
        {
2286
470
            if ((vsi_l_offset)record->Length <= max_bytes)
2287
470
                max_bytes -= record->Length;
2288
0
            else
2289
0
            {
2290
0
                CPLDebug("SAR_CEOS",
2291
0
                         "Partial record found.  %d > " CPL_FRMT_GUIB,
2292
0
                         record->Length, max_bytes);
2293
0
                max_bytes = 0;
2294
0
            }
2295
470
        }
2296
470
    }
2297
2298
36
    CPLFree(temp_body);
2299
2300
36
    return CE_None;
2301
105
}
2302
2303
/************************************************************************/
2304
/*                       GDALRegister_SAR_CEOS()                        */
2305
/************************************************************************/
2306
2307
void GDALRegister_SAR_CEOS()
2308
2309
2
{
2310
2
    if (GDALGetDriverByName("SAR_CEOS") != nullptr)
2311
0
        return;
2312
2313
2
    GDALDriver *poDriver = new GDALDriver();
2314
2315
2
    poDriver->SetDescription("SAR_CEOS");
2316
2
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
2317
2
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "CEOS SAR Image");
2318
2
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
2319
2
                              "drivers/raster/sar_ceos.html");
2320
2
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
2321
2322
2
    poDriver->pfnOpen = SAR_CEOSDataset::Open;
2323
2324
2
    GetGDALDriverManager()->RegisterDriver(poDriver);
2325
2
}
2326
2327
/************************************************************************/
2328
/*                            GetFileList()                             */
2329
/************************************************************************/
2330
2331
char **SAR_CEOSDataset::GetFileList()
2332
2333
20
{
2334
20
    char **papszFileList = GDALPamDataset::GetFileList();
2335
2336
20
    papszFileList = CSLInsertStrings(papszFileList, -1, papszExtraFiles);
2337
2338
20
    return papszFileList;
2339
20
}