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