Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: APP ENVISAT Support
4 : * Purpose: Reader for ENVISAT format image data.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2001, 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 "adsrange.hpp"
15 : #include "rawdataset.h"
16 : #include "cpl_string.h"
17 : #include "gdal_frmts.h"
18 : #include "ogr_srs_api.h"
19 : #include "timedelta.hpp"
20 :
21 : CPL_C_START
22 : #include "EnvisatFile.h"
23 : #include "records.h"
24 : CPL_C_END
25 :
26 : #include <algorithm>
27 :
28 : /************************************************************************/
29 : /* ==================================================================== */
30 : /* MerisL2FlagBand */
31 : /* ==================================================================== */
32 : /************************************************************************/
33 : class MerisL2FlagBand final : public GDALPamRasterBand
34 : {
35 : public:
36 : MerisL2FlagBand(GDALDataset *, int, VSILFILE *, vsi_l_offset, int);
37 : ~MerisL2FlagBand() override;
38 : virtual CPLErr IReadBlock(int, int, void *) override;
39 :
40 : private:
41 : vsi_l_offset nImgOffset;
42 : int nPrefixBytes;
43 : size_t nBytePerPixel;
44 : size_t nRecordSize;
45 : size_t nDataSize;
46 : GByte *pReadBuf;
47 : VSILFILE *fpImage;
48 : };
49 :
50 : /************************************************************************/
51 : /* MerisL2FlagBand() */
52 : /************************************************************************/
53 0 : MerisL2FlagBand::MerisL2FlagBand(GDALDataset *poDSIn, int nBandIn,
54 : VSILFILE *fpImageIn, vsi_l_offset nImgOffsetIn,
55 0 : int nPrefixBytesIn)
56 : : nImgOffset(nImgOffsetIn), nPrefixBytes(nPrefixBytesIn), nBytePerPixel(3),
57 0 : nRecordSize(0), nDataSize(0), pReadBuf(nullptr)
58 : {
59 0 : poDS = poDSIn;
60 0 : nBand = nBandIn;
61 :
62 0 : fpImage = fpImageIn;
63 :
64 0 : eDataType = GDT_UInt32;
65 :
66 0 : nBlockXSize = poDS->GetRasterXSize();
67 0 : nBlockYSize = 1;
68 0 : nRecordSize = nPrefixBytesIn + nBlockXSize * nBytePerPixel;
69 0 : nDataSize = nBlockXSize * nBytePerPixel;
70 0 : pReadBuf = static_cast<GByte *>(CPLMalloc(nRecordSize));
71 0 : }
72 :
73 : /************************************************************************/
74 : /* ~MerisL2FlagBand() */
75 : /************************************************************************/
76 0 : MerisL2FlagBand::~MerisL2FlagBand()
77 : {
78 0 : CPLFree(pReadBuf);
79 0 : }
80 :
81 : /************************************************************************/
82 : /* IReadBlock() */
83 : /************************************************************************/
84 0 : CPLErr MerisL2FlagBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
85 : void *pImage)
86 : {
87 0 : CPLAssert(nBlockXOff == 0);
88 0 : CPLAssert(pReadBuf != nullptr);
89 :
90 0 : vsi_l_offset nOffset =
91 0 : nImgOffset + nPrefixBytes +
92 0 : static_cast<vsi_l_offset>(nBlockYOff) * nBlockYSize * nRecordSize;
93 :
94 0 : if (VSIFSeekL(fpImage, nOffset, SEEK_SET) != 0)
95 : {
96 0 : CPLError(CE_Failure, CPLE_FileIO,
97 : "Seek to %d for scanline %d failed.\n", (int)nOffset,
98 : nBlockYOff);
99 0 : return CE_Failure;
100 : }
101 :
102 0 : if (VSIFReadL(pReadBuf, 1, nDataSize, fpImage) != nDataSize)
103 : {
104 0 : CPLError(CE_Failure, CPLE_FileIO,
105 0 : "Read of %d bytes for scanline %d failed.\n", (int)nDataSize,
106 : nBlockYOff);
107 0 : return CE_Failure;
108 : }
109 :
110 0 : const unsigned int nUInt32Size = 4;
111 0 : for (unsigned iImg = 0, iBuf = 0; iImg < nBlockXSize * nUInt32Size;
112 0 : iImg += nUInt32Size, iBuf += (unsigned)nBytePerPixel)
113 : {
114 : #ifdef CPL_LSB
115 0 : ((GByte *)pImage)[iImg] = pReadBuf[iBuf + 2];
116 0 : ((GByte *)pImage)[iImg + 1] = pReadBuf[iBuf + 1];
117 0 : ((GByte *)pImage)[iImg + 2] = pReadBuf[iBuf];
118 0 : ((GByte *)pImage)[iImg + 3] = 0;
119 : #else
120 : ((GByte *)pImage)[iImg] = 0;
121 : ((GByte *)pImage)[iImg + 1] = pReadBuf[iBuf];
122 : ((GByte *)pImage)[iImg + 2] = pReadBuf[iBuf + 1];
123 : ((GByte *)pImage)[iImg + 3] = pReadBuf[iBuf + 2];
124 : #endif
125 : }
126 :
127 0 : return CE_None;
128 : }
129 :
130 : /************************************************************************/
131 : /* ==================================================================== */
132 : /* EnvisatDataset */
133 : /* ==================================================================== */
134 : /************************************************************************/
135 :
136 : class EnvisatDataset final : public RawDataset
137 : {
138 : EnvisatFile *hEnvisatFile;
139 : VSILFILE *fpImage;
140 :
141 : OGRSpatialReference m_oGCPSRS{};
142 : int nGCPCount;
143 : GDAL_GCP *pasGCPList;
144 :
145 : char **papszTempMD;
146 :
147 : void ScanForGCPs_ASAR();
148 : void ScanForGCPs_MERIS();
149 :
150 : void UnwrapGCPs();
151 :
152 : void CollectMetadata(EnvisatFile_HeaderFlag);
153 : void CollectDSDMetadata();
154 : void CollectADSMetadata();
155 :
156 : CPLErr Close() override;
157 :
158 : public:
159 : EnvisatDataset();
160 : virtual ~EnvisatDataset();
161 :
162 : virtual int GetGCPCount() override;
163 : const OGRSpatialReference *GetGCPSpatialRef() const override;
164 : virtual const GDAL_GCP *GetGCPs() override;
165 : virtual char **GetMetadataDomainList() override;
166 : virtual char **GetMetadata(const char *pszDomain) override;
167 :
168 : static GDALDataset *Open(GDALOpenInfo *);
169 : };
170 :
171 : /************************************************************************/
172 : /* ==================================================================== */
173 : /* EnvisatDataset */
174 : /* ==================================================================== */
175 : /************************************************************************/
176 :
177 : /************************************************************************/
178 : /* EnvisatDataset() */
179 : /************************************************************************/
180 :
181 0 : EnvisatDataset::EnvisatDataset()
182 : : hEnvisatFile(nullptr), fpImage(nullptr), nGCPCount(0),
183 0 : pasGCPList(nullptr), papszTempMD(nullptr)
184 : {
185 0 : m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
186 0 : m_oGCPSRS.importFromWkt(SRS_WKT_WGS84_LAT_LONG);
187 0 : }
188 :
189 : /************************************************************************/
190 : /* ~EnvisatDataset() */
191 : /************************************************************************/
192 :
193 0 : EnvisatDataset::~EnvisatDataset()
194 :
195 : {
196 0 : EnvisatDataset::Close();
197 0 : }
198 :
199 : /************************************************************************/
200 : /* Close() */
201 : /************************************************************************/
202 :
203 0 : CPLErr EnvisatDataset::Close()
204 : {
205 0 : CPLErr eErr = CE_None;
206 0 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
207 : {
208 0 : if (EnvisatDataset::FlushCache(true) != CE_None)
209 0 : eErr = CE_Failure;
210 :
211 0 : if (hEnvisatFile != nullptr)
212 0 : EnvisatFile_Close(hEnvisatFile);
213 :
214 0 : if (fpImage != nullptr)
215 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
216 :
217 0 : if (nGCPCount > 0)
218 : {
219 0 : GDALDeinitGCPs(nGCPCount, pasGCPList);
220 0 : CPLFree(pasGCPList);
221 : }
222 :
223 0 : CSLDestroy(papszTempMD);
224 :
225 0 : if (GDALPamDataset::Close() != CE_None)
226 0 : eErr = CE_Failure;
227 : }
228 0 : return eErr;
229 : }
230 :
231 : /************************************************************************/
232 : /* GetGCPCount() */
233 : /************************************************************************/
234 :
235 0 : int EnvisatDataset::GetGCPCount()
236 :
237 : {
238 0 : return nGCPCount;
239 : }
240 :
241 : /************************************************************************/
242 : /* GetGCPSpatialRef() */
243 : /************************************************************************/
244 :
245 0 : const OGRSpatialReference *EnvisatDataset::GetGCPSpatialRef() const
246 :
247 : {
248 0 : if (nGCPCount > 0)
249 0 : return &m_oGCPSRS;
250 :
251 0 : return nullptr;
252 : }
253 :
254 : /************************************************************************/
255 : /* GetGCP() */
256 : /************************************************************************/
257 :
258 0 : const GDAL_GCP *EnvisatDataset::GetGCPs()
259 :
260 : {
261 0 : return pasGCPList;
262 : }
263 :
264 : /************************************************************************/
265 : /* UnwrapGCPs() */
266 : /************************************************************************/
267 :
268 : /* external C++ implementation of the in-place unwrapper */
269 : void EnvisatUnwrapGCPs(int nGCPCount, GDAL_GCP *pasGCPList);
270 :
271 0 : void EnvisatDataset::UnwrapGCPs()
272 : {
273 0 : EnvisatUnwrapGCPs(nGCPCount, pasGCPList);
274 0 : }
275 :
276 : /************************************************************************/
277 : /* ScanForGCPs_ASAR() */
278 : /************************************************************************/
279 :
280 0 : void EnvisatDataset::ScanForGCPs_ASAR()
281 :
282 : {
283 : /* -------------------------------------------------------------------- */
284 : /* Do we have a meaningful geolocation grid? */
285 : /* -------------------------------------------------------------------- */
286 : int nDatasetIndex =
287 0 : EnvisatFile_GetDatasetIndex(hEnvisatFile, "GEOLOCATION GRID ADS");
288 0 : if (nDatasetIndex == -1)
289 0 : return;
290 :
291 : int nNumDSR, nDSRSize;
292 0 : if (EnvisatFile_GetDatasetInfo(hEnvisatFile, nDatasetIndex, nullptr,
293 : nullptr, nullptr, nullptr, nullptr, &nNumDSR,
294 0 : &nDSRSize) != SUCCESS)
295 0 : return;
296 :
297 0 : if (nNumDSR == 0 || nDSRSize != 521)
298 0 : return;
299 :
300 : /* -------------------------------------------------------------------- */
301 : /* Collect the first GCP set from each record. */
302 : /* -------------------------------------------------------------------- */
303 : GByte abyRecord[521];
304 0 : int nRange = 0;
305 0 : int nRangeOffset = 0;
306 : GUInt32 unValue;
307 :
308 0 : nGCPCount = 0;
309 0 : pasGCPList = (GDAL_GCP *)CPLCalloc(sizeof(GDAL_GCP), (nNumDSR + 1) * 11);
310 :
311 0 : for (int iRecord = 0; iRecord < nNumDSR; iRecord++)
312 : {
313 0 : if (EnvisatFile_ReadDatasetRecord(hEnvisatFile, nDatasetIndex, iRecord,
314 0 : abyRecord) != SUCCESS)
315 0 : continue;
316 :
317 0 : memcpy(&unValue, abyRecord + 13, 4);
318 0 : nRange = CPL_MSBWORD32(unValue) + nRangeOffset;
319 :
320 0 : if ((iRecord > 1) &&
321 0 : (int(pasGCPList[nGCPCount - 1].dfGCPLine + 0.5) > nRange))
322 : {
323 0 : int delta = (int)(pasGCPList[nGCPCount - 1].dfGCPLine -
324 0 : pasGCPList[nGCPCount - 12].dfGCPLine);
325 0 : nRange = int(pasGCPList[nGCPCount - 1].dfGCPLine + 0.5) + delta;
326 0 : nRangeOffset = nRange - 1;
327 : }
328 :
329 0 : for (int iGCP = 0; iGCP < 11; iGCP++)
330 : {
331 0 : GDALInitGCPs(1, pasGCPList + nGCPCount);
332 :
333 0 : CPLFree(pasGCPList[nGCPCount].pszId);
334 :
335 : char szId[128];
336 0 : snprintf(szId, sizeof(szId), "%d", nGCPCount + 1);
337 0 : pasGCPList[nGCPCount].pszId = CPLStrdup(szId);
338 :
339 0 : memcpy(&unValue, abyRecord + 25 + iGCP * 4, 4);
340 0 : int nSample = CPL_MSBWORD32(unValue);
341 :
342 0 : memcpy(&unValue, abyRecord + 25 + 176 + iGCP * 4, 4);
343 0 : pasGCPList[nGCPCount].dfGCPX =
344 0 : ((int)CPL_MSBWORD32(unValue)) * 0.000001;
345 :
346 0 : memcpy(&unValue, abyRecord + 25 + 132 + iGCP * 4, 4);
347 0 : pasGCPList[nGCPCount].dfGCPY =
348 0 : ((int)CPL_MSBWORD32(unValue)) * 0.000001;
349 :
350 0 : pasGCPList[nGCPCount].dfGCPZ = 0.0;
351 :
352 0 : pasGCPList[nGCPCount].dfGCPLine = nRange - 0.5;
353 0 : pasGCPList[nGCPCount].dfGCPPixel = nSample - 0.5;
354 :
355 0 : nGCPCount++;
356 : }
357 : }
358 :
359 : /* -------------------------------------------------------------------- */
360 : /* We also collect the bottom GCPs from the last granule. */
361 : /* -------------------------------------------------------------------- */
362 0 : memcpy(&unValue, abyRecord + 17, 4);
363 0 : nRange = nRange + CPL_MSBWORD32(unValue) - 1;
364 :
365 0 : for (int iGCP = 0; iGCP < 11; iGCP++)
366 : {
367 0 : GDALInitGCPs(1, pasGCPList + nGCPCount);
368 :
369 0 : CPLFree(pasGCPList[nGCPCount].pszId);
370 :
371 : char szId[128];
372 0 : snprintf(szId, sizeof(szId), "%d", nGCPCount + 1);
373 0 : pasGCPList[nGCPCount].pszId = CPLStrdup(szId);
374 :
375 0 : memcpy(&unValue, abyRecord + 279 + iGCP * 4, 4);
376 0 : int nSample = CPL_MSBWORD32(unValue);
377 :
378 0 : memcpy(&unValue, abyRecord + 279 + 176 + iGCP * 4, 4);
379 0 : pasGCPList[nGCPCount].dfGCPX = ((int)CPL_MSBWORD32(unValue)) * 0.000001;
380 :
381 0 : memcpy(&unValue, abyRecord + 279 + 132 + iGCP * 4, 4);
382 0 : pasGCPList[nGCPCount].dfGCPY = ((int)CPL_MSBWORD32(unValue)) * 0.000001;
383 :
384 0 : pasGCPList[nGCPCount].dfGCPZ = 0.0;
385 :
386 0 : pasGCPList[nGCPCount].dfGCPLine = nRange - 0.5;
387 0 : pasGCPList[nGCPCount].dfGCPPixel = nSample - 0.5;
388 :
389 0 : nGCPCount++;
390 : }
391 : }
392 :
393 : /************************************************************************/
394 : /* ScanForGCPs_MERIS() */
395 : /************************************************************************/
396 :
397 0 : void EnvisatDataset::ScanForGCPs_MERIS()
398 :
399 : {
400 : /* -------------------------------------------------------------------- */
401 : /* Do we have a meaningful geolocation grid? Search for a */
402 : /* DS_TYPE=A and a name containing "geolocation" or "tie */
403 : /* points". */
404 : /* -------------------------------------------------------------------- */
405 : int nDatasetIndex =
406 0 : EnvisatFile_GetDatasetIndex(hEnvisatFile, "Tie points ADS");
407 0 : if (nDatasetIndex == -1)
408 0 : return;
409 :
410 : int nNumDSR, nDSRSize;
411 0 : if (EnvisatFile_GetDatasetInfo(hEnvisatFile, nDatasetIndex, nullptr,
412 : nullptr, nullptr, nullptr, nullptr, &nNumDSR,
413 0 : &nDSRSize) != SUCCESS)
414 0 : return;
415 :
416 0 : if (nNumDSR == 0)
417 0 : return;
418 :
419 : /* -------------------------------------------------------------------- */
420 : /* Figure out the tiepoint space, and how many we have. */
421 : /* -------------------------------------------------------------------- */
422 : int nLinesPerTiePoint =
423 0 : EnvisatFile_GetKeyValueAsInt(hEnvisatFile, SPH, "LINES_PER_TIE_PT", 0);
424 0 : int nSamplesPerTiePoint = EnvisatFile_GetKeyValueAsInt(
425 : hEnvisatFile, SPH, "SAMPLES_PER_TIE_PT", 0);
426 :
427 0 : if (nLinesPerTiePoint == 0 || nSamplesPerTiePoint == 0)
428 0 : return;
429 :
430 0 : int nTPPerColumn = nNumDSR;
431 : int nTPPerLine =
432 0 : (GetRasterXSize() + nSamplesPerTiePoint - 1) / nSamplesPerTiePoint;
433 :
434 : /* -------------------------------------------------------------------- */
435 : /* Find a measurement type dataset to use as a reference raster */
436 : /* band. */
437 : /* -------------------------------------------------------------------- */
438 :
439 0 : int nMDSIndex = 0;
440 :
441 0 : for (; true; nMDSIndex++)
442 : {
443 0 : const char *pszDSType = nullptr;
444 0 : if (EnvisatFile_GetDatasetInfo(hEnvisatFile, nMDSIndex, nullptr,
445 : &pszDSType, nullptr, nullptr, nullptr,
446 0 : nullptr, nullptr) == FAILURE)
447 : {
448 0 : CPLDebug("EnvisatDataset", "Unable to find MDS in Envisat file.");
449 0 : return;
450 : }
451 0 : if (EQUAL(pszDSType, "M"))
452 0 : break;
453 0 : }
454 :
455 : /* -------------------------------------------------------------------- */
456 : /* Get subset of TP ADS records matching the MDS records */
457 : /* -------------------------------------------------------------------- */
458 :
459 : /* get the MDS line sampling time interval */
460 : TimeDelta tdMDSSamplingInterval(
461 : 0, 0,
462 : EnvisatFile_GetKeyValueAsInt(hEnvisatFile, SPH, "LINE_TIME_INTERVAL",
463 0 : 0));
464 :
465 : /* get range of TiePoint ADS records matching the measurements */
466 0 : ADSRangeLastAfter arTP(*hEnvisatFile, nDatasetIndex, nMDSIndex,
467 0 : tdMDSSamplingInterval);
468 :
469 : /* check if there are any TPs to be used */
470 0 : if (arTP.getDSRCount() <= 0)
471 : {
472 0 : CPLDebug("EnvisatDataset", "No tiepoint covering "
473 : "the measurement records.");
474 0 : return; /* No TPs - no extraction. */
475 : }
476 :
477 : /* check if TPs cover the whole range of MDSRs */
478 0 : if ((arTP.getFirstOffset() < 0) || (arTP.getLastOffset() < 0))
479 : {
480 0 : CPLDebug("EnvisatDataset", "The tiepoints do not cover "
481 : "whole range of measurement records.");
482 : /* Not good but we can still extract some of the TPS, can we? */
483 : }
484 :
485 : /* Check TP record spacing */
486 0 : if ((1 +
487 0 : (arTP.getFirstOffset() + arTP.getLastOffset() + GetRasterYSize() - 1) /
488 0 : nLinesPerTiePoint) != arTP.getDSRCount())
489 : {
490 0 : CPLDebug("EnvisatDataset",
491 : "Not enough tiepoints per column! "
492 : "received=%d expected=%d",
493 : nTPPerColumn,
494 0 : 1 + (arTP.getFirstOffset() + arTP.getLastOffset() +
495 0 : GetRasterYSize() - 1) /
496 : nLinesPerTiePoint);
497 0 : return; // That is far more serious - we risk misplacing TPs.
498 : }
499 :
500 : bool isBrowseProduct;
501 0 : if (50 * nTPPerLine + 13 == nDSRSize) /* regular product */
502 : {
503 0 : isBrowseProduct = false;
504 : }
505 0 : else if (8 * nTPPerLine + 13 == nDSRSize) /* browse product */
506 : {
507 : /* although BPs are rare there is no reason not to support them */
508 0 : isBrowseProduct = true;
509 : }
510 : else
511 : {
512 0 : CPLDebug("EnvisatDataset",
513 : "Unexpected size of 'Tie points ADS' !"
514 : " received=%d expected=%d or %d",
515 0 : nDSRSize, 50 * nTPPerLine + 13, 8 * nTPPerLine + 13);
516 0 : return;
517 : }
518 :
519 : /* -------------------------------------------------------------------- */
520 : /* Collect the first GCP set from each record. */
521 : /* -------------------------------------------------------------------- */
522 :
523 0 : GByte *pabyRecord = (GByte *)CPLMalloc(nDSRSize - 13);
524 :
525 0 : GUInt32 *tpLat = ((GUInt32 *)pabyRecord) + nTPPerLine * 0; /* latitude */
526 0 : GUInt32 *tpLon = ((GUInt32 *)pabyRecord) + nTPPerLine * 1; /* longitude */
527 0 : GUInt32 *tpLtc =
528 0 : ((GUInt32 *)pabyRecord) + nTPPerLine * 4; /* lat. DEM correction */
529 0 : GUInt32 *tpLnc =
530 0 : ((GUInt32 *)pabyRecord) + nTPPerLine * 5; /* lon. DEM correction */
531 :
532 0 : nGCPCount = 0;
533 0 : pasGCPList = (GDAL_GCP *)CPLCalloc(
534 0 : sizeof(GDAL_GCP), static_cast<size_t>(arTP.getDSRCount()) * nTPPerLine);
535 :
536 0 : for (int ir = 0; ir < arTP.getDSRCount(); ir++)
537 : {
538 0 : int iRecord = ir + arTP.getFirstIndex();
539 :
540 : double dfGCPLine =
541 0 : 0.5 + (iRecord * nLinesPerTiePoint - arTP.getFirstOffset());
542 :
543 0 : if (EnvisatFile_ReadDatasetRecordChunk(hEnvisatFile, nDatasetIndex,
544 : iRecord, pabyRecord, 13,
545 0 : -1) != SUCCESS)
546 0 : continue;
547 :
548 0 : for (int iGCP = 0; iGCP < nTPPerLine; iGCP++)
549 : {
550 0 : GDALInitGCPs(1, pasGCPList + nGCPCount);
551 :
552 0 : CPLFree(pasGCPList[nGCPCount].pszId);
553 :
554 : char szId[128];
555 0 : snprintf(szId, sizeof(szId), "%d", nGCPCount + 1);
556 0 : pasGCPList[nGCPCount].pszId = CPLStrdup(szId);
557 :
558 : #define INT32(x) ((GInt32)CPL_MSBWORD32(x))
559 :
560 0 : pasGCPList[nGCPCount].dfGCPX = 1e-6 * INT32(tpLon[iGCP]);
561 0 : pasGCPList[nGCPCount].dfGCPY = 1e-6 * INT32(tpLat[iGCP]);
562 0 : pasGCPList[nGCPCount].dfGCPZ = 0.0;
563 :
564 0 : if (!isBrowseProduct) /* add DEM corrections */
565 : {
566 0 : pasGCPList[nGCPCount].dfGCPX += 1e-6 * INT32(tpLnc[iGCP]);
567 0 : pasGCPList[nGCPCount].dfGCPY += 1e-6 * INT32(tpLtc[iGCP]);
568 : }
569 :
570 : #undef INT32
571 :
572 0 : pasGCPList[nGCPCount].dfGCPLine = dfGCPLine;
573 0 : pasGCPList[nGCPCount].dfGCPPixel = iGCP * nSamplesPerTiePoint + 0.5;
574 :
575 0 : nGCPCount++;
576 : }
577 : }
578 0 : CPLFree(pabyRecord);
579 : }
580 :
581 : /************************************************************************/
582 : /* GetMetadataDomainList() */
583 : /************************************************************************/
584 :
585 0 : char **EnvisatDataset::GetMetadataDomainList()
586 : {
587 0 : return CSLAddString(GDALDataset::GetMetadataDomainList(), "envisat-ds-*-*");
588 : }
589 :
590 : /************************************************************************/
591 : /* GetMetadata() */
592 : /************************************************************************/
593 :
594 0 : char **EnvisatDataset::GetMetadata(const char *pszDomain)
595 :
596 : {
597 0 : if (pszDomain == nullptr || !STARTS_WITH_CI(pszDomain, "envisat-ds-"))
598 0 : return GDALDataset::GetMetadata(pszDomain);
599 :
600 : /* -------------------------------------------------------------------- */
601 : /* Get the dataset name and record number. */
602 : /* -------------------------------------------------------------------- */
603 : char szDSName[128];
604 0 : strncpy(szDSName, pszDomain + 11, sizeof(szDSName));
605 0 : szDSName[sizeof(szDSName) - 1] = 0;
606 :
607 0 : int nRecord = -1;
608 0 : for (int i = 0; i < (int)sizeof(szDSName) - 1; i++)
609 : {
610 0 : if (szDSName[i] == '-')
611 : {
612 0 : szDSName[i] = '\0';
613 0 : nRecord = atoi(szDSName + 1);
614 0 : break;
615 : }
616 : }
617 :
618 0 : if (nRecord == -1)
619 0 : return nullptr;
620 :
621 : /* -------------------------------------------------------------------- */
622 : /* Get the dataset index and info. */
623 : /* -------------------------------------------------------------------- */
624 0 : int nDSIndex = EnvisatFile_GetDatasetIndex(hEnvisatFile, szDSName);
625 0 : if (nDSIndex == -1)
626 0 : return nullptr;
627 :
628 : int nDSRSize, nNumDSR;
629 0 : EnvisatFile_GetDatasetInfo(hEnvisatFile, nDSIndex, nullptr, nullptr,
630 : nullptr, nullptr, nullptr, &nNumDSR, &nDSRSize);
631 :
632 0 : if (nDSRSize == -1 || nRecord < 0 || nRecord >= nNumDSR)
633 0 : return nullptr;
634 :
635 : /* -------------------------------------------------------------------- */
636 : /* Read the requested record. */
637 : /* -------------------------------------------------------------------- */
638 0 : char *pszRecord = (char *)CPLMalloc(nDSRSize + 1);
639 :
640 0 : if (EnvisatFile_ReadDatasetRecord(hEnvisatFile, nDSIndex, nRecord,
641 0 : pszRecord) == FAILURE)
642 : {
643 0 : CPLFree(pszRecord);
644 0 : return nullptr;
645 : }
646 :
647 : /* -------------------------------------------------------------------- */
648 : /* Massage the data into a safe textual format. For now we */
649 : /* just turn zero bytes into spaces. */
650 : /* -------------------------------------------------------------------- */
651 0 : CSLDestroy(papszTempMD);
652 :
653 : char *pszEscapedRecord =
654 0 : CPLEscapeString(pszRecord, nDSRSize, CPLES_BackslashQuotable);
655 0 : papszTempMD = CSLSetNameValue(nullptr, "EscapedRecord", pszEscapedRecord);
656 0 : CPLFree(pszEscapedRecord);
657 :
658 0 : for (int i = 0; i < nDSRSize; i++)
659 0 : if (pszRecord[i] == '\0')
660 0 : pszRecord[i] = ' ';
661 :
662 0 : papszTempMD = CSLSetNameValue(papszTempMD, "RawRecord", pszRecord);
663 :
664 0 : CPLFree(pszRecord);
665 :
666 0 : return papszTempMD;
667 : }
668 :
669 : /************************************************************************/
670 : /* CollectDSDMetadata() */
671 : /* */
672 : /* Collect metadata based on any DSD entries with filenames */
673 : /* associated. */
674 : /************************************************************************/
675 :
676 0 : void EnvisatDataset::CollectDSDMetadata()
677 :
678 : {
679 : const char *pszDSName;
680 : const char *pszFilename;
681 :
682 0 : for (int iDSD = 0;
683 0 : EnvisatFile_GetDatasetInfo(hEnvisatFile, iDSD, &pszDSName, nullptr,
684 : &pszFilename, nullptr, nullptr, nullptr,
685 0 : nullptr) == SUCCESS;
686 : iDSD++)
687 : {
688 0 : if (pszFilename == nullptr || strlen(pszFilename) == 0 ||
689 0 : STARTS_WITH_CI(pszFilename, "NOT USED") ||
690 0 : STARTS_WITH_CI(pszFilename, " "))
691 0 : continue;
692 :
693 0 : std::string osKey("DS_");
694 0 : osKey += pszDSName;
695 : // strip trailing spaces.
696 : {
697 0 : const auto nPos = osKey.rfind(' ');
698 0 : if (nPos != std::string::npos)
699 0 : osKey.resize(nPos);
700 : }
701 :
702 : // convert spaces into underscores.
703 0 : for (char &ch : osKey)
704 : {
705 0 : if (ch == ' ')
706 0 : ch = '_';
707 : }
708 :
709 0 : osKey += "_NAME";
710 :
711 0 : std::string osTrimmedName(pszFilename);
712 : {
713 0 : const auto nPos = osTrimmedName.rfind(' ');
714 0 : if (nPos != std::string::npos)
715 0 : osTrimmedName.resize(nPos);
716 : }
717 :
718 0 : SetMetadataItem(osKey.c_str(), osTrimmedName.c_str());
719 : }
720 0 : }
721 :
722 : /************************************************************************/
723 : /* CollectADSMetadata() */
724 : /* */
725 : /* Collect metadata from envisat ADS and GADS. */
726 : /************************************************************************/
727 :
728 0 : void EnvisatDataset::CollectADSMetadata()
729 : {
730 : int nNumDsr, nDSRSize;
731 : const char *pszDSName;
732 : const char *pszDSType;
733 : const char *pszDSFilename;
734 :
735 : const char *pszProduct =
736 0 : EnvisatFile_GetKeyValueAsString(hEnvisatFile, MPH, "PRODUCT", "");
737 :
738 0 : for (int nDSIndex = 0;
739 0 : EnvisatFile_GetDatasetInfo(hEnvisatFile, nDSIndex, &pszDSName,
740 : &pszDSType, &pszDSFilename, nullptr,
741 0 : nullptr, &nNumDsr, &nDSRSize) == SUCCESS;
742 : ++nDSIndex)
743 : {
744 0 : if (STARTS_WITH_CI(pszDSFilename, "NOT USED") || (nNumDsr <= 0))
745 0 : continue;
746 0 : if (!EQUAL(pszDSType, "A") && !EQUAL(pszDSType, "G"))
747 0 : continue;
748 :
749 0 : for (int nRecord = 0; nRecord < nNumDsr; ++nRecord)
750 : {
751 : char szPrefix[128];
752 0 : strncpy(szPrefix, pszDSName, sizeof(szPrefix) - 1);
753 0 : szPrefix[sizeof(szPrefix) - 1] = '\0';
754 :
755 : // strip trailing spaces
756 0 : for (int i = static_cast<int>(strlen(szPrefix)) - 1;
757 0 : i && szPrefix[i] == ' '; --i)
758 0 : szPrefix[i] = '\0';
759 :
760 : // convert spaces into underscores
761 0 : for (int i = 0; szPrefix[i] != '\0'; i++)
762 : {
763 0 : if (szPrefix[i] == ' ')
764 0 : szPrefix[i] = '_';
765 : }
766 :
767 0 : char *pszRecord = (char *)CPLMalloc(nDSRSize + 1);
768 :
769 0 : if (EnvisatFile_ReadDatasetRecord(hEnvisatFile, nDSIndex, nRecord,
770 0 : pszRecord) == FAILURE)
771 : {
772 0 : CPLFree(pszRecord);
773 0 : return;
774 : }
775 :
776 : const EnvisatRecordDescr *pRecordDescr =
777 0 : EnvisatFile_GetRecordDescriptor(pszProduct, pszDSName);
778 0 : if (pRecordDescr)
779 : {
780 0 : const EnvisatFieldDescr *pField = pRecordDescr->pFields;
781 0 : while (pField && pField->szName)
782 : {
783 : char szValue[1024];
784 0 : if (CE_None == EnvisatFile_GetFieldAsString(
785 : pszRecord, nDSRSize, pField, szValue,
786 : sizeof(szValue)))
787 : {
788 : char szKey[256];
789 0 : if (nNumDsr == 1)
790 0 : snprintf(szKey, sizeof(szKey), "%s_%s", szPrefix,
791 0 : pField->szName);
792 : else
793 : // sprintf(szKey, "%s_%02d_%s", szPrefix, nRecord,
794 0 : snprintf(szKey, sizeof(szKey), "%s_%d_%s", szPrefix,
795 0 : nRecord, pField->szName);
796 0 : SetMetadataItem(szKey, szValue, "RECORDS");
797 : }
798 : // silently ignore conversion errors
799 :
800 0 : ++pField;
801 : }
802 : }
803 0 : CPLFree(pszRecord);
804 : }
805 : }
806 : }
807 :
808 : /************************************************************************/
809 : /* CollectMetadata() */
810 : /* */
811 : /* Collect metadata from the SPH or MPH header fields. */
812 : /************************************************************************/
813 :
814 0 : void EnvisatDataset::CollectMetadata(EnvisatFile_HeaderFlag eMPHOrSPH)
815 :
816 : {
817 0 : for (int iKey = 0; true; iKey++)
818 : {
819 : const char *pszKey =
820 0 : EnvisatFile_GetKeyByIndex(hEnvisatFile, eMPHOrSPH, iKey);
821 0 : if (pszKey == nullptr)
822 0 : break;
823 :
824 0 : const char *pszValue = EnvisatFile_GetKeyValueAsString(
825 : hEnvisatFile, eMPHOrSPH, pszKey, nullptr);
826 :
827 0 : if (pszValue == nullptr)
828 0 : continue;
829 :
830 : // skip some uninteresting structural information.
831 0 : if (EQUAL(pszKey, "TOT_SIZE") || EQUAL(pszKey, "SPH_SIZE") ||
832 0 : EQUAL(pszKey, "NUM_DSD") || EQUAL(pszKey, "DSD_SIZE") ||
833 0 : EQUAL(pszKey, "NUM_DATA_SETS"))
834 0 : continue;
835 :
836 : char szHeaderKey[128];
837 0 : if (eMPHOrSPH == MPH)
838 0 : snprintf(szHeaderKey, sizeof(szHeaderKey), "MPH_%s", pszKey);
839 : else
840 0 : snprintf(szHeaderKey, sizeof(szHeaderKey), "SPH_%s", pszKey);
841 :
842 0 : SetMetadataItem(szHeaderKey, pszValue);
843 0 : }
844 0 : }
845 :
846 : /************************************************************************/
847 : /* Open() */
848 : /************************************************************************/
849 :
850 34587 : GDALDataset *EnvisatDataset::Open(GDALOpenInfo *poOpenInfo)
851 :
852 : {
853 : /* -------------------------------------------------------------------- */
854 : /* Check the header. */
855 : /* -------------------------------------------------------------------- */
856 34587 : if (poOpenInfo->nHeaderBytes < 8 || poOpenInfo->fpL == nullptr)
857 28599 : return nullptr;
858 :
859 5988 : if (!STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "PRODUCT="))
860 5988 : return nullptr;
861 :
862 : /* -------------------------------------------------------------------- */
863 : /* Try opening the dataset. */
864 : /* -------------------------------------------------------------------- */
865 0 : EnvisatFile *hEnvisatFile = nullptr;
866 0 : if (EnvisatFile_Open(&hEnvisatFile, poOpenInfo->pszFilename, "r") ==
867 : FAILURE)
868 0 : return nullptr;
869 :
870 : /* -------------------------------------------------------------------- */
871 : /* Find a measurement type dataset to use as our reference */
872 : /* raster band. */
873 : /* -------------------------------------------------------------------- */
874 : int dsr_size, num_dsr, ds_offset;
875 0 : const char *pszDSType = nullptr;
876 :
877 0 : int ds_index = 0;
878 0 : for (; true; ds_index++)
879 : {
880 0 : if (EnvisatFile_GetDatasetInfo(hEnvisatFile, ds_index, nullptr,
881 : &pszDSType, nullptr, &ds_offset, nullptr,
882 0 : &num_dsr, &dsr_size) == FAILURE)
883 : {
884 0 : CPLError(CE_Failure, CPLE_AppDefined,
885 : "Unable to find \"MDS1\" measurement dataset in "
886 : "Envisat file.");
887 0 : EnvisatFile_Close(hEnvisatFile);
888 0 : return nullptr;
889 : }
890 :
891 : /* Have we found what we are looking for? A Measurement ds. */
892 0 : if (EQUAL(pszDSType, "M"))
893 0 : break;
894 : }
895 :
896 : /* -------------------------------------------------------------------- */
897 : /* Confirm the requested access is supported. */
898 : /* -------------------------------------------------------------------- */
899 0 : if (poOpenInfo->eAccess == GA_Update)
900 : {
901 0 : EnvisatFile_Close(hEnvisatFile);
902 0 : CPLError(CE_Failure, CPLE_NotSupported,
903 : "The ENVISAT driver does not support update access to existing"
904 : " datasets.\n");
905 0 : return nullptr;
906 : }
907 : /* -------------------------------------------------------------------- */
908 : /* Create a corresponding GDALDataset. */
909 : /* -------------------------------------------------------------------- */
910 0 : auto poDS = std::make_unique<EnvisatDataset>();
911 :
912 0 : poDS->hEnvisatFile = hEnvisatFile;
913 :
914 : /* -------------------------------------------------------------------- */
915 : /* Setup image definition. */
916 : /* -------------------------------------------------------------------- */
917 0 : EnvisatFile_GetDatasetInfo(hEnvisatFile, ds_index, nullptr, nullptr,
918 : nullptr, &ds_offset, nullptr, &num_dsr,
919 : &dsr_size);
920 :
921 0 : poDS->nRasterXSize =
922 0 : EnvisatFile_GetKeyValueAsInt(hEnvisatFile, SPH, "LINE_LENGTH", 0);
923 0 : poDS->nRasterYSize = num_dsr;
924 0 : poDS->eAccess = GA_ReadOnly;
925 :
926 : const char *pszProduct =
927 0 : EnvisatFile_GetKeyValueAsString(hEnvisatFile, MPH, "PRODUCT", "");
928 : const char *pszDataType =
929 0 : EnvisatFile_GetKeyValueAsString(hEnvisatFile, SPH, "DATA_TYPE", "");
930 : const char *pszSampleType =
931 0 : EnvisatFile_GetKeyValueAsString(hEnvisatFile, SPH, "SAMPLE_TYPE", "");
932 :
933 : GDALDataType eDataType;
934 0 : if (EQUAL(pszDataType, "FLT32") && STARTS_WITH_CI(pszSampleType, "COMPLEX"))
935 0 : eDataType = GDT_CFloat32;
936 0 : else if (EQUAL(pszDataType, "FLT32"))
937 0 : eDataType = GDT_Float32;
938 0 : else if (EQUAL(pszDataType, "UWORD"))
939 0 : eDataType = GDT_UInt16;
940 0 : else if (EQUAL(pszDataType, "SWORD") &&
941 0 : STARTS_WITH_CI(pszSampleType, "COMPLEX"))
942 0 : eDataType = GDT_CInt16;
943 0 : else if (EQUAL(pszDataType, "SWORD"))
944 0 : eDataType = GDT_Int16;
945 0 : else if (STARTS_WITH_CI(pszProduct, "ATS_TOA_1"))
946 : {
947 : /* all 16bit data, no line length provided */
948 0 : eDataType = GDT_Int16;
949 0 : poDS->nRasterXSize = (dsr_size - 20) / 2;
950 : }
951 0 : else if (poDS->nRasterXSize == 0)
952 : {
953 0 : CPLError(CE_Warning, CPLE_AppDefined,
954 : "Envisat product format not recognised. Assuming 8bit\n"
955 : "with no per-record prefix data. Results may be useless!");
956 0 : eDataType = GDT_Byte;
957 0 : poDS->nRasterXSize = dsr_size;
958 : }
959 : else
960 : {
961 0 : if (dsr_size >= 2 * poDS->nRasterXSize)
962 0 : eDataType = GDT_UInt16;
963 : else
964 0 : eDataType = GDT_Byte;
965 : }
966 :
967 : int nPrefixBytes =
968 0 : dsr_size - ((GDALGetDataTypeSize(eDataType) / 8) * poDS->nRasterXSize);
969 :
970 : /* -------------------------------------------------------------------- */
971 : /* Fail out if we didn't get non-zero sizes. */
972 : /* -------------------------------------------------------------------- */
973 0 : if (poDS->nRasterXSize < 1 || poDS->nRasterYSize < 1)
974 : {
975 0 : CPLError(CE_Failure, CPLE_AppDefined,
976 : "Unable to determine organization of dataset. It would\n"
977 : "appear this is an Envisat dataset, but an unsupported\n"
978 : "data product. Unable to utilize.");
979 0 : return nullptr;
980 : }
981 :
982 0 : std::swap(poDS->fpImage, poOpenInfo->fpL);
983 :
984 : /* -------------------------------------------------------------------- */
985 : /* Try to collect GCPs. */
986 : /* -------------------------------------------------------------------- */
987 :
988 : /* -------------------------------------------------------------------- */
989 : /* Scan for all datasets matching the reference dataset. */
990 : /* -------------------------------------------------------------------- */
991 0 : int num_dsr2, dsr_size2, iBand = 0;
992 0 : const char *pszDSName = nullptr;
993 : char szBandName[128];
994 : bool bMiltiChannel;
995 :
996 0 : for (ds_index = 0;
997 0 : EnvisatFile_GetDatasetInfo(hEnvisatFile, ds_index, &pszDSName, nullptr,
998 : nullptr, &ds_offset, nullptr, &num_dsr2,
999 0 : &dsr_size2) == SUCCESS;
1000 : ds_index++)
1001 : {
1002 0 : if (!EQUAL(pszDSType, "M") || num_dsr2 != num_dsr)
1003 0 : continue;
1004 :
1005 0 : if (STARTS_WITH_CI(pszProduct, "MER") && (pszProduct[8] == '2') &&
1006 0 : ((strstr(pszDSName, "MDS(16)") != nullptr) ||
1007 0 : (strstr(pszDSName, "MDS(19)") != nullptr)))
1008 0 : bMiltiChannel = true;
1009 : else
1010 0 : bMiltiChannel = false;
1011 :
1012 0 : if ((dsr_size2 == dsr_size) && !bMiltiChannel)
1013 : {
1014 : auto poBand = RawRasterBand::Create(
1015 0 : poDS.get(), iBand + 1, poDS->fpImage, ds_offset + nPrefixBytes,
1016 0 : GDALGetDataTypeSize(eDataType) / 8, dsr_size, eDataType,
1017 : RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
1018 0 : RawRasterBand::OwnFP::NO);
1019 0 : if (!poBand)
1020 0 : return nullptr;
1021 0 : poBand->SetDescription(pszDSName);
1022 0 : poDS->SetBand(iBand + 1, std::move(poBand));
1023 0 : iBand++;
1024 : }
1025 : /* --------------------------------------------------------------------
1026 : */
1027 : /* Handle MERIS Level 2 datasets with data type different from */
1028 : /* the one declared in the SPH */
1029 : /* --------------------------------------------------------------------
1030 : */
1031 0 : else if (STARTS_WITH_CI(pszProduct, "MER") &&
1032 0 : (strstr(pszDSName, "Flags") != nullptr))
1033 : {
1034 0 : if (pszProduct[8] == '1')
1035 : {
1036 : // Flags
1037 : {
1038 : auto poBand = RawRasterBand::Create(
1039 0 : poDS.get(), iBand + 1, poDS->fpImage,
1040 0 : ds_offset + nPrefixBytes, 3, dsr_size, GDT_Byte,
1041 : RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
1042 0 : RawRasterBand::OwnFP::NO);
1043 0 : if (!poBand)
1044 0 : return nullptr;
1045 0 : poBand->SetDescription(pszDSName);
1046 0 : poDS->SetBand(iBand + 1, std::move(poBand));
1047 0 : iBand++;
1048 : }
1049 :
1050 : // Detector indices
1051 : auto poBand = RawRasterBand::Create(
1052 0 : poDS.get(), iBand + 1, poDS->fpImage,
1053 0 : ds_offset + nPrefixBytes + 1, 3, dsr_size, GDT_Int16,
1054 : RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
1055 0 : RawRasterBand::OwnFP::NO);
1056 0 : if (!poBand)
1057 0 : return nullptr;
1058 :
1059 0 : const char *pszSuffix = strstr(pszDSName, "MDS");
1060 0 : if (pszSuffix != nullptr)
1061 0 : snprintf(szBandName, sizeof(szBandName),
1062 : "Detector index %s", pszSuffix);
1063 : else
1064 0 : snprintf(szBandName, sizeof(szBandName), "%s",
1065 : "Detector index");
1066 0 : poBand->SetDescription(szBandName);
1067 :
1068 0 : poDS->SetBand(iBand + 1, std::move(poBand));
1069 0 : iBand++;
1070 : }
1071 0 : else if ((pszProduct[8] == '2') &&
1072 0 : (dsr_size2 >= 3 * poDS->nRasterXSize))
1073 : {
1074 0 : int nFlagPrefixBytes = dsr_size2 - 3 * poDS->nRasterXSize;
1075 :
1076 : auto poBand =
1077 0 : new MerisL2FlagBand(poDS.get(), iBand + 1, poDS->fpImage,
1078 0 : ds_offset, nFlagPrefixBytes);
1079 0 : poBand->SetDescription(pszDSName);
1080 0 : poDS->SetBand(iBand + 1, poBand);
1081 0 : iBand++;
1082 0 : }
1083 : }
1084 0 : else if (STARTS_WITH_CI(pszProduct, "MER") && (pszProduct[8] == '2'))
1085 : {
1086 : int nPrefixBytes2, nSubBands, nSubBandIdx, nSubBandOffset;
1087 :
1088 0 : int nPixelSize = 1;
1089 0 : GDALDataType eDataType2 = GDT_Byte;
1090 :
1091 0 : nSubBands = dsr_size2 / poDS->nRasterXSize;
1092 0 : if ((nSubBands < 1) || (nSubBands > 3))
1093 0 : nSubBands = 0;
1094 :
1095 0 : nPrefixBytes2 =
1096 0 : dsr_size2 - (nSubBands * nPixelSize * poDS->nRasterXSize);
1097 :
1098 0 : for (nSubBandIdx = 0; nSubBandIdx < nSubBands; ++nSubBandIdx)
1099 : {
1100 0 : nSubBandOffset =
1101 0 : ds_offset + nPrefixBytes2 + nSubBandIdx * nPixelSize;
1102 :
1103 : auto poBand = RawRasterBand::Create(
1104 0 : poDS.get(), iBand + 1, poDS->fpImage, nSubBandOffset,
1105 : nPixelSize * nSubBands, dsr_size2, eDataType2,
1106 : RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
1107 0 : RawRasterBand::OwnFP::NO);
1108 0 : if (!poBand)
1109 0 : return nullptr;
1110 :
1111 0 : if (nSubBands > 1)
1112 : {
1113 0 : snprintf(szBandName, sizeof(szBandName), "%s (%d)",
1114 : pszDSName, nSubBandIdx);
1115 0 : poBand->SetDescription(szBandName);
1116 : }
1117 : else
1118 0 : poBand->SetDescription(pszDSName);
1119 :
1120 0 : poDS->SetBand(iBand + 1, std::move(poBand));
1121 0 : iBand++;
1122 : }
1123 : }
1124 : }
1125 :
1126 : /* -------------------------------------------------------------------- */
1127 : /* Collect metadata. */
1128 : /* -------------------------------------------------------------------- */
1129 0 : poDS->CollectMetadata(MPH);
1130 0 : poDS->CollectMetadata(SPH);
1131 0 : poDS->CollectDSDMetadata();
1132 0 : poDS->CollectADSMetadata();
1133 :
1134 0 : if (STARTS_WITH_CI(pszProduct, "MER"))
1135 0 : poDS->ScanForGCPs_MERIS();
1136 : else
1137 0 : poDS->ScanForGCPs_ASAR();
1138 :
1139 : /* unwrap GCPs for products crossing date border */
1140 0 : poDS->UnwrapGCPs();
1141 :
1142 : /* -------------------------------------------------------------------- */
1143 : /* Initialize any PAM information. */
1144 : /* -------------------------------------------------------------------- */
1145 0 : poDS->SetDescription(poOpenInfo->pszFilename);
1146 0 : poDS->TryLoadXML();
1147 :
1148 : /* -------------------------------------------------------------------- */
1149 : /* Check for overviews. */
1150 : /* -------------------------------------------------------------------- */
1151 0 : poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
1152 :
1153 0 : return poDS.release();
1154 : }
1155 :
1156 : /************************************************************************/
1157 : /* GDALRegister_Envisat() */
1158 : /************************************************************************/
1159 :
1160 1595 : void GDALRegister_Envisat()
1161 :
1162 : {
1163 1595 : if (GDALGetDriverByName("ESAT") != nullptr)
1164 302 : return;
1165 :
1166 1293 : GDALDriver *poDriver = new GDALDriver();
1167 :
1168 1293 : poDriver->SetDescription("ESAT");
1169 1293 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1170 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Envisat Image Format");
1171 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/esat.html");
1172 1293 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "n1");
1173 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1174 :
1175 1293 : poDriver->pfnOpen = EnvisatDataset::Open;
1176 :
1177 1293 : GetGDALDriverManager()->RegisterDriver(poDriver);
1178 : }
|