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