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