Coverage Report

Created: 2025-06-09 08:44

/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
257
{
73
257
    CeosTypeCode_t abcd;
74
75
257
    abcd.UCharCode.Subtype1 = (unsigned char)a;
76
257
    abcd.UCharCode.Type = (unsigned char)b;
77
257
    abcd.UCharCode.Subtype2 = (unsigned char)c;
78
257
    abcd.UCharCode.Subtype3 = (unsigned char)d;
79
80
257
    return abcd;
81
257
}
82
83
30
#define LEADER_DATASET_SUMMARY_TC QuadToTC(18, 10, 18, 20)
84
15
#define LEADER_DATASET_SUMMARY_ERS2_TC QuadToTC(10, 10, 31, 20)
85
15
#define LEADER_RADIOMETRIC_COMPENSATION_TC QuadToTC(18, 51, 18, 20)
86
15
#define VOLUME_DESCRIPTOR_RECORD_TC QuadToTC(192, 192, 18, 18)
87
15
#define IMAGE_HEADER_RECORD_TC QuadToTC(63, 192, 18, 18)
88
30
#define LEADER_RADIOMETRIC_DATA_RECORD_TC QuadToTC(18, 50, 18, 20)
89
8
#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
8
#define LEADER_MAP_PROJ_RECORD_JERS_TC QuadToTC(18, 20, 18, 20)
95
96
/* Leader from ASF has different identifiers */
97
8
#define LEADER_MAP_PROJ_RECORD_ASF_TC QuadToTC(10, 20, 18, 20)
98
15
#define LEADER_DATASET_SUMMARY_ASF_TC QuadToTC(10, 10, 18, 20)
99
8
#define LEADER_FACILITY_ASF_TC QuadToTC(90, 210, 18, 61)
100
101
/* For ERS calibration and incidence angle information */
102
15
#define ERS_GENERAL_FACILITY_DATA_TC QuadToTC(10, 200, 31, 50)
103
15
#define ERS_GENERAL_FACILITY_DATA_ALT_TC QuadToTC(10, 216, 31, 50)
104
105
30
#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
35
    : fpImage(nullptr), papszTempMD(nullptr), nGCPCount(0), pasGCPList(nullptr),
625
35
      papszExtraFiles(nullptr)
