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