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