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