626
35
{
627
35
    m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
628
35
    m_oSRS.importFromWkt(SRS_WKT_WGS84_LAT_LONG);
629
630
35
    sVolume.Flavor = 0;
631
35
    sVolume.Sensor = 0;
632
35
    sVolume.ProductType = 0;
633
35
    sVolume.FileNamingConvention = 0;
634
635
35
    sVolume.VolumeDirectoryFile = 0;
636
35
    sVolume.SARLeaderFile = 0;
637
35
    sVolume.ImagryOptionsFile = 0;
638
35
    sVolume.SARTrailerFile = 0;
639
35
    sVolume.NullVolumeDirectoryFile = 0;
640
641
35
    sVolume.ImageDesc.ImageDescValid = 0;
642
35
    sVolume.ImageDesc.NumChannels = 0;
643
35
    sVolume.ImageDesc.ChannelInterleaving = 0;
644
35
    sVolume.ImageDesc.DataType = 0;
645
35
    sVolume.ImageDesc.BytesPerRecord = 0;
646
35
    sVolume.ImageDesc.Lines = 0;
647
35
    sVolume.ImageDesc.TopBorderPixels = 0;
648
35
    sVolume.ImageDesc.BottomBorderPixels = 0;
649
35
    sVolume.ImageDesc.PixelsPerLine = 0;
650
35
    sVolume.ImageDesc.LeftBorderPixels = 0;
651
35
    sVolume.ImageDesc.RightBorderPixels = 0;
652
35
    sVolume.ImageDesc.BytesPerPixel = 0;
653
35
    sVolume.ImageDesc.RecordsPerLine = 0;
654
35
    sVolume.ImageDesc.PixelsPerRecord = 0;
655
35
    sVolume.ImageDesc.ImageDataStart = 0;
656
35
    sVolume.ImageDesc.ImageSuffixData = 0;
657
35
    sVolume.ImageDesc.FileDescriptorLength = 0;
658
35
    sVolume.ImageDesc.PixelOrder = 0;
659
35
    sVolume.ImageDesc.LineOrder = 0;
660
35
    sVolume.ImageDesc.PixelDataBytesPerRecord = 0;
661
662
35
    sVolume.RecordList = nullptr;
663
35
}
664
665
/************************************************************************/
666
/*                          ~SAR_CEOSDataset()                          */
667
/************************************************************************/
668
669
SAR_CEOSDataset::~SAR_CEOSDataset()
670
671
35
{
672
35
    FlushCache(true);
673
674
35
    CSLDestroy(papszTempMD);
675
676
35
    if (fpImage != nullptr)
677
35
        CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
678
679
35
    if (nGCPCount > 0)
680
7
    {
681
7
        GDALDeinitGCPs(nGCPCount, pasGCPList);
682
7
    }
683
35
    CPLFree(pasGCPList);
684
685
35
    if (sVolume.RecordList)
686
33
    {
687
532
        for (Link_t *Links = sVolume.RecordList; Links != nullptr;
688
499
             Links = Links->next)
689
499
        {
690
499
            if (Links->object)
691
499
            {
692
499
                DeleteCeosRecord((CeosRecord_t *)Links->object);
693
499
                Links->object = nullptr;
694
499
            }
695
499
        }
696
33
        DestroyList(sVolume.RecordList);
697
33
    }
698
35
    FreeRecipes();
699
35
    CSLDestroy(papszExtraFiles);
700
35
}
701
702
/************************************************************************/
703
/*                            GetGCPCount()                             */
704
/************************************************************************/
705
706
int SAR_CEOSDataset::GetGCPCount()
707
708
15
{
709
15
    return nGCPCount;
710
15
}
711
712
/************************************************************************/
713
/*                          GetGCPSpatialRef()                          */
714
/************************************************************************/
715
716
const OGRSpatialReference *SAR_CEOSDataset::GetGCPSpatialRef() const
717
718
15
{
719
15
    if (nGCPCount > 0)
720
7
        return &m_oSRS;
721
722
8
    return nullptr;
723
15
}
724
725
/************************************************************************/
726
/*                               GetGCP()                               */
727
/************************************************************************/
728
729
const GDAL_GCP *SAR_CEOSDataset::GetGCPs()
730
731
15
{
732
15
    return pasGCPList;
733
15
}
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
31
{
768
31
    if (pszDomain == nullptr || !STARTS_WITH_CI(pszDomain, "ceos-"))
769
31
        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
15
{
863
    /* -------------------------------------------------------------------- */
864
    /*      Get the volume id (with the sensor name)                        */
865
    /* -------------------------------------------------------------------- */
866
15
    CeosRecord_t *record =
867
15
        FindCeosRecord(sVolume.RecordList, VOLUME_DESCRIPTOR_RECORD_TC,
868
15
                       CEOS_VOLUME_DIR_FILE, -1, -1);
869
870
15
    char szVolId[128];
871
15
    szVolId[0] = '\0';
872
15
    char szField[128];
873
15
    szField[0] = '\0';
874
15
    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
15
    record = FindCeosRecord(sVolume.RecordList, LEADER_DATASET_SUMMARY_TC,
960
15
                            CEOS_LEADER_FILE, -1, -1);
961
962
15
    if (record == nullptr)
963
15
        record =
964
15
            FindCeosRecord(sVolume.RecordList, LEADER_DATASET_SUMMARY_ASF_TC,
965
15
                           CEOS_LEADER_FILE, -1, -1);
966
967
15
    if (record == nullptr)
968
15
        record = FindCeosRecord(sVolume.RecordList, LEADER_DATASET_SUMMARY_TC,
969
15
                                CEOS_TRAILER_FILE, -1, -1);
970
971
15
    if (record == nullptr)
972
15
        record =
973
15
            FindCeosRecord(sVolume.RecordList, LEADER_DATASET_SUMMARY_ERS2_TC,
974
15
                           CEOS_LEADER_FILE, -1, -1);
975
976
15
    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
15
    record =
1198
15
        FindCeosRecord(sVolume.RecordList, LEADER_RADIOMETRIC_COMPENSATION_TC,
1199
15
                       CEOS_LEADER_FILE, -1, -1);
1200
1201
15
    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
15
    record = FindCeosRecord(sVolume.RecordList, ERS_GENERAL_FACILITY_DATA_TC,
1214
15
                            CEOS_LEADER_FILE, -1, -1);
1215
1216
15
    if (record == nullptr)
1217
15
        record =
1218
15
            FindCeosRecord(sVolume.RecordList, ERS_GENERAL_FACILITY_DATA_ALT_TC,
1219
15
                           CEOS_LEADER_FILE, -1, -1);
1220
1221
15
    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
15
    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
15
    record = FindCeosRecord(sVolume.RecordList, RSAT_PROC_PARAM_TC,
1285
15
                            CEOS_LEADER_FILE, -1, -1);
1286
1287
15
    if (record == nullptr)
1288
15
        record = FindCeosRecord(sVolume.RecordList, RSAT_PROC_PARAM_TC,
1289
15
                                CEOS_TRAILER_FILE, -1, -1);
1290
1291
15
    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
15
    record = FindCeosRecord(sVolume.RecordList, IMAGE_HEADER_RECORD_TC,
1400
15
                            CEOS_IMAGRY_OPT_FILE, -1, -1);
1401
1402
15
    if (record != nullptr)
1403
15
    {
1404
15
        GetCeosField(record, 449, "A4", szField);
1405
15
        szField[4] = '\0';
1406
1407
15
        if (!STARTS_WITH_CI(szField, "    "))
1408
3
            SetMetadataItem("CEOS_DM_CORNER", szField);
1409
1410
15
        GetCeosField(record, 453, "A4", szField);
1411
15
        szField[4] = '\0';
1412
1413
15
        if (!STARTS_WITH_CI(szField, "    "))
1414
3
            SetMetadataItem("CEOS_DM_TRANSPOSE", szField);
1415
1416
15
        GetCeosField(record, 457, "A4", szField);
1417
15
        szField[4] = '\0';
1418
1419
15
        if (!STARTS_WITH_CI(szField, "    "))
1420
3
            SetMetadataItem("CEOS_DM_START_SAMPLE", szField);
1421
1422
15
        GetCeosField(record, 461, "A5", szField);
1423
15
        szField[5] = '\0';
1424
1425
15
        if (!STARTS_WITH_CI(szField, "     "))
1426
3
            SetMetadataItem("CEOS_DM_START_PULSE", szField);
1427
1428
15
        GetCeosField(record, 466, "A16", szField);
1429
15
        szField[16] = '\0';
1430
1431
15
        if (!STARTS_WITH_CI(szField, "                "))
1432
3
            SetMetadataItem("CEOS_DM_FAST_ALPHA", szField);
1433
1434
15
        GetCeosField(record, 482, "A16", szField);
1435
15
        szField[16] = '\0';
1436
1437
15
        if (!STARTS_WITH_CI(szField, "                "))
1438
3
            SetMetadataItem("CEOS_DM_FAST_BETA", szField);
1439
1440
15
        GetCeosField(record, 498, "A16", szField);
1441
15
        szField[16] = '\0';
1442
1443
15
        if (!STARTS_WITH_CI(szField, "                "))
1444
3
            SetMetadataItem("CEOS_DM_SLOW_ALPHA", szField);
1445
1446
15
        GetCeosField(record, 514, "A16", szField);
1447
15
        szField[16] = '\0';
1448
1449
15
        if (!STARTS_WITH_CI(szField, "                "))
1450
3
            SetMetadataItem("CEOS_DM_SLOW_BETA", szField);
1451
1452
15
        GetCeosField(record, 530, "A16", szField);
1453
15
        szField[16] = '\0';
1454
1455
15
        if (!STARTS_WITH_CI(szField, "                "))
1456
3
            SetMetadataItem("CEOS_DM_FAST_ALPHA_2", szField);
1457
15
    }
1458
1459
    /* -------------------------------------------------------------------- */
1460
    /*      Try to find calibration information from Radiometric Data       */
1461
    /*      Record.                                                         */
1462
    /* -------------------------------------------------------------------- */
1463
15
    record =
1464
15
        FindCeosRecord(sVolume.RecordList, LEADER_RADIOMETRIC_DATA_RECORD_TC,
1465
15
                       CEOS_LEADER_FILE, -1, -1);
1466
1467
15
    if (record == nullptr)
1468
15
        record = FindCeosRecord(sVolume.RecordList,
1469
15
                                LEADER_RADIOMETRIC_DATA_RECORD_TC,
1470
15
                                CEOS_TRAILER_FILE, -1, -1);
1471
1472
15
    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
15
    record =
1487
15
        FindCeosRecord(sVolume.RecordList, QuadToTC(0x3f, 0x24, 0x12, 0x09),
1488
15
                       CEOS_LEADER_FILE, -1, -1);
1489
15
    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
15
    record =
1509
15
        FindCeosRecord(sVolume.RecordList, QuadToTC(0x12, 0x12, 0x12, 0x09),
1510
15
                       CEOS_LEADER_FILE, -1, -1);
1511
15
    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
15
}
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
8
{
1531
    /* -------------------------------------------------------------------- */
1532
    /*      Find record, and try to determine if it has useful GCPs.        */
1533
    /* -------------------------------------------------------------------- */
1534
1535
8
    CeosRecord_t *record =
1536
8
        FindCeosRecord(sVolume.RecordList, LEADER_MAP_PROJ_RECORD_TC,
1537
8
                       CEOS_LEADER_FILE, -1, -1);
1538
1539
8
    int gcp_ordering_mode = CEOS_STD_MAPREC_GCP_ORDER;
1540
    /* JERS from Japan */
1541
8
    if (record == nullptr)
1542
8
        record =
1543
8
            FindCeosRecord(sVolume.RecordList, LEADER_MAP_PROJ_RECORD_JERS_TC,
1544
8
                           CEOS_LEADER_FILE, -1, -1);
1545
1546
8
    if (record == nullptr)
1547
8
    {
1548
8
        record =
1549
8
            FindCeosRecord(sVolume.RecordList, LEADER_MAP_PROJ_RECORD_ASF_TC,
1550
8
                           CEOS_LEADER_FILE, -1, -1);
1551
8
        gcp_ordering_mode = CEOS_ASF_MAPREC_GCP_ORDER;
1552
8
    }
1553
8
    if (record == nullptr)
1554
8
    {
1555
8
        record = FindCeosRecord(sVolume.RecordList, LEADER_FACILITY_ASF_TC,
1556
8
                                CEOS_LEADER_FILE, -1, -1);
1557
8
        gcp_ordering_mode = CEOS_ASF_FACREC_GCP_ORDER;
1558
8
    }
1559
1560
8
    if (record == nullptr)
1561
8
        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
15
{
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
15
    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
15
    const char *pszValue = GetMetadataItem("CEOS_FACILITY");
1688
15
    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
15
    nGCPCount = 0;
1701
15
    int nGCPMax = 15;
1702
15
    pasGCPList = (GDAL_GCP *)CPLCalloc(sizeof(GDAL_GCP), nGCPMax);
1703
1704
15
    int nStep = (GetRasterYSize() - 1) / (nGCPMax / 3 - 1);
1705
51
    for (int iScanline = 0; iScanline < GetRasterYSize(); iScanline += nStep)
1706
50
    {
1707
50
        if (nGCPCount > nGCPMax - 3)
1708
0
            break;
1709
1710
50
        int nFileOffset;
1711
50
        CalcCeosSARImageFilePosition(&sVolume, 1, iScanline + 1, nullptr,
1712
50
                                     &nFileOffset);
1713
1714
50
        GInt32 anRecord[192 / 4];
1715
50
        if (VSIFSeekL(fpImage, nFileOffset, SEEK_SET) != 0 ||
1716
50
            VSIFReadL(anRecord, 1, 192, fpImage) != 192)
1717
14
            break;
1718
1719
        /* loop over first, middle and last pixel gcps */
1720
1721
144
        for (int iGCP = 0; iGCP < 3; iGCP++)
1722
108
        {
1723
108
            const int nLat = CPL_MSBWORD32(anRecord[132 / 4 + iGCP]);
1724
108
            const int nLong = CPL_MSBWORD32(anRecord[144 / 4 + iGCP]);
1725
1726
108
            if (nLat != 0 || nLong != 0)
1727
37
            {
1728
37
                GDALInitGCPs(1, pasGCPList + nGCPCount);
1729
1730
37
                CPLFree(pasGCPList[nGCPCount].pszId);
1731
1732
37
                char szId[32];
1733
37
                snprintf(szId, sizeof(szId), "%d", nGCPCount + 1);
1734
37
                pasGCPList[nGCPCount].pszId = CPLStrdup(szId);
1735
1736
37
                pasGCPList[nGCPCount].dfGCPX = nLong / 1000000.0;
1737
37
                pasGCPList[nGCPCount].dfGCPY = nLat / 1000000.0;
1738
37
                pasGCPList[nGCPCount].dfGCPZ = 0.0;
1739
1740
37
                pasGCPList[nGCPCount].dfGCPLine = iScanline + 0.5;
1741
1742
37
                if (iGCP == 0)
1743
13
                    pasGCPList[nGCPCount].dfGCPPixel = 0.5;
1744
24
                else if (iGCP == 1)
1745
12
                    pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize() / 2.0;
1746
12
                else
1747
12
                    pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize() - 0.5;
1748
1749
37
                nGCPCount++;
1750
37
            }
1751
108
        }
1752
36
    }
1753
    /* If general GCP's were not found, look for Map Projection (e.g. JERS) */
1754
15
    if (nGCPCount == 0)
1755
8
    {
1756
8
        CPLFree(pasGCPList);
1757
8
        pasGCPList = nullptr;
1758
8
        ScanForMapProjection();
1759
8
        return;
1760
8
    }
1761
15
}
1762
1763
/************************************************************************/
1764
/*                                Open()                                */
1765
/************************************************************************/
1766
1767
GDALDataset *SAR_CEOSDataset::Open(GDALOpenInfo *poOpenInfo)
1768
1769
901k
{
1770
    /* -------------------------------------------------------------------- */
1771
    /*      Does this appear to be a valid ceos leader record?              */
1772
    /* -------------------------------------------------------------------- */
1773
901k
    if (poOpenInfo->nHeaderBytes < CEOS_HEADER_LENGTH ||
1774
901k
        poOpenInfo->fpL == nullptr)
1775
805k
        return nullptr;
1776
1777
96.3k
    if ((poOpenInfo->pabyHeader[4] != 0x3f &&
1778
96.3k
         poOpenInfo->pabyHeader[4] != 0x32) ||
1779
96.3k
        poOpenInfo->pabyHeader[5] != 0xc0 ||
1780
96.3k
        poOpenInfo->pabyHeader[6] != 0x12 || poOpenInfo->pabyHeader[7] != 0x12)
1781
96.3k
        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
47
    if (poOpenInfo->pabyHeader[0] != 0)
1787
12
        return nullptr;
1788
1789
    /* -------------------------------------------------------------------- */
1790
    /*      Confirm the requested access is supported.                      */
1791
    /* -------------------------------------------------------------------- */
1792
35
    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
35
    auto poDS = std::make_unique<SAR_CEOSDataset>();
1803
35
    std::swap(poDS->fpImage, poOpenInfo->fpL);
1804
1805
35
    CeosSARVolume_t *psVolume = &(poDS->sVolume);
1806
35
    InitCeosSARVolume(psVolume, 0);
1807
1808
    /* -------------------------------------------------------------------- */
1809
    /*      Try to read the current file as an imagery file.                */
1810
    /* -------------------------------------------------------------------- */
1811
1812
35
    psVolume->ImagryOptionsFile = TRUE;
1813
35
    if (ProcessData(poDS->fpImage, CEOS_IMAGRY_OPT_FILE, psVolume, 4,
1814
35
                    VSI_L_OFFSET_MAX) != CE_None)
1815
11
    {
1816
11
        return nullptr;
1817
11
    }
1818
1819
    /* -------------------------------------------------------------------- */
1820
    /*      Try the various filenames.                                      */
1821
    /* -------------------------------------------------------------------- */
1822
24
    char *pszPath = CPLStrdup(CPLGetPathSafe(poOpenInfo->pszFilename).c_str());
1823
24
    char *pszBasename =
1824
24
        CPLStrdup(CPLGetBasenameSafe(poOpenInfo->pszFilename).c_str());
1825
24
    char *pszExtension =
1826
24
        CPLStrdup(CPLGetExtensionSafe(poOpenInfo->pszFilename).c_str());
1827
1828
24
    int nBand;
1829
24
    if (strlen(pszBasename) > 4)
1830
6
        nBand = atoi(pszBasename + 4);
1831
18
    else
1832
18
        nBand = 0;
1833
1834
144
    for (int iFile = 0; iFile < 5; iFile++)
1835
120
    {
1836
        /* skip image file ... we already did it */
1837
120
        if (iFile == 2)
1838
24
            continue;
1839
1840
96
        int e = 0;
1841
1.30k
        while (CeosExtension[e][iFile] != nullptr)
1842
1.22k
        {
1843
1.22k
            std::string osFilename;
1844
1845
            /* build filename */
1846
1.22k
            if (EQUAL(CeosExtension[e][5], "base"))
1847
288
            {
1848
288
                char szMadeBasename[32];
1849
1850
288
                snprintf(szMadeBasename, sizeof(szMadeBasename),
1851
288
                         CeosExtension[e][iFile], nBand);
1852
288
                osFilename =
1853
288
                    CPLFormFilenameSafe(pszPath, szMadeBasename, pszExtension);
1854
288
            }
1855
936
            else if (EQUAL(CeosExtension[e][5], "ext"))
1856
744
            {
1857
744
                osFilename = CPLFormFilenameSafe(pszPath, pszBasename,
1858
744
                                                 CeosExtension[e][iFile]);
1859
744
            }
1860
192
            else if (EQUAL(CeosExtension[e][5], "whole"))
1861
96
            {
1862
96
                osFilename =
1863
96
                    CPLFormFilenameSafe(pszPath, CeosExtension[e][iFile], "");
1864
96
            }
1865
1866
            // This is for SAR SLC as per the SAR Toolbox (from ASF).
1867
96
            else if (EQUAL(CeosExtension[e][5], "ext2"))
1868
96
            {
1869
96
                char szThisExtension[32];
1870
1871
96
                if (strlen(pszExtension) > 3)
1872
0
                    snprintf(szThisExtension, sizeof(szThisExtension), "%s%s",
1873
0
                             CeosExtension[e][iFile], pszExtension + 3);
1874
96
                else
1875
96
                    snprintf(szThisExtension, sizeof(szThisExtension), "%s",
1876
96
                             CeosExtension[e][iFile]);
1877
1878
96
                osFilename =
1879
96
                    CPLFormFilenameSafe(pszPath, pszBasename, szThisExtension);
1880
96
            }
1881
1882
            /* try to open */
1883
1.22k
            VSILFILE *process_fp = VSIFOpenL(osFilename.c_str(), "rb");
1884
1885
            /* try upper case */
1886
1.22k
            if (process_fp == nullptr)
1887
1.14k
            {
1888
1.14k
                for (int i = static_cast<int>(osFilename.size()) - 1;
1889
12.8k
                     i >= 0 && osFilename[i] != '/' && osFilename[i] != '\\';
1890
11.6k
                     i--)
1891
11.6k
                {
1892
11.6k
                    if (osFilename[i] >= 'a' && osFilename[i] <= 'z')
1893
8.20k
                        osFilename[i] = osFilename[i] - 'a' + 'A';
1894
11.6k
                }
1895
1896
1.14k
                process_fp = VSIFOpenL(osFilename.c_str(), "rb");
1897
1.14k
            }
1898
1899
1.22k
            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
1.20k
            e++;
1934
1.20k
        }
1935
96
    }
1936
1937
24
    CPLFree(pszPath);
1938
24
    CPLFree(pszBasename);
1939
24
    CPLFree(pszExtension);
1940
1941
    /* -------------------------------------------------------------------- */
1942
    /*      Check that we have an image description.                        */
1943
    /* -------------------------------------------------------------------- */
1944
24
    GetCeosSARImageDesc(psVolume);
1945
24
    struct CeosSARImageDesc *psImageDesc = &(psVolume->ImageDesc);
1946
24
    if (!psImageDesc->ImageDescValid)
1947
9
    {
1948
9
        CPLDebug("CEOS",
1949
9
                 "Unable to extract CEOS image description\n"
1950
9
                 "from %s.",
1951
9
                 poOpenInfo->pszFilename);
1952
1953
9
        return nullptr;
1954
9
    }
1955
1956
    /* -------------------------------------------------------------------- */
1957
    /*      Establish image type.                                           */
1958
    /* -------------------------------------------------------------------- */
1959
15
    GDALDataType eType;
1960
1961
15
    switch (psImageDesc->DataType)
1962
15
    {
1963
0
        case CEOS_TYP_CHAR:
1964
12
        case CEOS_TYP_UCHAR:
1965
12
            eType = GDT_Byte;
1966
12
            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
3
        case CEOS_TYP_USHORT:
1978
3
            eType = GDT_UInt16;
1979
3
            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
15
    }
2008
2009
    /* -------------------------------------------------------------------- */
2010
    /*      Capture some information from the file that is of interest.     */
2011
    /* -------------------------------------------------------------------- */
2012
15
    poDS->nRasterXSize = psImageDesc->PixelsPerLine +
2013
15
                         psImageDesc->LeftBorderPixels +
2014
15
                         psImageDesc->RightBorderPixels;
2015
15
    poDS->nRasterYSize = psImageDesc->Lines;
2016
2017
    /* -------------------------------------------------------------------- */
2018
    /*      Special case for compressed cross products.                     */
2019
    /* -------------------------------------------------------------------- */
2020
15
    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
15
    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
15
    else if (psImageDesc->RecordsPerLine > 1 ||
2059
15
             psImageDesc->DataType == CEOS_TYP_CHAR ||
2060
15
             psImageDesc->DataType == CEOS_TYP_LONG ||
2061
15
             psImageDesc->DataType == CEOS_TYP_ULONG ||
2062
15
             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
15
    else
2076
15
    {
2077
15
        int StartData;
2078
15
        CalcCeosSARImageFilePosition(psVolume, 1, 1, nullptr, &StartData);
2079
2080
        /*StartData += psImageDesc->ImageDataStart; */
2081
2082
15
        int nLineSize, nLineSize2;
2083
15
        CalcCeosSARImageFilePosition(psVolume, 1, 1, nullptr, &nLineSize);
2084
15
        CalcCeosSARImageFilePosition(psVolume, 1, 2, nullptr, &nLineSize2);
2085
2086
15
        nLineSize = nLineSize2 - nLineSize;
2087
2088
31
        for (int iBand = 0; iBand < psImageDesc->NumChannels; iBand++)
2089
16
        {
2090
16
            int nStartData, nPixelOffset, nLineOffset;
2091
2092
16
            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
16
            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
16
            else if (psImageDesc->ChannelInterleaving == CEOS_IL_BAND)
2114
16
            {
2115
16
                CalcCeosSARImageFilePosition(psVolume, iBand + 1, 1, nullptr,
2116
16
                                             &nStartData);
2117
2118
16
                nStartData += psImageDesc->ImageDataStart;
2119
16
                nPixelOffset = psImageDesc->BytesPerPixel;
2120
16
                nLineOffset = nLineSize;
2121
16
            }
2122
0
            else
2123
0
            {
2124
0
                CPLAssert(false);
2125
0
                return nullptr;
2126
0
            }
2127
2128
16
            auto poBand = RawRasterBand::Create(
2129
16
                poDS.get(), poDS->nBands + 1, poDS->fpImage, nStartData,
2130
16
                nPixelOffset, nLineOffset, eType,
2131
16
                RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
2132
16
                RawRasterBand::OwnFP::NO);
2133
16
            if (!poBand)
2134
0
                return nullptr;
2135
16
            poDS->SetBand(poDS->nBands + 1, std::move(poBand));
2136
16
        }
2137
15
    }
2138
2139
    /* -------------------------------------------------------------------- */
2140
    /*      Collect metadata.                                               */
2141
    /* -------------------------------------------------------------------- */
2142
15
    poDS->ScanForMetadata();
2143
2144
    /* -------------------------------------------------------------------- */
2145
    /*      Check for GCPs.                                                 */
2146
    /* -------------------------------------------------------------------- */
2147
15
    poDS->ScanForGCPs();
2148
2149
    /* -------------------------------------------------------------------- */
2150
    /*      Initialize any PAM information.                                 */
2151
    /* -------------------------------------------------------------------- */
2152
15
    poDS->SetDescription(poOpenInfo->pszFilename);
2153
15
    poDS->TryLoadXML();
2154
2155
    /* -------------------------------------------------------------------- */
2156
    /*      Open overviews.                                                 */
2157
    /* -------------------------------------------------------------------- */
2158
15
    poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
2159
2160
15
    return poDS.release();
2161
15
}
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
113
{
2170
113
    unsigned char temp_buffer[CEOS_HEADER_LENGTH];
2171
113
    unsigned char *temp_body = nullptr;
2172
113
    int start = 0;
2173
113
    int CurrentBodyLength = 0;
2174
113
    int CurrentType = 0;
2175
113
    int CurrentSequence = 0;
2176
113
    int iThisRecord = 0;
2177
2178
612
    while (max_records != 0 && max_bytes != 0)
2179
570
    {
2180
570
        iThisRecord++;
2181
2182
570
        if (VSIFSeekL(fp, start, SEEK_SET) != 0 ||
2183
570
            VSIFReadL(temp_buffer, 1, CEOS_HEADER_LENGTH, fp) !=
2184
570
                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
565
        CeosRecord_t *record = (CeosRecord_t *)CPLMalloc(sizeof(CeosRecord_t));
2192
565
        record->Length = DetermineCeosRecordBodyLength(temp_buffer);
2193
2194
565
        CeosToNative(&(record->Sequence), temp_buffer, 4, 4);
2195
2196
565
        if (iThisRecord != record->Sequence)
2197
47
        {
2198
47
            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
44
            else
2208
44
            {
2209
44
                CPLError(CE_Failure, CPLE_AppDefined,
2210
44
                         "Corrupt CEOS File - got record seq# %d instead of "
2211
44
                         "the expected %d.",
2212
44
                         record->Sequence, iThisRecord);
2213
44
                CPLFree(record);
2214
44
                CPLFree(temp_body);
2215
44
                return CE_Failure;
2216
44
            }
2217
47
        }
2218
2219
518
        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
517
        if (record->Length > CurrentBodyLength)
2229
198
        {
2230
198
            unsigned char *temp_body_new =
2231
198
                (unsigned char *)VSI_REALLOC_VERBOSE(temp_body, record->Length);
2232
198
            if (temp_body_new == nullptr)
2233
0
            {
2234
0
                CPLFree(record);
2235
0
                CPLFree(temp_body);
2236
0
                return CE_Failure;
2237
0
            }
2238
198
            temp_body = temp_body_new;
2239
198
            CurrentBodyLength = record->Length;
2240
198
        }
2241
2242
517
        int nToRead = record->Length - CEOS_HEADER_LENGTH;
2243
517
        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
499
        InitCeosRecordWithHeader(record, temp_buffer, temp_body);
2253
499
        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
499
        if (CurrentType == record->TypeCode.Int32Code)
2263
148
            record->Subsequence = ++CurrentSequence;
2264
351
        else
2265
351
        {
2266
351
            CurrentType = record->TypeCode.Int32Code;
2267
351
            record->Subsequence = 0;
2268
351
            CurrentSequence = 0;
2269
351
        }
2270
2271
499
        record->FileId = fileid;
2272
2273
499
        Link_t *TheLink = ceos2CreateLink(record);
2274
2275
499
        if (sar->RecordList == nullptr)
2276
33
            sar->RecordList = TheLink;
2277
466
        else
2278
466
            sar->RecordList = InsertLink(sar->RecordList, TheLink);
2279
2280
499
        start += record->Length;
2281
2282
499
        if (max_records > 0)
2283
114
            max_records--;
2284
499
        if (max_bytes > 0)
2285
499
        {
2286
499
            if ((vsi_l_offset)record->Length <= max_bytes)
2287
499
                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
499
        }
2296
499
    }
2297
2298
42
    CPLFree(temp_body);
2299
2300
42
    return CE_None;
2301
113
}
2302
2303
/************************************************************************/
2304
/*                       GDALRegister_SAR_CEOS()                        */
2305
/************************************************************************/
2306
2307
void GDALRegister_SAR_CEOS()
2308
2309
24
{
2310
24
    if (GDALGetDriverByName("SAR_CEOS") != nullptr)
2311
0
        return;
2312
2313
24
    GDALDriver *poDriver = new GDALDriver();
2314
2315
24
    poDriver->SetDescription("SAR_CEOS");
2316
24
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
2317
24
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "CEOS SAR Image");
2318
24
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
2319
24
                              "drivers/raster/sar_ceos.html");
2320
24
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
2321
2322
24
    poDriver->pfnOpen = SAR_CEOSDataset::Open;
2323
2324
24
    GetGDALDriverManager()->RegisterDriver(poDriver);
2325
24
}
2326
2327
/************************************************************************/
2328
/*                            GetFileList()                             */
2329
/************************************************************************/
2330
2331
char **SAR_CEOSDataset::GetFileList()
2332
2333
30
{
2334
30
    char **papszFileList = GDALPamDataset::GetFileList();
2335
2336
30
    papszFileList = CSLInsertStrings(papszFileList, -1, papszExtraFiles);
2337
2338
30
    return papszFileList;
2339
30
}