Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: AirSAR Reader
4 : * Purpose: Implements read support for AirSAR Polarimetric data.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
9 : * Copyright (c) 2007-2009, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_conv.h"
15 : #include "cpl_string.h"
16 : #include "cpl_vsi.h"
17 : #include "gdal_frmts.h"
18 : #include "gdal_pam.h"
19 : #include "gdal_driver.h"
20 : #include "gdal_drivermanager.h"
21 : #include "gdal_openinfo.h"
22 : #include "gdal_cpp_functions.h"
23 :
24 : /************************************************************************/
25 : /* ==================================================================== */
26 : /* AirSARDataset */
27 : /* ==================================================================== */
28 : /************************************************************************/
29 :
30 : class AirSARRasterBand;
31 :
32 : class AirSARDataset final : public GDALPamDataset
33 : {
34 : friend class AirSARRasterBand;
35 :
36 : VSILFILE *fp;
37 :
38 : int nLoadedLine;
39 : GByte *pabyCompressedLine;
40 : double *padfMatrix;
41 :
42 : int nDataStart;
43 : int nRecordLength;
44 :
45 : CPLErr LoadLine(int iLine);
46 :
47 : static char **ReadHeader(VSILFILE *fp, int nFileOffset,
48 : const char *pszPrefix, int nMaxLines);
49 :
50 : public:
51 : AirSARDataset();
52 : ~AirSARDataset() override;
53 :
54 : static GDALDataset *Open(GDALOpenInfo *);
55 : };
56 :
57 : /************************************************************************/
58 : /* ==================================================================== */
59 : /* AirSARRasterBand */
60 : /* ==================================================================== */
61 : /************************************************************************/
62 :
63 : class AirSARRasterBand final : public GDALPamRasterBand
64 : {
65 : public:
66 : AirSARRasterBand(AirSARDataset *, int);
67 : ~AirSARRasterBand() override;
68 :
69 : CPLErr IReadBlock(int, int, void *) override;
70 : };
71 :
72 : /* locations of stokes matrix values within padfMatrix ... same order as they
73 : are computed in the document. */
74 :
75 : constexpr int M11 = 0;
76 : constexpr int M12 = 1;
77 : constexpr int M13 = 2;
78 : constexpr int M14 = 3;
79 : constexpr int M23 = 4;
80 : constexpr int M24 = 5;
81 : constexpr int M33 = 6;
82 : constexpr int M34 = 7;
83 : constexpr int M44 = 8;
84 : constexpr int M22 = 9;
85 :
86 : /************************************************************************/
87 : /* AirSARRasterBand() */
88 : /************************************************************************/
89 :
90 0 : AirSARRasterBand::AirSARRasterBand(AirSARDataset *poDSIn, int nBandIn)
91 :
92 : {
93 0 : poDS = poDSIn;
94 0 : nBand = nBandIn;
95 :
96 0 : nBlockXSize = poDS->GetRasterXSize();
97 0 : nBlockYSize = 1;
98 :
99 0 : if (this->nBand == 2 || this->nBand == 3 || this->nBand == 5)
100 0 : eDataType = GDT_CFloat32;
101 : else
102 0 : eDataType = GDT_Float32;
103 :
104 0 : switch (nBand)
105 : {
106 0 : case 1:
107 0 : SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_11");
108 0 : SetDescription("Covariance_11");
109 0 : eDataType = GDT_CFloat32;
110 0 : break;
111 :
112 0 : case 2:
113 0 : SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_12");
114 0 : SetDescription("Covariance_12");
115 0 : eDataType = GDT_CFloat32;
116 0 : break;
117 :
118 0 : case 3:
119 0 : SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_13");
120 0 : SetDescription("Covariance_13");
121 0 : eDataType = GDT_CFloat32;
122 0 : break;
123 :
124 0 : case 4:
125 0 : SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_22");
126 0 : SetDescription("Covariance_22");
127 0 : eDataType = GDT_CFloat32;
128 0 : break;
129 :
130 0 : case 5:
131 0 : SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_23");
132 0 : SetDescription("Covariance_23");
133 0 : eDataType = GDT_CFloat32;
134 0 : break;
135 :
136 0 : case 6:
137 0 : SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_33");
138 0 : SetDescription("Covariance_33");
139 0 : eDataType = GDT_CFloat32;
140 0 : break;
141 : }
142 0 : }
143 :
144 : /************************************************************************/
145 : /* ~AirSARRasterBand() */
146 : /************************************************************************/
147 :
148 0 : AirSARRasterBand::~AirSARRasterBand()
149 :
150 : {
151 0 : }
152 :
153 : /************************************************************************/
154 : /* IReadBlock() */
155 : /************************************************************************/
156 :
157 0 : CPLErr AirSARRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff,
158 : void *pImage)
159 : {
160 0 : float *pafLine = (float *)pImage;
161 0 : const double SQRT_2 = 1.4142135623730951;
162 :
163 0 : CPLErr eErr = cpl::down_cast<AirSARDataset *>(poDS)->LoadLine(nBlockYOff);
164 0 : if (eErr != CE_None)
165 0 : return eErr;
166 :
167 0 : double *padfMatrix = cpl::down_cast<AirSARDataset *>(poDS)->padfMatrix;
168 :
169 0 : if (nBand == 1) /* C11 */
170 : {
171 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
172 : {
173 0 : double *m = padfMatrix + 10 * iPixel;
174 :
175 0 : pafLine[iPixel * 2 + 0] = (float)(m[M11] + m[M22] + 2 * m[M12]);
176 0 : pafLine[iPixel * 2 + 1] = 0.0;
177 : }
178 : }
179 0 : else if (nBand == 2) /* C12 */
180 : {
181 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
182 : {
183 0 : double *m = padfMatrix + 10 * iPixel;
184 :
185 : // real
186 0 : pafLine[iPixel * 2 + 0] = (float)(SQRT_2 * (m[M13] + m[M23]));
187 :
188 : // imaginary
189 0 : pafLine[iPixel * 2 + 1] = (float)(-SQRT_2 * (m[M24] + m[M14]));
190 : }
191 : }
192 0 : else if (nBand == 3) /* C13 */
193 : {
194 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
195 : {
196 0 : double *m = padfMatrix + 10 * iPixel;
197 :
198 : // real
199 0 : pafLine[iPixel * 2 + 0] = (float)(2 * m[M33] + m[M22] - m[M11]);
200 :
201 : // imaginary
202 0 : pafLine[iPixel * 2 + 1] = (float)(-2 * m[M34]);
203 : }
204 : }
205 0 : else if (nBand == 4) /* C22 */
206 : {
207 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
208 : {
209 0 : double *m = padfMatrix + 10 * iPixel;
210 :
211 0 : pafLine[iPixel * 2 + 0] = (float)(2 * (m[M11] - m[M22]));
212 0 : pafLine[iPixel * 2 + 1] = 0.0;
213 : }
214 : }
215 0 : else if (nBand == 5) /* C23 */
216 : {
217 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
218 : {
219 0 : double *m = padfMatrix + 10 * iPixel;
220 :
221 : // real
222 0 : pafLine[iPixel * 2 + 0] = (float)(SQRT_2 * (m[M13] - m[M23]));
223 :
224 : // imaginary
225 0 : pafLine[iPixel * 2 + 1] = (float)(SQRT_2 * (m[M24] - m[M14]));
226 : }
227 : }
228 0 : else if (nBand == 6) /* C33 */
229 : {
230 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
231 : {
232 0 : double *m = padfMatrix + 10 * iPixel;
233 :
234 0 : pafLine[iPixel * 2 + 0] = (float)(m[M11] + m[M22] - 2 * m[M12]);
235 0 : pafLine[iPixel * 2 + 1] = 0.0;
236 : }
237 : }
238 :
239 0 : return CE_None;
240 : }
241 :
242 : /************************************************************************/
243 : /* ==================================================================== */
244 : /* AirSARDataset */
245 : /* ==================================================================== */
246 : /************************************************************************/
247 :
248 : /************************************************************************/
249 : /* AirSARDataset() */
250 : /************************************************************************/
251 :
252 0 : AirSARDataset::AirSARDataset()
253 : : fp(nullptr), nLoadedLine(-1), pabyCompressedLine(nullptr),
254 0 : padfMatrix(nullptr), nDataStart(0), nRecordLength(0)
255 : {
256 0 : }
257 :
258 : /************************************************************************/
259 : /* ~AirSARDataset() */
260 : /************************************************************************/
261 :
262 0 : AirSARDataset::~AirSARDataset()
263 :
264 : {
265 0 : FlushCache(true);
266 0 : CPLFree(pabyCompressedLine);
267 0 : CPLFree(padfMatrix);
268 :
269 0 : if (fp != nullptr)
270 : {
271 0 : VSIFCloseL(fp);
272 0 : fp = nullptr;
273 : }
274 0 : }
275 :
276 : /************************************************************************/
277 : /* LoadLine() */
278 : /************************************************************************/
279 :
280 0 : CPLErr AirSARDataset::LoadLine(int iLine)
281 :
282 : {
283 0 : if (iLine == nLoadedLine)
284 0 : return CE_None;
285 :
286 : /* -------------------------------------------------------------------- */
287 : /* allocate working buffers if we don't have them already. */
288 : /* -------------------------------------------------------------------- */
289 0 : if (pabyCompressedLine == nullptr)
290 : {
291 0 : pabyCompressedLine = (GByte *)VSI_MALLOC2_VERBOSE(nRasterXSize, 10);
292 :
293 0 : padfMatrix =
294 0 : (double *)VSI_MALLOC2_VERBOSE(10 * sizeof(double), nRasterXSize);
295 0 : if (pabyCompressedLine == nullptr || padfMatrix == nullptr)
296 : {
297 0 : CPLFree(pabyCompressedLine);
298 0 : CPLFree(padfMatrix);
299 0 : return CE_Failure;
300 : }
301 : }
302 :
303 0 : CPLAssert(nRecordLength == nRasterXSize * 10);
304 :
305 : /* -------------------------------------------------------------------- */
306 : /* Load raw compressed data. */
307 : /* -------------------------------------------------------------------- */
308 0 : if (VSIFSeekL(fp, nDataStart + iLine * nRecordLength, SEEK_SET) != 0 ||
309 0 : ((int)VSIFReadL(pabyCompressedLine, 10, nRasterXSize, fp)) !=
310 0 : nRasterXSize)
311 : {
312 0 : CPLError(CE_Failure, CPLE_FileIO,
313 : "Error reading %d bytes for line %d at offset %d.\n%s",
314 0 : nRasterXSize * 10, iLine, nDataStart + iLine * nRecordLength,
315 0 : VSIStrerror(errno));
316 0 : return CE_Failure;
317 : }
318 :
319 : /* -------------------------------------------------------------------- */
320 : /* Build stokes matrix */
321 : /* -------------------------------------------------------------------- */
322 0 : for (int iPixel = 0; iPixel < nRasterXSize; iPixel++)
323 : {
324 0 : double *M = padfMatrix + 10 * iPixel;
325 0 : signed char *byte = (signed char *)pabyCompressedLine + 10 * iPixel - 1;
326 0 : const double gen_fac = 1.0; // should we have a general scale factor?
327 :
328 0 : M[M11] = (byte[2] / 254.0 + 1.5) * pow(2.0, byte[1]) * gen_fac;
329 0 : M[M12] = byte[3] * M[M11] / 127.0;
330 0 : M[M13] = byte[4] * fabs((double)byte[4]) * M[M11] / (127 * 127);
331 0 : M[M14] = byte[5] * fabs((double)byte[5]) * M[M11] / (127 * 127);
332 0 : M[M23] = byte[6] * fabs((double)byte[6]) * M[M11] / (127 * 127);
333 0 : M[M24] = byte[7] * fabs((double)byte[7]) * M[M11] / (127 * 127);
334 0 : M[M33] = byte[8] * M[M11] / 127;
335 0 : M[M34] = byte[9] * M[M11] / 127;
336 0 : M[M44] = byte[10] * M[M11] / 127;
337 0 : M[M22] = M[M11] - M[M33] - M[M44];
338 : }
339 :
340 0 : return CE_None;
341 : }
342 :
343 : /************************************************************************/
344 : /* ReadHeader() */
345 : /* */
346 : /* Read the AirSAR header. We assume an equal sign separates */
347 : /* the keyword name from the value. If not, assume the last */
348 : /* "blank delimited" word is the value and everything else is a */
349 : /* keyword. */
350 : /* */
351 : /* The records are 50 characters each. Read till we get an all */
352 : /* blank record or some zero bytes. */
353 : /************************************************************************/
354 :
355 0 : char **AirSARDataset::ReadHeader(VSILFILE *fp, int nFileOffset,
356 : const char *pszPrefix, int nMaxLines)
357 :
358 : {
359 0 : char **papszHeadInfo = nullptr;
360 : char szLine[51];
361 :
362 0 : VSIFSeekL(fp, nFileOffset, SEEK_SET);
363 :
364 : /* ==================================================================== */
365 : /* Loop collecting one line at a time. */
366 : /* ==================================================================== */
367 0 : for (int iLine = 0; iLine < nMaxLines; iLine++)
368 : {
369 : /* --------------------------------------------------------------------
370 : */
371 : /* Read a 50 byte header record. */
372 : /* --------------------------------------------------------------------
373 : */
374 0 : if (VSIFReadL(szLine, 1, 50, fp) != 50)
375 : {
376 0 : CPLError(CE_Failure, CPLE_FileIO,
377 : "Read error collecting AirSAR header.");
378 0 : CSLDestroy(papszHeadInfo);
379 0 : return nullptr;
380 : }
381 :
382 0 : szLine[50] = '\0';
383 :
384 : /* --------------------------------------------------------------------
385 : */
386 : /* Is it all spaces, or does it have a zero byte? */
387 : /* --------------------------------------------------------------------
388 : */
389 0 : bool bAllSpaces = true;
390 0 : bool bHasIllegalChars = false;
391 :
392 0 : for (int i = 0; i < 50; i++)
393 : {
394 0 : if (szLine[i] == '\0')
395 0 : break;
396 :
397 0 : if (szLine[i] != ' ')
398 0 : bAllSpaces = false;
399 :
400 0 : if (((unsigned char *)szLine)[i] > 127 ||
401 0 : ((unsigned char *)szLine)[i] < 10)
402 0 : bHasIllegalChars = true;
403 : }
404 :
405 0 : if (bAllSpaces || bHasIllegalChars)
406 : break;
407 :
408 : /* --------------------------------------------------------------------
409 : */
410 : /* Find the pivot between the keyword name and value. */
411 : /* --------------------------------------------------------------------
412 : */
413 0 : int iPivot = -1;
414 :
415 0 : for (int i = 0; i < 50; i++)
416 : {
417 0 : if (szLine[i] == '=')
418 : {
419 0 : iPivot = i;
420 0 : break;
421 : }
422 : }
423 :
424 : // If no "=" found, split on first double white space
425 0 : if (iPivot == -1)
426 : {
427 0 : for (int i = 48; i >= 0; i--)
428 : {
429 0 : if (szLine[i] == ' ' && szLine[i + 1] == ' ')
430 : {
431 0 : iPivot = i;
432 0 : break;
433 : }
434 : }
435 : }
436 :
437 0 : if (iPivot == -1) // Yikes!
438 : {
439 0 : CPLDebug("AIRSAR", "No pivot in line `%s'.", szLine);
440 0 : CPLAssert(iPivot != -1);
441 0 : break;
442 : }
443 :
444 : /* --------------------------------------------------------------------
445 : */
446 : /* Trace ahead to the first non-white space value character. */
447 : /* --------------------------------------------------------------------
448 : */
449 0 : int iValue = iPivot + 1;
450 :
451 0 : while (iValue < 50 && szLine[iValue] == ' ')
452 0 : iValue++;
453 :
454 : /* --------------------------------------------------------------------
455 : */
456 : /* Strip any white space off the keyword. */
457 : /* --------------------------------------------------------------------
458 : */
459 0 : int iKeyEnd = iPivot - 1;
460 :
461 0 : while (iKeyEnd > 0 && szLine[iKeyEnd] == ' ')
462 0 : iKeyEnd--;
463 :
464 0 : szLine[iKeyEnd + 1] = '\0';
465 :
466 : /* --------------------------------------------------------------------
467 : */
468 : /* Convert spaces or colons into underscores in the key name. */
469 : /* --------------------------------------------------------------------
470 : */
471 0 : for (int i = 0; szLine[i] != '\0'; i++)
472 : {
473 0 : if (szLine[i] == ' ' || szLine[i] == ':' || szLine[i] == ',')
474 0 : szLine[i] = '_';
475 : }
476 :
477 : /* --------------------------------------------------------------------
478 : */
479 : /* Prefix key name with provided prefix string. */
480 : /* --------------------------------------------------------------------
481 : */
482 : char szPrefixedKeyName[55];
483 :
484 0 : snprintf(szPrefixedKeyName, sizeof(szPrefixedKeyName), "%s_%s",
485 : pszPrefix, szLine);
486 :
487 : papszHeadInfo =
488 0 : CSLSetNameValue(papszHeadInfo, szPrefixedKeyName, szLine + iValue);
489 : }
490 :
491 0 : return papszHeadInfo;
492 : }
493 :
494 : /************************************************************************/
495 : /* Open() */
496 : /************************************************************************/
497 :
498 37909 : GDALDataset *AirSARDataset::Open(GDALOpenInfo *poOpenInfo)
499 :
500 : {
501 37909 : if (poOpenInfo->fpL == nullptr || poOpenInfo->nHeaderBytes < 800)
502 33758 : return nullptr;
503 :
504 : /* -------------------------------------------------------------------- */
505 : /* Check for AirSAR/ keyword. */
506 : /* -------------------------------------------------------------------- */
507 4151 : if (!STARTS_WITH_CI((char *)poOpenInfo->pabyHeader,
508 : "RECORD LENGTH IN BYTES"))
509 4151 : return nullptr;
510 :
511 0 : if (strstr((char *)poOpenInfo->pabyHeader, "COMPRESSED") == nullptr ||
512 0 : strstr((char *)poOpenInfo->pabyHeader, "JPL AIRCRAFT") == nullptr)
513 0 : return nullptr;
514 :
515 : /* -------------------------------------------------------------------- */
516 : /* Parse the header fields. We turn all the transform the */
517 : /* keywords by converting spaces to underscores so they will be */
518 : /* "well behaved" as metadata keywords. */
519 : /* -------------------------------------------------------------------- */
520 0 : char **papszMD = ReadHeader(poOpenInfo->fpL, 0, "MH", 20);
521 :
522 0 : if (papszMD == nullptr)
523 0 : return nullptr;
524 :
525 : /* -------------------------------------------------------------------- */
526 : /* Confirm the requested access is supported. */
527 : /* -------------------------------------------------------------------- */
528 0 : if (poOpenInfo->eAccess == GA_Update)
529 : {
530 0 : ReportUpdateNotSupportedByDriver("AIRSAR");
531 0 : CSLDestroy(papszMD);
532 0 : return nullptr;
533 : }
534 : /* -------------------------------------------------------------------- */
535 : /* Create a corresponding GDALDataset. */
536 : /* -------------------------------------------------------------------- */
537 0 : AirSARDataset *poDS = new AirSARDataset();
538 :
539 : /* -------------------------------------------------------------------- */
540 : /* Extract some key information. */
541 : /* -------------------------------------------------------------------- */
542 :
543 0 : poDS->nRasterXSize =
544 0 : atoi(CSLFetchNameValue(papszMD, "MH_NUMBER_OF_SAMPLES_PER_RECORD"));
545 0 : poDS->nRasterYSize =
546 0 : atoi(CSLFetchNameValue(papszMD, "MH_NUMBER_OF_LINES_IN_IMAGE"));
547 :
548 0 : poDS->nRecordLength =
549 0 : atoi(CSLFetchNameValue(papszMD, "MH_RECORD_LENGTH_IN_BYTES"));
550 :
551 0 : poDS->nDataStart =
552 0 : atoi(CSLFetchNameValue(papszMD, "MH_BYTE_OFFSET_OF_FIRST_DATA_RECORD"));
553 :
554 : /* -------------------------------------------------------------------- */
555 : /* Adopt the openinfo file pointer. */
556 : /* -------------------------------------------------------------------- */
557 0 : poDS->fp = poOpenInfo->fpL;
558 0 : poOpenInfo->fpL = nullptr;
559 :
560 : /* -------------------------------------------------------------------- */
561 : /* Read and merge parameter header into metadata. Prefix */
562 : /* parameter header values with PH_. */
563 : /* -------------------------------------------------------------------- */
564 0 : int nPHOffset = 0;
565 :
566 0 : if (CSLFetchNameValue(papszMD, "MH_BYTE_OFFSET_OF_PARAMETER_HEADER") !=
567 : nullptr)
568 : {
569 0 : nPHOffset = atoi(
570 : CSLFetchNameValue(papszMD, "MH_BYTE_OFFSET_OF_PARAMETER_HEADER"));
571 0 : char **papszPHInfo = ReadHeader(poDS->fp, nPHOffset, "PH", 100);
572 :
573 0 : papszMD = CSLInsertStrings(papszMD, CSLCount(papszMD), papszPHInfo);
574 :
575 0 : CSLDestroy(papszPHInfo);
576 : }
577 :
578 : /* -------------------------------------------------------------------- */
579 : /* Read and merge calibration header into metadata. Prefix */
580 : /* parameter header values with CH_. */
581 : /* -------------------------------------------------------------------- */
582 0 : if (nPHOffset != 0)
583 : {
584 : char **papszCHInfo =
585 0 : ReadHeader(poDS->fp, nPHOffset + poDS->nRecordLength, "CH", 18);
586 :
587 0 : papszMD = CSLInsertStrings(papszMD, CSLCount(papszMD), papszCHInfo);
588 :
589 0 : CSLDestroy(papszCHInfo);
590 : }
591 :
592 : /* -------------------------------------------------------------------- */
593 : /* Assign metadata to dataset. */
594 : /* -------------------------------------------------------------------- */
595 0 : poDS->SetMetadata(papszMD);
596 0 : CSLDestroy(papszMD);
597 :
598 : /* -------------------------------------------------------------------- */
599 : /* Create band information objects. */
600 : /* -------------------------------------------------------------------- */
601 0 : poDS->SetBand(1, new AirSARRasterBand(poDS, 1));
602 0 : poDS->SetBand(2, new AirSARRasterBand(poDS, 2));
603 0 : poDS->SetBand(3, new AirSARRasterBand(poDS, 3));
604 0 : poDS->SetBand(4, new AirSARRasterBand(poDS, 4));
605 0 : poDS->SetBand(5, new AirSARRasterBand(poDS, 5));
606 0 : poDS->SetBand(6, new AirSARRasterBand(poDS, 6));
607 :
608 0 : poDS->SetMetadataItem("MATRIX_REPRESENTATION", "SYMMETRIZED_COVARIANCE");
609 :
610 : /* -------------------------------------------------------------------- */
611 : /* Initialize any PAM information. */
612 : /* -------------------------------------------------------------------- */
613 0 : poDS->SetDescription(poOpenInfo->pszFilename);
614 0 : poDS->TryLoadXML();
615 :
616 0 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
617 :
618 0 : return poDS;
619 : }
620 :
621 : /************************************************************************/
622 : /* GDALRegister_AirSAR() */
623 : /************************************************************************/
624 :
625 2033 : void GDALRegister_AirSAR()
626 :
627 : {
628 2033 : if (GDALGetDriverByName("AirSAR") != nullptr)
629 283 : return;
630 :
631 1750 : GDALDriver *poDriver = new GDALDriver();
632 :
633 1750 : poDriver->SetDescription("AirSAR");
634 1750 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
635 1750 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "AirSAR Polarimetric Image");
636 1750 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/airsar.html");
637 :
638 1750 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
639 :
640 1750 : poDriver->pfnOpen = AirSARDataset::Open;
641 :
642 1750 : GetGDALDriverManager()->RegisterDriver(poDriver);
643 : }
|