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