LCOV - code coverage report
Current view: top level - frmts/envisat - envisatdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 17 478 3.6 %
Date: 2024-11-21 22:18:42 Functions: 2 21 9.5 %

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

Generated by: LCOV version 1.14