LCOV - code coverage report
Current view: top level - frmts/ceos2 - sar_ceosdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 474 966 49.1 %
Date: 2024-11-21 22:18:42 Functions: 12 23 52.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  ASI CEOS Translator
       4             :  * Purpose:  GDALDataset driver for CEOS translator.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2000, 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 "ceos.h"
      15             : #include "cpl_string.h"
      16             : #include "gdal_frmts.h"
      17             : #include "gdal_priv.h"
      18             : #include "rawdataset.h"
      19             : #include "ogr_srs_api.h"
      20             : 
      21             : #include <algorithm>
      22             : 
      23           0 : static GInt16 CastToGInt16(float val)
      24             : {
      25           0 :     if (val < -32768.0)
      26           0 :         val = -32768.0;
      27             : 
      28           0 :     if (val > 32767)
      29           0 :         val = 32767.0;
      30             : 
      31           0 :     return static_cast<GInt16>(val);
      32             : }
      33             : 
      34             : static const char *const CeosExtension[][6] = {
      35             :     {"vol", "led", "img", "trl", "nul", "ext"},
      36             :     {"vol", "lea", "img", "trl", "nul", "ext"},
      37             :     {"vol", "led", "img", "tra", "nul", "ext"},
      38             :     {"vol", "lea", "img", "tra", "nul", "ext"},
      39             :     {"vdf", "slf", "sdf", "stf", "nvd", "ext"},
      40             : 
      41             :     {"vdf", "ldr", "img", "tra", "nul", "ext2"},
      42             : 
      43             :     /* Jers from Japan- not sure if this is generalized as much as it could be
      44             :      */
      45             :     {"VOLD", "Sarl_01", "Imop_%02d", "Sart_01", "NULL", "base"},
      46             : 
      47             :     /* Radarsat: basename, not extension */
      48             :     {"vdf_dat", "lea_%02d", "dat_%02d", "tra_%02d", "nul_vdf", "base"},
      49             : 
      50             :     /* Ers-1: basename, not extension */
      51             :     {"vdf_dat", "lea_%02d", "dat_%02d", "tra_%02d", "nul_dat", "base"},
      52             : 
      53             :     /* Ers-2 from Telaviv */
      54             :     {"volume", "leader", "image", "trailer", "nul_dat", "whole"},
      55             : 
      56             :     /* Ers-1 from D-PAF */
      57             :     {"VDF", "LF", "SLC", "", "", "ext"},
      58             : 
      59             :     /* Radarsat-1 per #2051 */
      60             :     {"vol", "sarl", "sard", "sart", "nvol", "ext"},
      61             : 
      62             :     /* Radarsat-1 ASF */
      63             :     {"", "L", "D", "", "", "ext"},
      64             : 
      65             :     /* end marker */
      66             :     {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}};
      67             : 
      68             : static int ProcessData(VSILFILE *fp, int fileid, CeosSARVolume_t *sar,
      69             :                        int max_records, vsi_l_offset max_bytes);
      70             : 
      71          64 : static CeosTypeCode_t QuadToTC(int a, int b, int c, int d)
      72             : {
      73             :     CeosTypeCode_t abcd;
      74             : 
      75          64 :     abcd.UCharCode.Subtype1 = (unsigned char)a;
      76          64 :     abcd.UCharCode.Type = (unsigned char)b;
      77          64 :     abcd.UCharCode.Subtype2 = (unsigned char)c;
      78          64 :     abcd.UCharCode.Subtype3 = (unsigned char)d;
      79             : 
      80          64 :     return abcd;
      81             : }
      82             : 
      83             : #define LEADER_DATASET_SUMMARY_TC QuadToTC(18, 10, 18, 20)
      84             : #define LEADER_DATASET_SUMMARY_ERS2_TC QuadToTC(10, 10, 31, 20)
      85             : #define LEADER_RADIOMETRIC_COMPENSATION_TC QuadToTC(18, 51, 18, 20)
      86             : #define VOLUME_DESCRIPTOR_RECORD_TC QuadToTC(192, 192, 18, 18)
      87             : #define IMAGE_HEADER_RECORD_TC QuadToTC(63, 192, 18, 18)
      88             : #define LEADER_RADIOMETRIC_DATA_RECORD_TC QuadToTC(18, 50, 18, 20)
      89             : #define LEADER_MAP_PROJ_RECORD_TC QuadToTC(10, 20, 31, 20)
      90             : 
      91             : // TODO: recond?
      92             : /* JERS from Japan has MAP_PROJ recond with different identifiers */
      93             : /* see CEOS-SAR-CCT Iss/Rev: 2/0 February 10, 1989 */
      94             : #define LEADER_MAP_PROJ_RECORD_JERS_TC QuadToTC(18, 20, 18, 20)
      95             : 
      96             : /* Leader from ASF has different identifiers */
      97             : #define LEADER_MAP_PROJ_RECORD_ASF_TC QuadToTC(10, 20, 18, 20)
      98             : #define LEADER_DATASET_SUMMARY_ASF_TC QuadToTC(10, 10, 18, 20)
      99             : #define LEADER_FACILITY_ASF_TC QuadToTC(90, 210, 18, 61)
     100             : 
     101             : /* For ERS calibration and incidence angle information */
     102             : #define ERS_GENERAL_FACILITY_DATA_TC QuadToTC(10, 200, 31, 50)
     103             : #define ERS_GENERAL_FACILITY_DATA_ALT_TC QuadToTC(10, 216, 31, 50)
     104             : 
     105             : #define RSAT_PROC_PARAM_TC QuadToTC(18, 120, 18, 20)
     106             : 
     107             : /************************************************************************/
     108             : /* ==================================================================== */
     109             : /*                              SAR_CEOSDataset                         */
     110             : /* ==================================================================== */
     111             : /************************************************************************/
     112             : 
     113             : class SAR_CEOSRasterBand;
     114             : class CCPRasterBand;
     115             : class PALSARRasterBand;
     116             : 
     117             : class SAR_CEOSDataset final : public GDALPamDataset
     118             : {
     119             :     friend class SAR_CEOSRasterBand;
     120             :     friend class CCPRasterBand;
     121             :     friend class PALSARRasterBand;
     122             : 
     123             :     CeosSARVolume_t sVolume;
     124             : 
     125             :     VSILFILE *fpImage;
     126             : 
     127             :     char **papszTempMD;
     128             : 
     129             :     OGRSpatialReference m_oSRS{};
     130             :     int nGCPCount;
     131             :     GDAL_GCP *pasGCPList;
     132             : 
     133             :     void ScanForGCPs();
     134             :     void ScanForMetadata();
     135             :     int ScanForMapProjection();
     136             :     char **papszExtraFiles;
     137             : 
     138             :   public:
     139             :     SAR_CEOSDataset();
     140             :     ~SAR_CEOSDataset() override;
     141             : 
     142             :     int GetGCPCount() override;
     143             :     const OGRSpatialReference *GetGCPSpatialRef() const override;
     144             :     const GDAL_GCP *GetGCPs() override;
     145             : 
     146             :     char **GetMetadataDomainList() override;
     147             :     char **GetMetadata(const char *pszDomain) override;
     148             : 
     149             :     static GDALDataset *Open(GDALOpenInfo *);
     150             :     virtual char **GetFileList(void) override;
     151             : };
     152             : 
     153             : /************************************************************************/
     154             : /* ==================================================================== */
     155             : /*                          CCPRasterBand                               */
     156             : /* ==================================================================== */
     157             : /************************************************************************/
     158             : 
     159             : class CCPRasterBand final : public GDALPamRasterBand
     160             : {
     161             :     friend class SAR_CEOSDataset;
     162             : 
     163             :   public:
     164             :     CCPRasterBand(SAR_CEOSDataset *, int, GDALDataType);
     165             : 
     166             :     CPLErr IReadBlock(int, int, void *) override;
     167             : };
     168             : 
     169             : /************************************************************************/
     170             : /* ==================================================================== */
     171             : /*                        PALSARRasterBand                              */
     172             : /* ==================================================================== */
     173             : /************************************************************************/
     174             : 
     175             : class PALSARRasterBand final : public GDALPamRasterBand
     176             : {
     177             :     friend class SAR_CEOSDataset;
     178             : 
     179             :   public:
     180             :     PALSARRasterBand(SAR_CEOSDataset *, int);
     181             : 
     182             :     CPLErr IReadBlock(int, int, void *) override;
     183             : };
     184             : 
     185             : /************************************************************************/
     186             : /* ==================================================================== */
     187             : /*                       SAR_CEOSRasterBand                             */
     188             : /* ==================================================================== */
     189             : /************************************************************************/
     190             : 
     191             : class SAR_CEOSRasterBand final : public GDALPamRasterBand
     192             : {
     193             :     friend class SAR_CEOSDataset;
     194             : 
     195             :   public:
     196             :     SAR_CEOSRasterBand(SAR_CEOSDataset *, int, GDALDataType);
     197             : 
     198             :     CPLErr IReadBlock(int, int, void *) override;
     199             : };
     200             : 
     201             : /************************************************************************/
     202             : /*                         SAR_CEOSRasterBand()                         */
     203             : /************************************************************************/
     204             : 
     205           0 : SAR_CEOSRasterBand::SAR_CEOSRasterBand(SAR_CEOSDataset *poGDSIn, int nBandIn,
     206           0 :                                        GDALDataType eType)
     207             : 
     208             : {
     209           0 :     poDS = poGDSIn;
     210           0 :     nBand = nBandIn;
     211             : 
     212           0 :     eDataType = eType;
     213             : 
     214           0 :     nBlockXSize = poGDSIn->nRasterXSize;
     215           0 :     nBlockYSize = 1;
     216           0 : }
     217             : 
     218             : /************************************************************************/
     219             : /*                             IReadBlock()                             */
     220             : /************************************************************************/
     221             : 
     222           0 : CPLErr SAR_CEOSRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff,
     223             :                                       void *pImage)
     224             : {
     225           0 :     SAR_CEOSDataset *poGDS = (SAR_CEOSDataset *)poDS;
     226             : 
     227           0 :     struct CeosSARImageDesc *ImageDesc = &(poGDS->sVolume.ImageDesc);
     228             : 
     229             :     int offset;
     230           0 :     CalcCeosSARImageFilePosition(&(poGDS->sVolume), nBand, nBlockYOff + 1,
     231             :                                  nullptr, &offset);
     232             : 
     233           0 :     offset += ImageDesc->ImageDataStart;
     234             : 
     235             :     /* -------------------------------------------------------------------- */
     236             :     /*      Load all the pixel data associated with this scanline.          */
     237             :     /*      Ensure we handle multiple record scanlines properly.            */
     238             :     /* -------------------------------------------------------------------- */
     239           0 :     int nPixelsRead = 0;
     240             : 
     241             :     GByte *pabyRecord =
     242           0 :         (GByte *)VSI_MALLOC2_VERBOSE(ImageDesc->BytesPerPixel, nBlockXSize);
     243           0 :     if (!pabyRecord)
     244           0 :         return CE_Failure;
     245             : 
     246           0 :     for (int iRecord = 0; iRecord < ImageDesc->RecordsPerLine; iRecord++)
     247             :     {
     248             :         int nPixelsToRead;
     249             : 
     250           0 :         if (nPixelsRead + ImageDesc->PixelsPerRecord > nBlockXSize)
     251           0 :             nPixelsToRead = nBlockXSize - nPixelsRead;
     252             :         else
     253           0 :             nPixelsToRead = ImageDesc->PixelsPerRecord;
     254             : 
     255           0 :         CPL_IGNORE_RET_VAL(VSIFSeekL(poGDS->fpImage, offset, SEEK_SET));
     256           0 :         CPL_IGNORE_RET_VAL(VSIFReadL(
     257           0 :             pabyRecord +
     258           0 :                 static_cast<size_t>(nPixelsRead) * ImageDesc->BytesPerPixel,
     259           0 :             1, static_cast<size_t>(nPixelsToRead) * ImageDesc->BytesPerPixel,
     260             :             poGDS->fpImage));
     261             : 
     262           0 :         nPixelsRead += nPixelsToRead;
     263           0 :         offset += ImageDesc->BytesPerRecord;
     264             :     }
     265             : 
     266             :     /* -------------------------------------------------------------------- */
     267             :     /*      Copy the desired band out based on the size of the type, and    */
     268             :     /*      the interleaving mode.                                          */
     269             :     /* -------------------------------------------------------------------- */
     270           0 :     const int nBytesPerSample = GDALGetDataTypeSizeBytes(eDataType);
     271             : 
     272           0 :     if (ImageDesc->ChannelInterleaving == CEOS_IL_PIXEL)
     273             :     {
     274           0 :         GDALCopyWords(pabyRecord + (nBand - 1) * nBytesPerSample, eDataType,
     275             :                       ImageDesc->BytesPerPixel, pImage, eDataType,
     276             :                       nBytesPerSample, nBlockXSize);
     277             :     }
     278           0 :     else if (ImageDesc->ChannelInterleaving == CEOS_IL_LINE)
     279             :     {
     280           0 :         GDALCopyWords(pabyRecord + (nBand - 1) * nBytesPerSample * nBlockXSize,
     281             :                       eDataType, nBytesPerSample, pImage, eDataType,
     282             :                       nBytesPerSample, nBlockXSize);
     283             :     }
     284           0 :     else if (ImageDesc->ChannelInterleaving == CEOS_IL_BAND)
     285             :     {
     286           0 :         memcpy(pImage, pabyRecord,
     287           0 :                static_cast<size_t>(nBytesPerSample) * nBlockXSize);
     288             :     }
     289             : 
     290             : #ifdef CPL_LSB
     291           0 :     GDALSwapWords(pImage, nBytesPerSample, nBlockXSize, nBytesPerSample);
     292             : #endif
     293             : 
     294           0 :     CPLFree(pabyRecord);
     295             : 
     296           0 :     return CE_None;
     297             : }
     298             : 
     299             : /************************************************************************/
     300             : /* ==================================================================== */
     301             : /*                              CCPRasterBand                           */
     302             : /* ==================================================================== */
     303             : /************************************************************************/
     304             : 
     305             : /************************************************************************/
     306             : /*                           CCPRasterBand()                            */
     307             : /************************************************************************/
     308             : 
     309           0 : CCPRasterBand::CCPRasterBand(SAR_CEOSDataset *poGDSIn, int nBandIn,
     310           0 :                              GDALDataType eType)
     311             : 
     312             : {
     313           0 :     poDS = poGDSIn;
     314           0 :     nBand = nBandIn;
     315             : 
     316           0 :     eDataType = eType;
     317             : 
     318           0 :     nBlockXSize = poGDSIn->nRasterXSize;
     319           0 :     nBlockYSize = 1;
     320             : 
     321           0 :     if (nBand == 1)
     322           0 :         SetMetadataItem("POLARIMETRIC_INTERP", "HH");
     323           0 :     else if (nBand == 2)
     324           0 :         SetMetadataItem("POLARIMETRIC_INTERP", "HV");
     325           0 :     else if (nBand == 3)
     326           0 :         SetMetadataItem("POLARIMETRIC_INTERP", "VH");
     327           0 :     else if (nBand == 4)
     328           0 :         SetMetadataItem("POLARIMETRIC_INTERP", "VV");
     329           0 : }
     330             : 
     331             : /************************************************************************/
     332             : /*                             IReadBlock()                             */
     333             : /************************************************************************/
     334             : 
     335             : /* From: http://southport.jpl.nasa.gov/software/dcomp/dcomp.html
     336             : 
     337             : ysca = sqrt{ [ (Byte(2) / 254 ) + 1.5] 2Byte(1) }
     338             : 
     339             : Re(SHH) = byte(3) ysca/127
     340             : 
     341             : Im(SHH) = byte(4) ysca/127
     342             : 
     343             : Re(SHV) = byte(5) ysca/127
     344             : 
     345             : Im(SHV) = byte(6) ysca/127
     346             : 
     347             : Re(SVH) = byte(7) ysca/127
     348             : 
     349             : Im(SVH) = byte(8) ysca/127
     350             : 
     351             : Re(SVV) = byte(9) ysca/127
     352             : 
     353             : Im(SVV) = byte(10) ysca/127
     354             : 
     355             : */
     356             : 
     357           0 : CPLErr CCPRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
     358             :                                  void *pImage)
     359             : {
     360           0 :     SAR_CEOSDataset *poGDS = (SAR_CEOSDataset *)poDS;
     361             : 
     362           0 :     struct CeosSARImageDesc *ImageDesc = &(poGDS->sVolume.ImageDesc);
     363             : 
     364           0 :     int offset = ImageDesc->FileDescriptorLength +
     365           0 :                  ImageDesc->BytesPerRecord * nBlockYOff +
     366           0 :                  ImageDesc->ImageDataStart;
     367             : 
     368             :     /* -------------------------------------------------------------------- */
     369             :     /*      Load all the pixel data associated with this scanline.          */
     370             :     /* -------------------------------------------------------------------- */
     371           0 :     const int nBytesToRead = ImageDesc->BytesPerPixel * nBlockXSize;
     372             : 
     373           0 :     GByte *pabyRecord = (GByte *)CPLMalloc(nBytesToRead);
     374             : 
     375           0 :     if (VSIFSeekL(poGDS->fpImage, offset, SEEK_SET) != 0 ||
     376           0 :         (int)VSIFReadL(pabyRecord, 1, nBytesToRead, poGDS->fpImage) !=
     377             :             nBytesToRead)
     378             :     {
     379           0 :         CPLError(CE_Failure, CPLE_FileIO,
     380             :                  "Error reading %d bytes of CEOS record data at offset %d.\n"
     381             :                  "Reading file %s failed.",
     382           0 :                  nBytesToRead, offset, poGDS->GetDescription());
     383           0 :         CPLFree(pabyRecord);
     384           0 :         return CE_Failure;
     385             :     }
     386             : 
     387             :     /* -------------------------------------------------------------------- */
     388             :     /*      Initialize our power table if this is our first time through.   */
     389             :     /* -------------------------------------------------------------------- */
     390             :     static float afPowTable[256];
     391             :     static bool bPowTableInitialized = false;
     392             : 
     393           0 :     if (!bPowTableInitialized)
     394             :     {
     395           0 :         bPowTableInitialized = true;
     396             : 
     397           0 :         for (int i = 0; i < 256; i++)
     398             :         {
     399           0 :             afPowTable[i] = (float)pow(2.0, i - 128);
     400             :         }
     401             :     }
     402             : 
     403             :     /* -------------------------------------------------------------------- */
     404             :     /*      Copy the desired band out based on the size of the type, and    */
     405             :     /*      the interleaving mode.                                          */
     406             :     /* -------------------------------------------------------------------- */
     407           0 :     for (int iX = 0; iX < nBlockXSize; iX++)
     408             :     {
     409           0 :         unsigned char *pabyGroup = pabyRecord + iX * ImageDesc->BytesPerPixel;
     410           0 :         signed char *Byte =
     411             :             (signed char *)pabyGroup - 1; /* A ones based alias */
     412             :         double dfReSHH, dfImSHH, dfReSHV, dfImSHV, dfReSVH, dfImSVH, dfReSVV,
     413             :             dfImSVV;
     414             : 
     415             :         const double dfScale =
     416           0 :             sqrt((Byte[2] / 254.0 + 1.5) * afPowTable[Byte[1] + 128]);
     417             : 
     418           0 :         if (nBand == 1)
     419             :         {
     420           0 :             dfReSHH = Byte[3] * dfScale / 127.0;
     421           0 :             dfImSHH = Byte[4] * dfScale / 127.0;
     422             : 
     423           0 :             ((float *)pImage)[iX * 2] = (float)dfReSHH;
     424           0 :             ((float *)pImage)[iX * 2 + 1] = (float)dfImSHH;
     425             :         }
     426           0 :         else if (nBand == 2)
     427             :         {
     428           0 :             dfReSHV = Byte[5] * dfScale / 127.0;
     429           0 :             dfImSHV = Byte[6] * dfScale / 127.0;
     430             : 
     431           0 :             ((float *)pImage)[iX * 2] = (float)dfReSHV;
     432           0 :             ((float *)pImage)[iX * 2 + 1] = (float)dfImSHV;
     433             :         }
     434           0 :         else if (nBand == 3)
     435             :         {
     436           0 :             dfReSVH = Byte[7] * dfScale / 127.0;
     437           0 :             dfImSVH = Byte[8] * dfScale / 127.0;
     438             : 
     439           0 :             ((float *)pImage)[iX * 2] = (float)dfReSVH;
     440           0 :             ((float *)pImage)[iX * 2 + 1] = (float)dfImSVH;
     441             :         }
     442           0 :         else if (nBand == 4)
     443             :         {
     444           0 :             dfReSVV = Byte[9] * dfScale / 127.0;
     445           0 :             dfImSVV = Byte[10] * dfScale / 127.0;
     446             : 
     447           0 :             ((float *)pImage)[iX * 2] = (float)dfReSVV;
     448           0 :             ((float *)pImage)[iX * 2 + 1] = (float)dfImSVV;
     449             :         }
     450             :     }
     451             : 
     452           0 :     CPLFree(pabyRecord);
     453             : 
     454           0 :     return CE_None;
     455             : }
     456             : 
     457             : /************************************************************************/
     458             : /* ==================================================================== */
     459             : /*                            PALSARRasterBand                          */
     460             : /* ==================================================================== */
     461             : /************************************************************************/
     462             : 
     463             : /************************************************************************/
     464             : /*                           PALSARRasterBand()                         */
     465             : /************************************************************************/
     466             : 
     467           0 : PALSARRasterBand::PALSARRasterBand(SAR_CEOSDataset *poGDSIn, int nBandIn)
     468             : 
     469             : {
     470           0 :     poDS = poGDSIn;
     471           0 :     nBand = nBandIn;
     472             : 
     473           0 :     eDataType = GDT_CInt16;
     474             : 
     475           0 :     nBlockXSize = poGDSIn->nRasterXSize;
     476           0 :     nBlockYSize = 1;
     477             : 
     478           0 :     if (nBand == 1)
     479           0 :         SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_11");
     480           0 :     else if (nBand == 2)
     481           0 :         SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_22");
     482           0 :     else if (nBand == 3)
     483           0 :         SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_33");
     484           0 :     else if (nBand == 4)
     485           0 :         SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_12");
     486           0 :     else if (nBand == 5)
     487           0 :         SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_13");
     488           0 :     else if (nBand == 6)
     489           0 :         SetMetadataItem("POLARIMETRIC_INTERP", "Covariance_23");
     490           0 : }
     491             : 
     492             : /************************************************************************/
     493             : /*                             IReadBlock()                             */
     494             : /*                                                                      */
     495             : /*      Based on ERSDAC-VX-CEOS-004                                     */
     496             : /************************************************************************/
     497             : 
     498           0 : CPLErr PALSARRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff,
     499             :                                     void *pImage)
     500             : {
     501           0 :     SAR_CEOSDataset *poGDS = (SAR_CEOSDataset *)poDS;
     502             : 
     503           0 :     struct CeosSARImageDesc *ImageDesc = &(poGDS->sVolume.ImageDesc);
     504             : 
     505           0 :     int offset = ImageDesc->FileDescriptorLength +
     506           0 :                  ImageDesc->BytesPerRecord * nBlockYOff +
     507           0 :                  ImageDesc->ImageDataStart;
     508             : 
     509             :     /* -------------------------------------------------------------------- */
     510             :     /*      Load all the pixel data associated with this scanline.          */
     511             :     /* -------------------------------------------------------------------- */
     512           0 :     const int nBytesToRead = ImageDesc->BytesPerPixel * nBlockXSize;
     513             : 
     514           0 :     GByte *pabyRecord = (GByte *)CPLMalloc(nBytesToRead);
     515             : 
     516           0 :     if (VSIFSeekL(poGDS->fpImage, offset, SEEK_SET) != 0 ||
     517           0 :         (int)VSIFReadL(pabyRecord, 1, nBytesToRead, poGDS->fpImage) !=
     518             :             nBytesToRead)
     519             :     {
     520           0 :         CPLError(CE_Failure, CPLE_FileIO,
     521             :                  "Error reading %d bytes of CEOS record data at offset %d.\n"
     522             :                  "Reading file %s failed.",
     523           0 :                  nBytesToRead, offset, poGDS->GetDescription());
     524           0 :         CPLFree(pabyRecord);
     525           0 :         return CE_Failure;
     526             :     }
     527             : 
     528             :     /* -------------------------------------------------------------------- */
     529             :     /*      Copy the desired band out based on the size of the type, and    */
     530             :     /*      the interleaving mode.                                          */
     531             :     /* -------------------------------------------------------------------- */
     532           0 :     if (nBand == 1 || nBand == 2 || nBand == 3)
     533             :     {
     534             :         // we need to pre-initialize things to set the imaginary component to 0
     535           0 :         memset(pImage, 0, nBlockXSize * 4);
     536             : 
     537           0 :         GDALCopyWords(pabyRecord + 4 * (nBand - 1), GDT_Int16, 18, pImage,
     538             :                       GDT_Int16, 4, nBlockXSize);
     539             : #ifdef CPL_LSB
     540           0 :         GDALSwapWords(pImage, 2, nBlockXSize, 4);
     541             : #endif
     542             :     }
     543             :     else
     544             :     {
     545           0 :         GDALCopyWords(pabyRecord + 6 + 4 * (nBand - 4), GDT_CInt16, 18, pImage,
     546             :                       GDT_CInt16, 4, nBlockXSize);
     547             : #ifdef CPL_LSB
     548           0 :         GDALSwapWords(pImage, 2, nBlockXSize * 2, 2);
     549             : #endif
     550             :     }
     551           0 :     CPLFree(pabyRecord);
     552             : 
     553             :     /* -------------------------------------------------------------------- */
     554             :     /*      Convert the values into covariance form as per:                 */
     555             :     /* -------------------------------------------------------------------- */
     556             :     /*
     557             :     ** 1) PALSAR- adjust so that it reads bands as a covariance matrix, and
     558             :     ** set polarimetric interpretation accordingly:
     559             :     **
     560             :     ** Covariance_11=HH*conj(HH): already there
     561             :     ** Covariance_22=2*HV*conj(HV): need a factor of 2
     562             :     ** Covariance_33=VV*conj(VV): already there
     563             :     ** Covariance_12=sqrt(2)*HH*conj(HV): need the sqrt(2) factor
     564             :     ** Covariance_13=HH*conj(VV): already there
     565             :     ** Covariance_23=sqrt(2)*HV*conj(VV): need to take the conjugate, then
     566             :     **               multiply by sqrt(2)
     567             :     **
     568             :     */
     569             : 
     570           0 :     if (nBand == 2)
     571             :     {
     572           0 :         GInt16 *panLine = (GInt16 *)pImage;
     573             : 
     574           0 :         for (int i = 0; i < nBlockXSize * 2; i++)
     575             :         {
     576           0 :             panLine[i] = (GInt16)CastToGInt16((float)2.0 * panLine[i]);
     577             :         }
     578             :     }
     579           0 :     else if (nBand == 4)
     580             :     {
     581           0 :         const double sqrt_2 = pow(2.0, 0.5);
     582           0 :         GInt16 *panLine = (GInt16 *)pImage;
     583             : 
     584           0 :         for (int i = 0; i < nBlockXSize * 2; i++)
     585             :         {
     586           0 :             panLine[i] =
     587           0 :                 (GInt16)CastToGInt16((float)floor(panLine[i] * sqrt_2 + 0.5));
     588             :         }
     589             :     }
     590           0 :     else if (nBand == 6)
     591             :     {
     592           0 :         GInt16 *panLine = (GInt16 *)pImage;
     593           0 :         const double sqrt_2 = pow(2.0, 0.5);
     594             : 
     595             :         // real portion - just multiple by sqrt(2)
     596           0 :         for (int i = 0; i < nBlockXSize * 2; i += 2)
     597             :         {
     598           0 :             panLine[i] =
     599           0 :                 (GInt16)CastToGInt16((float)floor(panLine[i] * sqrt_2 + 0.5));
     600             :         }
     601             : 
     602             :         // imaginary portion - conjugate and multiply
     603           0 :         for (int i = 1; i < nBlockXSize * 2; i += 2)
     604             :         {
     605           0 :             panLine[i] =
     606           0 :                 (GInt16)CastToGInt16((float)floor(-panLine[i] * sqrt_2 + 0.5));
     607             :         }
     608             :     }
     609             : 
     610           0 :     return CE_None;
     611             : }
     612             : 
     613             : /************************************************************************/
     614             : /* ==================================================================== */
     615             : /*                              SAR_CEOSDataset                         */
     616             : /* ==================================================================== */
     617             : /************************************************************************/
     618             : 
     619             : /************************************************************************/
     620             : /*                          SAR_CEOSDataset()                           */
     621             : /************************************************************************/
     622             : 
     623           4 : SAR_CEOSDataset::SAR_CEOSDataset()
     624             :     : fpImage(nullptr), papszTempMD(nullptr), nGCPCount(0), pasGCPList(nullptr),
     625           4 :       papszExtraFiles(nullptr)
     626             : {
     627           4 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     628           4 :     m_oSRS.importFromWkt(SRS_WKT_WGS84_LAT_LONG);
     629             : 
     630           4 :     sVolume.Flavor = 0;
     631           4 :     sVolume.Sensor = 0;
     632           4 :     sVolume.ProductType = 0;
     633           4 :     sVolume.FileNamingConvention = 0;
     634             : 
     635           4 :     sVolume.VolumeDirectoryFile = 0;
     636           4 :     sVolume.SARLeaderFile = 0;
     637           4 :     sVolume.ImagryOptionsFile = 0;
     638           4 :     sVolume.SARTrailerFile = 0;
     639           4 :     sVolume.NullVolumeDirectoryFile = 0;
     640             : 
     641           4 :     sVolume.ImageDesc.ImageDescValid = 0;
     642           4 :     sVolume.ImageDesc.NumChannels = 0;
     643           4 :     sVolume.ImageDesc.ChannelInterleaving = 0;
     644           4 :     sVolume.ImageDesc.DataType = 0;
     645           4 :     sVolume.ImageDesc.BytesPerRecord = 0;
     646           4 :     sVolume.ImageDesc.Lines = 0;
     647           4 :     sVolume.ImageDesc.TopBorderPixels = 0;
     648           4 :     sVolume.ImageDesc.BottomBorderPixels = 0;
     649           4 :     sVolume.ImageDesc.PixelsPerLine = 0;
     650           4 :     sVolume.ImageDesc.LeftBorderPixels = 0;
     651           4 :     sVolume.ImageDesc.RightBorderPixels = 0;
     652           4 :     sVolume.ImageDesc.BytesPerPixel = 0;
     653           4 :     sVolume.ImageDesc.RecordsPerLine = 0;
     654           4 :     sVolume.ImageDesc.PixelsPerRecord = 0;
     655           4 :     sVolume.ImageDesc.ImageDataStart = 0;
     656           4 :     sVolume.ImageDesc.ImageSuffixData = 0;
     657           4 :     sVolume.ImageDesc.FileDescriptorLength = 0;
     658           4 :     sVolume.ImageDesc.PixelOrder = 0;
     659           4 :     sVolume.ImageDesc.LineOrder = 0;
     660           4 :     sVolume.ImageDesc.PixelDataBytesPerRecord = 0;
     661             : 
     662           4 :     sVolume.RecordList = nullptr;
     663           4 : }
     664             : 
     665             : /************************************************************************/
     666             : /*                          ~SAR_CEOSDataset()                          */
     667             : /************************************************************************/
     668             : 
     669           8 : SAR_CEOSDataset::~SAR_CEOSDataset()
     670             : 
     671             : {
     672           4 :     FlushCache(true);
     673             : 
     674           4 :     CSLDestroy(papszTempMD);
     675             : 
     676           4 :     if (fpImage != nullptr)
     677           4 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage));
     678             : 
     679           4 :     if (nGCPCount > 0)
     680             :     {
     681           4 :         GDALDeinitGCPs(nGCPCount, pasGCPList);
     682             :     }
     683           4 :     CPLFree(pasGCPList);
     684             : 
     685           4 :     if (sVolume.RecordList)
     686             :     {
     687          40 :         for (Link_t *Links = sVolume.RecordList; Links != nullptr;
     688          36 :              Links = Links->next)
     689             :         {
     690          36 :             if (Links->object)
     691             :             {
     692          36 :                 DeleteCeosRecord((CeosRecord_t *)Links->object);
     693          36 :                 Links->object = nullptr;
     694             :             }
     695             :         }
     696           4 :         DestroyList(sVolume.RecordList);
     697             :     }
     698           4 :     FreeRecipes();
     699           4 :     CSLDestroy(papszExtraFiles);
     700           8 : }
     701             : 
     702             : /************************************************************************/
     703             : /*                            GetGCPCount()                             */
     704             : /************************************************************************/
     705             : 
     706           0 : int SAR_CEOSDataset::GetGCPCount()
     707             : 
     708             : {
     709           0 :     return nGCPCount;
     710             : }
     711             : 
     712             : /************************************************************************/
     713             : /*                          GetGCPSpatialRef()                          */
     714             : /************************************************************************/
     715             : 
     716           0 : const OGRSpatialReference *SAR_CEOSDataset::GetGCPSpatialRef() const
     717             : 
     718             : {
     719           0 :     if (nGCPCount > 0)
     720           0 :         return &m_oSRS;
     721             : 
     722           0 :     return nullptr;
     723             : }
     724             : 
     725             : /************************************************************************/
     726             : /*                               GetGCP()                               */
     727             : /************************************************************************/
     728             : 
     729           0 : const GDAL_GCP *SAR_CEOSDataset::GetGCPs()
     730             : 
     731             : {
     732           0 :     return pasGCPList;
     733             : }
     734             : 
     735             : /************************************************************************/
     736             : /*                      GetMetadataDomainList()                         */
     737             : /************************************************************************/
     738             : 
     739           0 : char **SAR_CEOSDataset::GetMetadataDomainList()
     740             : {
     741           0 :     return CSLAddString(GDALDataset::GetMetadataDomainList(),
     742           0 :                         "ceos-FFF-n-n-n-n:r");
     743             : }
     744             : 
     745             : /************************************************************************/
     746             : /*                            GetMetadata()                             */
     747             : /*                                                                      */
     748             : /*      We provide our own GetMetadata() so that we can override        */
     749             : /*      behavior for some very specialized domain names intended to     */
     750             : /*      give us access to raw record data.                              */
     751             : /*                                                                      */
     752             : /*      The domain must look like:                                      */
     753             : /*        ceos-FFF-n-n-n-n:r                                            */
     754             : /*                                                                      */
     755             : /*        FFF - The file id - one of vol, lea, img, trl or nul.         */
     756             : /*        n-n-n-n - the record type code such as 18-10-18-20 for the    */
     757             : /*        dataset summary record in the leader file.                    */
     758             : /*        :r - The zero based record number to fetch (optional)         */
     759             : /*                                                                      */
     760             : /*      Note that only records that are pre-loaded will be              */
     761             : /*      accessible, and this normally means that most image records     */
     762             : /*      are not available.                                              */
     763             : /************************************************************************/
     764             : 
     765           2 : char **SAR_CEOSDataset::GetMetadata(const char *pszDomain)
     766             : 
     767             : {
     768           2 :     if (pszDomain == nullptr || !STARTS_WITH_CI(pszDomain, "ceos-"))
     769           2 :         return GDALDataset::GetMetadata(pszDomain);
     770             : 
     771             :     /* -------------------------------------------------------------------- */
     772             :     /*      Identify which file to fetch the file from.                     */
     773             :     /* -------------------------------------------------------------------- */
     774           0 :     int nFileId = -1;
     775             : 
     776           0 :     if (STARTS_WITH_CI(pszDomain, "ceos-vol"))
     777             :     {
     778           0 :         nFileId = CEOS_VOLUME_DIR_FILE;
     779             :     }
     780           0 :     else if (STARTS_WITH_CI(pszDomain, "ceos-lea"))
     781             :     {
     782           0 :         nFileId = CEOS_LEADER_FILE;
     783             :     }
     784           0 :     else if (STARTS_WITH_CI(pszDomain, "ceos-img"))
     785             :     {
     786           0 :         nFileId = CEOS_IMAGRY_OPT_FILE;
     787             :     }
     788           0 :     else if (STARTS_WITH_CI(pszDomain, "ceos-trl"))
     789             :     {
     790           0 :         nFileId = CEOS_TRAILER_FILE;
     791             :     }
     792           0 :     else if (STARTS_WITH_CI(pszDomain, "ceos-nul"))
     793             :     {
     794           0 :         nFileId = CEOS_NULL_VOL_FILE;
     795             :     }
     796             :     else
     797           0 :         return nullptr;
     798             : 
     799           0 :     pszDomain += 8;
     800             : 
     801             :     /* -------------------------------------------------------------------- */
     802             :     /*      Identify the record type.                                       */
     803             :     /* -------------------------------------------------------------------- */
     804           0 :     int a, b, c, d, nRecordIndex = -1;
     805             : 
     806           0 :     if (sscanf(pszDomain, "-%d-%d-%d-%d:%d", &a, &b, &c, &d, &nRecordIndex) !=
     807           0 :             5 &&
     808           0 :         sscanf(pszDomain, "-%d-%d-%d-%d", &a, &b, &c, &d) != 4)
     809             :     {
     810           0 :         return nullptr;
     811             :     }
     812             : 
     813           0 :     CeosTypeCode_t sTypeCode = QuadToTC(a, b, c, d);
     814             : 
     815             :     /* -------------------------------------------------------------------- */
     816             :     /*      Try to fetch the record.                                        */
     817             :     /* -------------------------------------------------------------------- */
     818           0 :     CeosRecord_t *record = FindCeosRecord(sVolume.RecordList, sTypeCode,
     819             :                                           nFileId, -1, nRecordIndex);
     820             : 
     821           0 :     if (record == nullptr)
     822           0 :         return nullptr;
     823             : 
     824             :     /* -------------------------------------------------------------------- */
     825             :     /*      Massage the data into a safe textual format.  The RawRecord     */
     826             :     /*      just has zero bytes turned into spaces while the                */
     827             :     /*      EscapedRecord has regular backslash escaping applied to zero    */
     828             :     /*      chars, double quotes, and backslashes.                          */
     829             :     /*      just turn zero bytes into spaces.                               */
     830             :     /* -------------------------------------------------------------------- */
     831             : 
     832           0 :     CSLDestroy(papszTempMD);
     833             : 
     834             :     // Escaped version
     835           0 :     char *pszSafeCopy = CPLEscapeString((char *)record->Buffer, record->Length,
     836             :                                         CPLES_BackslashQuotable);
     837           0 :     papszTempMD = CSLSetNameValue(nullptr, "EscapedRecord", pszSafeCopy);
     838           0 :     CPLFree(pszSafeCopy);
     839             : 
     840             :     // Copy with '\0' replaced by spaces.
     841             : 
     842           0 :     pszSafeCopy = (char *)CPLCalloc(1, record->Length + 1);
     843           0 :     memcpy(pszSafeCopy, record->Buffer, record->Length);
     844             : 
     845           0 :     for (int i = 0; i < record->Length; i++)
     846           0 :         if (pszSafeCopy[i] == '\0')
     847           0 :             pszSafeCopy[i] = ' ';
     848             : 
     849           0 :     papszTempMD = CSLSetNameValue(papszTempMD, "RawRecord", pszSafeCopy);
     850             : 
     851           0 :     CPLFree(pszSafeCopy);
     852             : 
     853           0 :     return papszTempMD;
     854             : }
     855             : 
     856             : /************************************************************************/
     857             : /*                          ScanForMetadata()                           */
     858             : /************************************************************************/
     859             : 
     860           4 : void SAR_CEOSDataset::ScanForMetadata()
     861             : 
     862             : {
     863             :     /* -------------------------------------------------------------------- */
     864             :     /*      Get the volume id (with the sensor name)                        */
     865             :     /* -------------------------------------------------------------------- */
     866             :     CeosRecord_t *record =
     867           4 :         FindCeosRecord(sVolume.RecordList, VOLUME_DESCRIPTOR_RECORD_TC,
     868             :                        CEOS_VOLUME_DIR_FILE, -1, -1);
     869             : 
     870             :     char szVolId[128];
     871           4 :     szVolId[0] = '\0';
     872             :     char szField[128];
     873           4 :     szField[0] = '\0';
     874           4 :     if (record != nullptr)
     875             :     {
     876           0 :         szVolId[16] = '\0';
     877             : 
     878           0 :         GetCeosField(record, 61, "A16", szVolId);
     879             : 
     880           0 :         SetMetadataItem("CEOS_LOGICAL_VOLUME_ID", szVolId);
     881             : 
     882             :         /* --------------------------------------------------------------------
     883             :          */
     884             :         /*      Processing facility */
     885             :         /* --------------------------------------------------------------------
     886             :          */
     887           0 :         szField[0] = '\0';
     888           0 :         szField[12] = '\0';
     889             : 
     890           0 :         GetCeosField(record, 149, "A12", szField);
     891             : 
     892           0 :         if (!STARTS_WITH_CI(szField, "            "))
     893           0 :             SetMetadataItem("CEOS_PROCESSING_FACILITY", szField);
     894             : 
     895             :         /* --------------------------------------------------------------------
     896             :          */
     897             :         /*      Agency */
     898             :         /* --------------------------------------------------------------------
     899             :          */
     900           0 :         szField[8] = '\0';
     901             : 
     902           0 :         GetCeosField(record, 141, "A8", szField);
     903             : 
     904           0 :         if (!STARTS_WITH_CI(szField, "            "))
     905           0 :             SetMetadataItem("CEOS_PROCESSING_AGENCY", szField);
     906             : 
     907             :         /* --------------------------------------------------------------------
     908             :          */
     909             :         /*      Country */
     910             :         /* --------------------------------------------------------------------
     911             :          */
     912           0 :         szField[12] = '\0';
     913             : 
     914           0 :         GetCeosField(record, 129, "A12", szField);
     915             : 
     916           0 :         if (!STARTS_WITH_CI(szField, "            "))
     917           0 :             SetMetadataItem("CEOS_PROCESSING_COUNTRY", szField);
     918             : 
     919             :         /* --------------------------------------------------------------------
     920             :          */
     921             :         /*      software id. */
     922             :         /* --------------------------------------------------------------------
     923             :          */
     924           0 :         szField[12] = '\0';
     925             : 
     926           0 :         GetCeosField(record, 33, "A12", szField);
     927             : 
     928           0 :         if (!STARTS_WITH_CI(szField, "            "))
     929           0 :             SetMetadataItem("CEOS_SOFTWARE_ID", szField);
     930             : 
     931             :         /* --------------------------------------------------------------------
     932             :          */
     933             :         /*      product identifier. */
     934             :         /* --------------------------------------------------------------------
     935             :          */
     936           0 :         szField[8] = '\0';
     937             : 
     938           0 :         GetCeosField(record, 261, "A8", szField);
     939             : 
     940           0 :         if (!STARTS_WITH_CI(szField, "        "))
     941           0 :             SetMetadataItem("CEOS_PRODUCT_ID", szField);
     942             : 
     943             :         /* --------------------------------------------------------------------
     944             :          */
     945             :         /*      volume identifier. */
     946             :         /* --------------------------------------------------------------------
     947             :          */
     948           0 :         szField[16] = '\0';
     949             : 
     950           0 :         GetCeosField(record, 77, "A16", szField);
     951             : 
     952           0 :         if (!STARTS_WITH_CI(szField, "                "))
     953           0 :             SetMetadataItem("CEOS_VOLSET_ID", szField);
     954             :     }
     955             : 
     956             :     /* ==================================================================== */
     957             :     /*      Dataset summary record.                                         */
     958             :     /* ==================================================================== */
     959           4 :     record = FindCeosRecord(sVolume.RecordList, LEADER_DATASET_SUMMARY_TC,
     960             :                             CEOS_LEADER_FILE, -1, -1);
     961             : 
     962           4 :     if (record == nullptr)
     963             :         record =
     964           4 :             FindCeosRecord(sVolume.RecordList, LEADER_DATASET_SUMMARY_ASF_TC,
     965             :                            CEOS_LEADER_FILE, -1, -1);
     966             : 
     967           4 :     if (record == nullptr)
     968           2 :         record = FindCeosRecord(sVolume.RecordList, LEADER_DATASET_SUMMARY_TC,
     969             :                                 CEOS_TRAILER_FILE, -1, -1);
     970             : 
     971           4 :     if (record == nullptr)
     972             :         record =
     973           2 :             FindCeosRecord(sVolume.RecordList, LEADER_DATASET_SUMMARY_ERS2_TC,
     974             :                            CEOS_LEADER_FILE, -1, -1);
     975             : 
     976           4 :     if (record != nullptr)
     977             :     {
     978             :         /* --------------------------------------------------------------------
     979             :          */
     980             :         /*      Get the acquisition date. */
     981             :         /* --------------------------------------------------------------------
     982             :          */
     983           2 :         szField[0] = '\0';
     984           2 :         szField[32] = '\0';
     985             : 
     986           2 :         GetCeosField(record, 69, "A32", szField);
     987             : 
     988           2 :         SetMetadataItem("CEOS_ACQUISITION_TIME", szField);
     989             : 
     990             :         /* --------------------------------------------------------------------
     991             :          */
     992             :         /*      Ascending/Descending */
     993             :         /* --------------------------------------------------------------------
     994             :          */
     995           2 :         GetCeosField(record, 101, "A16", szField);
     996           2 :         szField[16] = '\0';
     997             : 
     998           2 :         if (strstr(szVolId, "RSAT") != nullptr &&
     999           0 :             !STARTS_WITH_CI(szField, "                "))
    1000           0 :             SetMetadataItem("CEOS_ASC_DES", szField);
    1001             : 
    1002             :         /* --------------------------------------------------------------------
    1003             :          */
    1004             :         /*      True heading - at least for ERS2. */
    1005             :         /* --------------------------------------------------------------------
    1006             :          */
    1007           2 :         GetCeosField(record, 149, "A16", szField);
    1008           2 :         szField[16] = '\0';
    1009             : 
    1010           2 :         if (!STARTS_WITH_CI(szField, "                "))
    1011           2 :             SetMetadataItem("CEOS_TRUE_HEADING", szField);
    1012             : 
    1013             :         /* --------------------------------------------------------------------
    1014             :          */
    1015             :         /*      Ellipsoid */
    1016             :         /* --------------------------------------------------------------------
    1017             :          */
    1018           2 :         GetCeosField(record, 165, "A16", szField);
    1019           2 :         szField[16] = '\0';
    1020             : 
    1021           2 :         if (!STARTS_WITH_CI(szField, "                "))
    1022           2 :             SetMetadataItem("CEOS_ELLIPSOID", szField);
    1023             : 
    1024             :         /* --------------------------------------------------------------------
    1025             :          */
    1026             :         /*      Semimajor, semiminor axis */
    1027             :         /* --------------------------------------------------------------------
    1028             :          */
    1029           2 :         GetCeosField(record, 181, "A16", szField);
    1030           2 :         szField[16] = '\0';
    1031             : 
    1032           2 :         if (!STARTS_WITH_CI(szField, "                "))
    1033           2 :             SetMetadataItem("CEOS_SEMI_MAJOR", szField);
    1034             : 
    1035           2 :         GetCeosField(record, 197, "A16", szField);
    1036           2 :         szField[16] = '\0';
    1037             : 
    1038           2 :         if (!STARTS_WITH_CI(szField, "                "))
    1039           2 :             SetMetadataItem("CEOS_SEMI_MINOR", szField);
    1040             : 
    1041             :         /* --------------------------------------------------------------------
    1042             :          */
    1043             :         /*      SCENE LENGTH KM */
    1044             :         /* --------------------------------------------------------------------
    1045             :          */
    1046           2 :         GetCeosField(record, 341, "A16", szField);
    1047           2 :         szField[16] = '\0';
    1048             : 
    1049           2 :         if (!STARTS_WITH_CI(szField, "                "))
    1050           2 :             SetMetadataItem("CEOS_SCENE_LENGTH_KM", szField);
    1051             : 
    1052             :         /* --------------------------------------------------------------------
    1053             :          */
    1054             :         /*      SCENE WIDTH KM */
    1055             :         /* --------------------------------------------------------------------
    1056             :          */
    1057           2 :         GetCeosField(record, 357, "A16", szField);
    1058           2 :         szField[16] = '\0';
    1059             : 
    1060           2 :         if (!STARTS_WITH_CI(szField, "                "))
    1061           2 :             SetMetadataItem("CEOS_SCENE_WIDTH_KM", szField);
    1062             : 
    1063             :         /* --------------------------------------------------------------------
    1064             :          */
    1065             :         /*      MISSION ID */
    1066             :         /* --------------------------------------------------------------------
    1067             :          */
    1068           2 :         GetCeosField(record, 397, "A16", szField);
    1069           2 :         szField[16] = '\0';
    1070             : 
    1071           2 :         if (!STARTS_WITH_CI(szField, "                "))
    1072           2 :             SetMetadataItem("CEOS_MISSION_ID", szField);
    1073             : 
    1074             :         /* --------------------------------------------------------------------
    1075             :          */
    1076             :         /*      SENSOR ID */
    1077             :         /* --------------------------------------------------------------------
    1078             :          */
    1079           2 :         GetCeosField(record, 413, "A32", szField);
    1080           2 :         szField[32] = '\0';
    1081             : 
    1082           2 :         if (!STARTS_WITH_CI(szField, "                                "))
    1083           2 :             SetMetadataItem("CEOS_SENSOR_ID", szField);
    1084             : 
    1085             :         /* --------------------------------------------------------------------
    1086             :          */
    1087             :         /*      ORBIT NUMBER */
    1088             :         /* --------------------------------------------------------------------
    1089             :          */
    1090           2 :         GetCeosField(record, 445, "A8", szField);
    1091           2 :         szField[8] = '\0';
    1092             : 
    1093           2 :         if (!STARTS_WITH_CI(szField, "        "))
    1094           2 :             SetMetadataItem("CEOS_ORBIT_NUMBER", szField);
    1095             : 
    1096             :         /* --------------------------------------------------------------------
    1097             :          */
    1098             :         /*      Platform latitude */
    1099             :         /* --------------------------------------------------------------------
    1100             :          */
    1101           2 :         GetCeosField(record, 453, "A8", szField);
    1102           2 :         szField[8] = '\0';
    1103             : 
    1104           2 :         if (!STARTS_WITH_CI(szField, "        "))
    1105           2 :             SetMetadataItem("CEOS_PLATFORM_LATITUDE", szField);
    1106             : 
    1107             :         /* --------------------------------------------------------------------
    1108             :          */
    1109             :         /*      Platform longitude */
    1110             :         /* --------------------------------------------------------------------
    1111             :          */
    1112           2 :         GetCeosField(record, 461, "A8", szField);
    1113           2 :         szField[8] = '\0';
    1114             : 
    1115           2 :         if (!STARTS_WITH_CI(szField, "        "))
    1116           2 :             SetMetadataItem("CEOS_PLATFORM_LONGITUDE", szField);
    1117             : 
    1118             :         /* --------------------------------------------------------------------
    1119             :          */
    1120             :         /*      Platform heading - at least for ERS2. */
    1121             :         /* --------------------------------------------------------------------
    1122             :          */
    1123           2 :         GetCeosField(record, 469, "A8", szField);
    1124           2 :         szField[8] = '\0';
    1125             : 
    1126           2 :         if (!STARTS_WITH_CI(szField, "        "))
    1127           2 :             SetMetadataItem("CEOS_PLATFORM_HEADING", szField);
    1128             : 
    1129             :         /* --------------------------------------------------------------------
    1130             :          */
    1131             :         /*      Look Angle. */
    1132             :         /* --------------------------------------------------------------------
    1133             :          */
    1134           2 :         GetCeosField(record, 477, "A8", szField);
    1135           2 :         szField[8] = '\0';
    1136             : 
    1137           2 :         if (!STARTS_WITH_CI(szField, "        "))
    1138           2 :             SetMetadataItem("CEOS_SENSOR_CLOCK_ANGLE", szField);
    1139             : 
    1140             :         /* --------------------------------------------------------------------
    1141             :          */
    1142             :         /*      Incidence angle */
    1143             :         /* --------------------------------------------------------------------
    1144             :          */
    1145           2 :         GetCeosField(record, 485, "A8", szField);
    1146           2 :         szField[8] = '\0';
    1147             : 
    1148           2 :         if (!STARTS_WITH_CI(szField, "        "))
    1149           2 :             SetMetadataItem("CEOS_INC_ANGLE", szField);
    1150             : 
    1151             :         /* --------------------------------------------------------------------
    1152             :          */
    1153             :         /*      Facility */
    1154             :         /* --------------------------------------------------------------------
    1155             :          */
    1156           2 :         GetCeosField(record, 1047, "A16", szField);
    1157           2 :         szField[16] = '\0';
    1158             : 
    1159           2 :         if (!STARTS_WITH_CI(szField, "                "))
    1160           2 :             SetMetadataItem("CEOS_FACILITY", szField);
    1161             :         /* --------------------------------------------------------------------
    1162             :          */
    1163             :         /*      Pixel time direction indicator */
    1164             :         /* --------------------------------------------------------------------
    1165             :          */
    1166           2 :         GetCeosField(record, 1527, "A8", szField);
    1167           2 :         szField[8] = '\0';
    1168             : 
    1169           2 :         if (!STARTS_WITH_CI(szField, "        "))
    1170           2 :             SetMetadataItem("CEOS_PIXEL_TIME_DIR", szField);
    1171             : 
    1172             :         /* --------------------------------------------------------------------
    1173             :          */
    1174             :         /*      Line spacing */
    1175             :         /* --------------------------------------------------------------------
    1176             :          */
    1177           2 :         GetCeosField(record, 1687, "A16", szField);
    1178           2 :         szField[16] = '\0';
    1179             : 
    1180           2 :         if (!STARTS_WITH_CI(szField, "                "))
    1181           2 :             SetMetadataItem("CEOS_LINE_SPACING_METERS", szField);
    1182             :         /* --------------------------------------------------------------------
    1183             :          */
    1184             :         /*      Pixel spacing */
    1185             :         /* --------------------------------------------------------------------
    1186             :          */
    1187           2 :         GetCeosField(record, 1703, "A16", szField);
    1188           2 :         szField[16] = '\0';
    1189             : 
    1190           2 :         if (!STARTS_WITH_CI(szField, "                "))
    1191           2 :             SetMetadataItem("CEOS_PIXEL_SPACING_METERS", szField);
    1192             :     }
    1193             : 
    1194             :     /* -------------------------------------------------------------------- */
    1195             :     /*      Get the beam mode, for radarsat.                                */
    1196             :     /* -------------------------------------------------------------------- */
    1197             :     record =
    1198           4 :         FindCeosRecord(sVolume.RecordList, LEADER_RADIOMETRIC_COMPENSATION_TC,
    1199             :                        CEOS_LEADER_FILE, -1, -1);
    1200             : 
    1201           4 :     if (strstr(szVolId, "RSAT") != nullptr && record != nullptr)
    1202             :     {
    1203           0 :         szField[16] = '\0';
    1204             : 
    1205           0 :         GetCeosField(record, 4189, "A16", szField);
    1206             : 
    1207           0 :         SetMetadataItem("CEOS_BEAM_TYPE", szField);
    1208             :     }
    1209             : 
    1210             :     /* ==================================================================== */
    1211             :     /*      ERS calibration and incidence angle info                        */
    1212             :     /* ==================================================================== */
    1213           4 :     record = FindCeosRecord(sVolume.RecordList, ERS_GENERAL_FACILITY_DATA_TC,
    1214             :                             CEOS_LEADER_FILE, -1, -1);
    1215             : 
    1216           4 :     if (record == nullptr)
    1217             :         record =
    1218           4 :             FindCeosRecord(sVolume.RecordList, ERS_GENERAL_FACILITY_DATA_ALT_TC,
    1219             :                            CEOS_LEADER_FILE, -1, -1);
    1220             : 
    1221           4 :     if (record != nullptr)
    1222             :     {
    1223           0 :         GetCeosField(record, 13, "A64", szField);
    1224           0 :         szField[64] = '\0';
    1225             : 
    1226             :         /* Avoid PCS records, which don't contain necessary info */
    1227           0 :         if (strstr(szField, "GENERAL") == nullptr)
    1228           0 :             record = nullptr;
    1229             :     }
    1230             : 
    1231           4 :     if (record != nullptr)
    1232             :     {
    1233           0 :         GetCeosField(record, 583, "A16", szField);
    1234           0 :         szField[16] = '\0';
    1235             : 
    1236           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1237           0 :             SetMetadataItem("CEOS_INC_ANGLE_FIRST_RANGE", szField);
    1238             : 
    1239           0 :         GetCeosField(record, 599, "A16", szField);
    1240           0 :         szField[16] = '\0';
    1241             : 
    1242           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1243           0 :             SetMetadataItem("CEOS_INC_ANGLE_CENTRE_RANGE", szField);
    1244             : 
    1245           0 :         GetCeosField(record, 615, "A16", szField);
    1246           0 :         szField[16] = '\0';
    1247             : 
    1248           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1249           0 :             SetMetadataItem("CEOS_INC_ANGLE_LAST_RANGE", szField);
    1250             : 
    1251           0 :         GetCeosField(record, 663, "A16", szField);
    1252           0 :         szField[16] = '\0';
    1253             : 
    1254           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1255           0 :             SetMetadataItem("CEOS_CALIBRATION_CONSTANT_K", szField);
    1256             : 
    1257           0 :         GetCeosField(record, 1855, "A20", szField);
    1258           0 :         szField[20] = '\0';
    1259             : 
    1260           0 :         if (!STARTS_WITH_CI(szField, "                    "))
    1261           0 :             SetMetadataItem("CEOS_GROUND_TO_SLANT_C0", szField);
    1262             : 
    1263           0 :         GetCeosField(record, 1875, "A20", szField);
    1264           0 :         szField[20] = '\0';
    1265             : 
    1266           0 :         if (!STARTS_WITH_CI(szField, "                    "))
    1267           0 :             SetMetadataItem("CEOS_GROUND_TO_SLANT_C1", szField);
    1268             : 
    1269           0 :         GetCeosField(record, 1895, "A20", szField);
    1270           0 :         szField[20] = '\0';
    1271             : 
    1272           0 :         if (!STARTS_WITH_CI(szField, "                    "))
    1273           0 :             SetMetadataItem("CEOS_GROUND_TO_SLANT_C2", szField);
    1274             : 
    1275           0 :         GetCeosField(record, 1915, "A20", szField);
    1276           0 :         szField[20] = '\0';
    1277             : 
    1278           0 :         if (!STARTS_WITH_CI(szField, "                    "))
    1279           0 :             SetMetadataItem("CEOS_GROUND_TO_SLANT_C3", szField);
    1280             :     }
    1281             :     /* -------------------------------------------------------------------- */
    1282             :     /*      Detailed Processing Parameters (Radarsat)                       */
    1283             :     /* -------------------------------------------------------------------- */
    1284           4 :     record = FindCeosRecord(sVolume.RecordList, RSAT_PROC_PARAM_TC,
    1285             :                             CEOS_LEADER_FILE, -1, -1);
    1286             : 
    1287           4 :     if (record == nullptr)
    1288           4 :         record = FindCeosRecord(sVolume.RecordList, RSAT_PROC_PARAM_TC,
    1289             :                                 CEOS_TRAILER_FILE, -1, -1);
    1290             : 
    1291           4 :     if (record != nullptr)
    1292             :     {
    1293           0 :         GetCeosField(record, 192, "A21", szField);
    1294           0 :         szField[21] = '\0';
    1295             : 
    1296           0 :         if (!STARTS_WITH_CI(szField, "                     "))
    1297           0 :             SetMetadataItem("CEOS_PROC_START", szField);
    1298             : 
    1299           0 :         GetCeosField(record, 213, "A21", szField);
    1300           0 :         szField[21] = '\0';
    1301             : 
    1302           0 :         if (!STARTS_WITH_CI(szField, "                     "))
    1303           0 :             SetMetadataItem("CEOS_PROC_STOP", szField);
    1304             : 
    1305           0 :         GetCeosField(record, 4649, "A16", szField);
    1306           0 :         szField[16] = '\0';
    1307             : 
    1308           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1309           0 :             SetMetadataItem("CEOS_EPH_ORB_DATA_0", szField);
    1310             : 
    1311           0 :         GetCeosField(record, 4665, "A16", szField);
    1312           0 :         szField[16] = '\0';
    1313             : 
    1314           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1315           0 :             SetMetadataItem("CEOS_EPH_ORB_DATA_1", szField);
    1316             : 
    1317           0 :         GetCeosField(record, 4681, "A16", szField);
    1318           0 :         szField[16] = '\0';
    1319             : 
    1320           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1321           0 :             SetMetadataItem("CEOS_EPH_ORB_DATA_2", szField);
    1322             : 
    1323           0 :         GetCeosField(record, 4697, "A16", szField);
    1324           0 :         szField[16] = '\0';
    1325             : 
    1326           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1327           0 :             SetMetadataItem("CEOS_EPH_ORB_DATA_3", szField);
    1328             : 
    1329           0 :         GetCeosField(record, 4713, "A16", szField);
    1330           0 :         szField[16] = '\0';
    1331             : 
    1332           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1333           0 :             SetMetadataItem("CEOS_EPH_ORB_DATA_4", szField);
    1334             : 
    1335           0 :         GetCeosField(record, 4729, "A16", szField);
    1336           0 :         szField[16] = '\0';
    1337             : 
    1338           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1339           0 :             SetMetadataItem("CEOS_EPH_ORB_DATA_5", szField);
    1340             : 
    1341           0 :         GetCeosField(record, 4745, "A16", szField);
    1342           0 :         szField[16] = '\0';
    1343             : 
    1344           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1345           0 :             SetMetadataItem("CEOS_EPH_ORB_DATA_6", szField);
    1346             : 
    1347           0 :         GetCeosField(record, 4908, "A16", szField);
    1348           0 :         szField[16] = '\0';
    1349             : 
    1350           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1351           0 :             SetMetadataItem("CEOS_GROUND_TO_SLANT_C0", szField);
    1352             : 
    1353           0 :         GetCeosField(record, 4924, "A16", szField);
    1354           0 :         szField[16] = '\0';
    1355             : 
    1356           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1357           0 :             SetMetadataItem("CEOS_GROUND_TO_SLANT_C1", szField);
    1358             : 
    1359           0 :         GetCeosField(record, 4940, "A16", szField);
    1360           0 :         szField[16] = '\0';
    1361             : 
    1362           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1363           0 :             SetMetadataItem("CEOS_GROUND_TO_SLANT_C2", szField);
    1364             : 
    1365           0 :         GetCeosField(record, 4956, "A16", szField);
    1366           0 :         szField[16] = '\0';
    1367             : 
    1368           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1369           0 :             SetMetadataItem("CEOS_GROUND_TO_SLANT_C3", szField);
    1370             : 
    1371           0 :         GetCeosField(record, 4972, "A16", szField);
    1372           0 :         szField[16] = '\0';
    1373             : 
    1374           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1375           0 :             SetMetadataItem("CEOS_GROUND_TO_SLANT_C4", szField);
    1376             : 
    1377           0 :         GetCeosField(record, 4988, "A16", szField);
    1378           0 :         szField[16] = '\0';
    1379             : 
    1380           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1381           0 :             SetMetadataItem("CEOS_GROUND_TO_SLANT_C5", szField);
    1382             : 
    1383           0 :         GetCeosField(record, 7334, "A16", szField);
    1384           0 :         szField[16] = '\0';
    1385             : 
    1386           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1387           0 :             SetMetadataItem("CEOS_INC_ANGLE_FIRST_RANGE", szField);
    1388             : 
    1389           0 :         GetCeosField(record, 7350, "A16", szField);
    1390           0 :         szField[16] = '\0';
    1391             : 
    1392           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1393           0 :             SetMetadataItem("CEOS_INC_ANGLE_LAST_RANGE", szField);
    1394             :     }
    1395             :     /* -------------------------------------------------------------------- */
    1396             :     /*      Get process-to-raw data coordinate translation values.  These   */
    1397             :     /*      are likely specific to Atlantis APP products.                   */
    1398             :     /* -------------------------------------------------------------------- */
    1399           4 :     record = FindCeosRecord(sVolume.RecordList, IMAGE_HEADER_RECORD_TC,
    1400             :                             CEOS_IMAGRY_OPT_FILE, -1, -1);
    1401             : 
    1402           4 :     if (record != nullptr)
    1403             :     {
    1404           4 :         GetCeosField(record, 449, "A4", szField);
    1405           4 :         szField[4] = '\0';
    1406             : 
    1407           4 :         if (!STARTS_WITH_CI(szField, "    "))
    1408           2 :             SetMetadataItem("CEOS_DM_CORNER", szField);
    1409             : 
    1410           4 :         GetCeosField(record, 453, "A4", szField);
    1411           4 :         szField[4] = '\0';
    1412             : 
    1413           4 :         if (!STARTS_WITH_CI(szField, "    "))
    1414           2 :             SetMetadataItem("CEOS_DM_TRANSPOSE", szField);
    1415             : 
    1416           4 :         GetCeosField(record, 457, "A4", szField);
    1417           4 :         szField[4] = '\0';
    1418             : 
    1419           4 :         if (!STARTS_WITH_CI(szField, "    "))
    1420           2 :             SetMetadataItem("CEOS_DM_START_SAMPLE", szField);
    1421             : 
    1422           4 :         GetCeosField(record, 461, "A5", szField);
    1423           4 :         szField[5] = '\0';
    1424             : 
    1425           4 :         if (!STARTS_WITH_CI(szField, "     "))
    1426           2 :             SetMetadataItem("CEOS_DM_START_PULSE", szField);
    1427             : 
    1428           4 :         GetCeosField(record, 466, "A16", szField);
    1429           4 :         szField[16] = '\0';
    1430             : 
    1431           4 :         if (!STARTS_WITH_CI(szField, "                "))
    1432           2 :             SetMetadataItem("CEOS_DM_FAST_ALPHA", szField);
    1433             : 
    1434           4 :         GetCeosField(record, 482, "A16", szField);
    1435           4 :         szField[16] = '\0';
    1436             : 
    1437           4 :         if (!STARTS_WITH_CI(szField, "                "))
    1438           2 :             SetMetadataItem("CEOS_DM_FAST_BETA", szField);
    1439             : 
    1440           4 :         GetCeosField(record, 498, "A16", szField);
    1441           4 :         szField[16] = '\0';
    1442             : 
    1443           4 :         if (!STARTS_WITH_CI(szField, "                "))
    1444           2 :             SetMetadataItem("CEOS_DM_SLOW_ALPHA", szField);
    1445             : 
    1446           4 :         GetCeosField(record, 514, "A16", szField);
    1447           4 :         szField[16] = '\0';
    1448             : 
    1449           4 :         if (!STARTS_WITH_CI(szField, "                "))
    1450           2 :             SetMetadataItem("CEOS_DM_SLOW_BETA", szField);
    1451             : 
    1452           4 :         GetCeosField(record, 530, "A16", szField);
    1453           4 :         szField[16] = '\0';
    1454             : 
    1455           4 :         if (!STARTS_WITH_CI(szField, "                "))
    1456           2 :             SetMetadataItem("CEOS_DM_FAST_ALPHA_2", szField);
    1457             :     }
    1458             : 
    1459             :     /* -------------------------------------------------------------------- */
    1460             :     /*      Try to find calibration information from Radiometric Data       */
    1461             :     /*      Record.                                                         */
    1462             :     /* -------------------------------------------------------------------- */
    1463             :     record =
    1464           4 :         FindCeosRecord(sVolume.RecordList, LEADER_RADIOMETRIC_DATA_RECORD_TC,
    1465             :                        CEOS_LEADER_FILE, -1, -1);
    1466             : 
    1467           4 :     if (record == nullptr)
    1468           4 :         record = FindCeosRecord(sVolume.RecordList,
    1469             :                                 LEADER_RADIOMETRIC_DATA_RECORD_TC,
    1470             :                                 CEOS_TRAILER_FILE, -1, -1);
    1471             : 
    1472           4 :     if (record != nullptr)
    1473             :     {
    1474           0 :         GetCeosField(record, 8317, "A16", szField);
    1475           0 :         szField[16] = '\0';
    1476             : 
    1477           0 :         if (!STARTS_WITH_CI(szField, "                "))
    1478           0 :             SetMetadataItem("CEOS_CALIBRATION_OFFSET", szField);
    1479             :     }
    1480             : 
    1481             :     /* -------------------------------------------------------------------- */
    1482             :     /*      For ERS Standard Format Landsat scenes we pick up the           */
    1483             :     /*      calibration offset and gain from the Radiometric Ancillary      */
    1484             :     /*      Record.                                                         */
    1485             :     /* -------------------------------------------------------------------- */
    1486             :     record =
    1487           4 :         FindCeosRecord(sVolume.RecordList, QuadToTC(0x3f, 0x24, 0x12, 0x09),
    1488             :                        CEOS_LEADER_FILE, -1, -1);
    1489           4 :     if (record != nullptr)
    1490             :     {
    1491           0 :         GetCeosField(record, 29, "A20", szField);
    1492           0 :         szField[20] = '\0';
    1493             : 
    1494           0 :         if (!STARTS_WITH_CI(szField, "                    "))
    1495           0 :             SetMetadataItem("CEOS_OFFSET_A0", szField);
    1496             : 
    1497           0 :         GetCeosField(record, 49, "A20", szField);
    1498           0 :         szField[20] = '\0';
    1499             : 
    1500           0 :         if (!STARTS_WITH_CI(szField, "                    "))
    1501           0 :             SetMetadataItem("CEOS_GAIN_A1", szField);
    1502             :     }
    1503             : 
    1504             :     /* -------------------------------------------------------------------- */
    1505             :     /*      For ERS Standard Format Landsat scenes we pick up the           */
    1506             :     /*      gain setting from the Scene Header Record.                      */
    1507             :     /* -------------------------------------------------------------------- */
    1508             :     record =
    1509           4 :         FindCeosRecord(sVolume.RecordList, QuadToTC(0x12, 0x12, 0x12, 0x09),
    1510             :                        CEOS_LEADER_FILE, -1, -1);
    1511           4 :     if (record != nullptr)
    1512             :     {
    1513           0 :         GetCeosField(record, 1486, "A1", szField);
    1514           0 :         szField[1] = '\0';
    1515             : 
    1516           0 :         if (szField[0] == 'H' || szField[0] == 'V')
    1517           0 :             SetMetadataItem("CEOS_GAIN_SETTING", szField);
    1518             :     }
    1519           4 : }
    1520             : 
    1521             : /************************************************************************/
    1522             : /*                        ScanForMapProjection()                        */
    1523             : /*                                                                      */
    1524             : /*      Try to find a map projection record, and read corner points     */
    1525             : /*      from it.  This has only been tested with ERS products.          */
    1526             : /************************************************************************/
    1527             : 
    1528           2 : int SAR_CEOSDataset::ScanForMapProjection()
    1529             : 
    1530             : {
    1531             :     /* -------------------------------------------------------------------- */
    1532             :     /*      Find record, and try to determine if it has useful GCPs.        */
    1533             :     /* -------------------------------------------------------------------- */
    1534             : 
    1535             :     CeosRecord_t *record =
    1536           2 :         FindCeosRecord(sVolume.RecordList, LEADER_MAP_PROJ_RECORD_TC,
    1537             :                        CEOS_LEADER_FILE, -1, -1);
    1538             : 
    1539           2 :     int gcp_ordering_mode = CEOS_STD_MAPREC_GCP_ORDER;
    1540             :     /* JERS from Japan */
    1541           2 :     if (record == nullptr)
    1542             :         record =
    1543           2 :             FindCeosRecord(sVolume.RecordList, LEADER_MAP_PROJ_RECORD_JERS_TC,
    1544             :                            CEOS_LEADER_FILE, -1, -1);
    1545             : 
    1546           2 :     if (record == nullptr)
    1547             :     {
    1548             :         record =
    1549           2 :             FindCeosRecord(sVolume.RecordList, LEADER_MAP_PROJ_RECORD_ASF_TC,
    1550             :                            CEOS_LEADER_FILE, -1, -1);
    1551           2 :         gcp_ordering_mode = CEOS_ASF_MAPREC_GCP_ORDER;
    1552             :     }
    1553           2 :     if (record == nullptr)
    1554             :     {
    1555           2 :         record = FindCeosRecord(sVolume.RecordList, LEADER_FACILITY_ASF_TC,
    1556             :                                 CEOS_LEADER_FILE, -1, -1);
    1557           2 :         gcp_ordering_mode = CEOS_ASF_FACREC_GCP_ORDER;
    1558             :     }
    1559             : 
    1560           2 :     if (record == nullptr)
    1561           0 :         return FALSE;
    1562             : 
    1563             :     char szField[100];
    1564           2 :     memset(szField, 0, 17);
    1565           2 :     GetCeosField(record, 29, "A16", szField);
    1566             : 
    1567           2 :     int GCPFieldSize = 16;
    1568           2 :     int GCPOffset = 1073;
    1569             : 
    1570           2 :     if (!STARTS_WITH_CI(szField, "Slant Range") &&
    1571           2 :         !STARTS_WITH_CI(szField, "Ground Range") &&
    1572           2 :         !STARTS_WITH_CI(szField, "GEOCODED"))
    1573             :     {
    1574             :         /* detect ASF map projection record */
    1575           2 :         GetCeosField(record, 1079, "A7", szField);
    1576           2 :         if (!STARTS_WITH_CI(szField, "Slant") &&
    1577           2 :             !STARTS_WITH_CI(szField, "Ground"))
    1578             :         {
    1579           0 :             return FALSE;
    1580             :         }
    1581             :         else
    1582             :         {
    1583           2 :             GCPFieldSize = 17;
    1584           2 :             GCPOffset = 157;
    1585             :         }
    1586             :     }
    1587             : 
    1588             :     char FieldSize[4];
    1589           2 :     snprintf(FieldSize, sizeof(FieldSize), "A%d", GCPFieldSize);
    1590             : 
    1591           2 :     GetCeosField(record, GCPOffset, FieldSize, szField);
    1592           2 :     if (STARTS_WITH_CI(szField, "        "))
    1593           0 :         return FALSE;
    1594             : 
    1595             :     /* -------------------------------------------------------------------- */
    1596             :     /*      Read corner points.                                             */
    1597             :     /* -------------------------------------------------------------------- */
    1598           2 :     nGCPCount = 4;
    1599           2 :     pasGCPList = (GDAL_GCP *)CPLCalloc(sizeof(GDAL_GCP), nGCPCount);
    1600             : 
    1601           2 :     GDALInitGCPs(nGCPCount, pasGCPList);
    1602             : 
    1603          10 :     for (int i = 0; i < nGCPCount; i++)
    1604             :     {
    1605             :         char szId[32];
    1606             : 
    1607           8 :         snprintf(szId, sizeof(szId), "%d", i + 1);
    1608           8 :         CPLFree(pasGCPList[i].pszId);
    1609           8 :         pasGCPList[i].pszId = CPLStrdup(szId);
    1610             : 
    1611           8 :         GetCeosField(record, GCPOffset + (GCPFieldSize * 2) * i, FieldSize,
    1612             :                      szField);
    1613           8 :         pasGCPList[i].dfGCPY = CPLAtof(szField);
    1614           8 :         GetCeosField(record, GCPOffset + GCPFieldSize + (GCPFieldSize * 2) * i,
    1615             :                      FieldSize, szField);
    1616           8 :         pasGCPList[i].dfGCPX = CPLAtof(szField);
    1617           8 :         pasGCPList[i].dfGCPZ = 0.0;
    1618             :     }
    1619             : 
    1620             :     /* Map Projection Record has the order UL UR LR LL
    1621             :      ASF Facility Data Record has the order UL,LL,UR,LR
    1622             :      ASF Map Projection Record has the order LL, LR, UR, UL */
    1623             : 
    1624           2 :     pasGCPList[0].dfGCPLine = 0.5;
    1625           2 :     pasGCPList[0].dfGCPPixel = 0.5;
    1626             : 
    1627           2 :     switch (gcp_ordering_mode)
    1628             :     {
    1629           2 :         case CEOS_ASF_FACREC_GCP_ORDER:
    1630           2 :             pasGCPList[1].dfGCPLine = nRasterYSize - 0.5;
    1631           2 :             pasGCPList[1].dfGCPPixel = 0.5;
    1632             : 
    1633           2 :             pasGCPList[2].dfGCPLine = 0.5;
    1634           2 :             pasGCPList[2].dfGCPPixel = nRasterXSize - 0.5;
    1635             : 
    1636           2 :             pasGCPList[3].dfGCPLine = nRasterYSize - 0.5;
    1637           2 :             pasGCPList[3].dfGCPPixel = nRasterXSize - 0.5;
    1638           2 :             break;
    1639           0 :         case CEOS_STD_MAPREC_GCP_ORDER:
    1640           0 :             pasGCPList[1].dfGCPLine = 0.5;
    1641           0 :             pasGCPList[1].dfGCPPixel = nRasterXSize - 0.5;
    1642             : 
    1643           0 :             pasGCPList[2].dfGCPLine = nRasterYSize - 0.5;
    1644           0 :             pasGCPList[2].dfGCPPixel = nRasterXSize - 0.5;
    1645             : 
    1646           0 :             pasGCPList[3].dfGCPLine = nRasterYSize - 0.5;
    1647           0 :             pasGCPList[3].dfGCPPixel = 0.5;
    1648           0 :             break;
    1649           0 :         case CEOS_ASF_MAPREC_GCP_ORDER:
    1650           0 :             pasGCPList[0].dfGCPLine = nRasterYSize - 0.5;
    1651           0 :             pasGCPList[0].dfGCPPixel = 0.5;
    1652             : 
    1653           0 :             pasGCPList[1].dfGCPLine = nRasterYSize - 0.5;
    1654           0 :             pasGCPList[1].dfGCPPixel = nRasterXSize - 0.5;
    1655             : 
    1656           0 :             pasGCPList[2].dfGCPLine = 0.5;
    1657           0 :             pasGCPList[2].dfGCPPixel = nRasterXSize - 0.5;
    1658             : 
    1659           0 :             pasGCPList[3].dfGCPLine = 0.5;
    1660           0 :             pasGCPList[3].dfGCPPixel = 0.5;
    1661           0 :             break;
    1662             :     }
    1663             : 
    1664           2 :     return TRUE;
    1665             : }
    1666             : 
    1667             : /************************************************************************/
    1668             : /*                            ScanForGCPs()                             */
    1669             : /************************************************************************/
    1670             : 
    1671           4 : void SAR_CEOSDataset::ScanForGCPs()
    1672             : 
    1673             : {
    1674             :     /* -------------------------------------------------------------------- */
    1675             :     /*      Do we have a standard 180 bytes of prefix data (192 bytes       */
    1676             :     /*      including the record marker information)?  If not, it is        */
    1677             :     /*      unlikely that the GCPs are available.                           */
    1678             :     /* -------------------------------------------------------------------- */
    1679           4 :     if (sVolume.ImageDesc.ImageDataStart < 192)
    1680             :     {
    1681           0 :         ScanForMapProjection();
    1682           0 :         return;
    1683             :     }
    1684             : 
    1685             :     /* ASF L1 products do not have valid data
    1686             :        in the lat/long first/mid/last fields */
    1687           4 :     const char *pszValue = GetMetadataItem("CEOS_FACILITY");
    1688           4 :     if ((pszValue != nullptr) && (strncmp(pszValue, "ASF", 3) == 0))
    1689             :     {
    1690           2 :         ScanForMapProjection();
    1691           2 :         return;
    1692             :     }
    1693             : 
    1694             :     /* -------------------------------------------------------------------- */
    1695             :     /*      Just sample fix scanlines through the image for GCPs, to        */
    1696             :     /*      return 15 GCPs.  That is an adequate coverage for most          */
    1697             :     /*      purposes.  A GCP is collected from the beginning, middle and    */
    1698             :     /*      end of each scanline.                                           */
    1699             :     /* -------------------------------------------------------------------- */
    1700           2 :     nGCPCount = 0;
    1701           2 :     int nGCPMax = 15;
    1702           2 :     pasGCPList = (GDAL_GCP *)CPLCalloc(sizeof(GDAL_GCP), nGCPMax);
    1703             : 
    1704           2 :     int nStep = (GetRasterYSize() - 1) / (nGCPMax / 3 - 1);
    1705           4 :     for (int iScanline = 0; iScanline < GetRasterYSize(); iScanline += nStep)
    1706             :     {
    1707           4 :         if (nGCPCount > nGCPMax - 3)
    1708           2 :             break;
    1709             : 
    1710             :         int nFileOffset;
    1711           4 :         CalcCeosSARImageFilePosition(&sVolume, 1, iScanline + 1, nullptr,
    1712             :                                      &nFileOffset);
    1713             : 
    1714             :         GInt32 anRecord[192 / 4];
    1715           8 :         if (VSIFSeekL(fpImage, nFileOffset, SEEK_SET) != 0 ||
    1716           4 :             VSIFReadL(anRecord, 1, 192, fpImage) != 192)
    1717           2 :             break;
    1718             : 
    1719             :         /* loop over first, middle and last pixel gcps */
    1720             : 
    1721           8 :         for (int iGCP = 0; iGCP < 3; iGCP++)
    1722             :         {
    1723           6 :             const int nLat = CPL_MSBWORD32(anRecord[132 / 4 + iGCP]);
    1724           6 :             const int nLong = CPL_MSBWORD32(anRecord[144 / 4 + iGCP]);
    1725             : 
    1726           6 :             if (nLat != 0 || nLong != 0)
    1727             :             {
    1728           6 :                 GDALInitGCPs(1, pasGCPList + nGCPCount);
    1729             : 
    1730           6 :                 CPLFree(pasGCPList[nGCPCount].pszId);
    1731             : 
    1732             :                 char szId[32];
    1733           6 :                 snprintf(szId, sizeof(szId), "%d", nGCPCount + 1);
    1734           6 :                 pasGCPList[nGCPCount].pszId = CPLStrdup(szId);
    1735             : 
    1736           6 :                 pasGCPList[nGCPCount].dfGCPX = nLong / 1000000.0;
    1737           6 :                 pasGCPList[nGCPCount].dfGCPY = nLat / 1000000.0;
    1738           6 :                 pasGCPList[nGCPCount].dfGCPZ = 0.0;
    1739             : 
    1740           6 :                 pasGCPList[nGCPCount].dfGCPLine = iScanline + 0.5;
    1741             : 
    1742           6 :                 if (iGCP == 0)
    1743           2 :                     pasGCPList[nGCPCount].dfGCPPixel = 0.5;
    1744           4 :                 else if (iGCP == 1)
    1745           2 :                     pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize() / 2.0;
    1746             :                 else
    1747           2 :                     pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize() - 0.5;
    1748             : 
    1749           6 :                 nGCPCount++;
    1750             :             }
    1751             :         }
    1752             :     }
    1753             :     /* If general GCP's were not found, look for Map Projection (e.g. JERS) */
    1754           2 :     if (nGCPCount == 0)
    1755             :     {
    1756           0 :         CPLFree(pasGCPList);
    1757           0 :         pasGCPList = nullptr;
    1758           0 :         ScanForMapProjection();
    1759           0 :         return;
    1760             :     }
    1761             : }
    1762             : 
    1763             : /************************************************************************/
    1764             : /*                                Open()                                */
    1765             : /************************************************************************/
    1766             : 
    1767       35868 : GDALDataset *SAR_CEOSDataset::Open(GDALOpenInfo *poOpenInfo)
    1768             : 
    1769             : {
    1770             :     /* -------------------------------------------------------------------- */
    1771             :     /*      Does this appear to be a valid ceos leader record?              */
    1772             :     /* -------------------------------------------------------------------- */
    1773       35868 :     if (poOpenInfo->nHeaderBytes < CEOS_HEADER_LENGTH ||
    1774        7254 :         poOpenInfo->fpL == nullptr)
    1775       28634 :         return nullptr;
    1776             : 
    1777        7234 :     if ((poOpenInfo->pabyHeader[4] != 0x3f &&
    1778        7226 :          poOpenInfo->pabyHeader[4] != 0x32) ||
    1779          12 :         poOpenInfo->pabyHeader[5] != 0xc0 ||
    1780           7 :         poOpenInfo->pabyHeader[6] != 0x12 || poOpenInfo->pabyHeader[7] != 0x12)
    1781        7227 :         return nullptr;
    1782             : 
    1783             :     // some products (#1862) have byte swapped record length/number
    1784             :     // values and will blow stuff up -- explicitly ignore if record index
    1785             :     // value appears to be little endian.
    1786           7 :     if (poOpenInfo->pabyHeader[0] != 0)
    1787           3 :         return nullptr;
    1788             : 
    1789             :     /* -------------------------------------------------------------------- */
    1790             :     /*      Confirm the requested access is supported.                      */
    1791             :     /* -------------------------------------------------------------------- */
    1792           4 :     if (poOpenInfo->eAccess == GA_Update)
    1793             :     {
    1794           0 :         CPLError(
    1795             :             CE_Failure, CPLE_NotSupported,
    1796             :             "The SAR_CEOS driver does not support update access to existing"
    1797             :             " datasets.\n");
    1798           0 :         return nullptr;
    1799             :     }
    1800             : 
    1801             :     /* -------------------------------------------------------------------- */
    1802             :     /*      Create a corresponding GDALDataset.                             */
    1803             :     /* -------------------------------------------------------------------- */
    1804             : 
    1805           8 :     auto poDS = std::make_unique<SAR_CEOSDataset>();
    1806           4 :     std::swap(poDS->fpImage, poOpenInfo->fpL);
    1807             : 
    1808           4 :     CeosSARVolume_t *psVolume = &(poDS->sVolume);
    1809           4 :     InitCeosSARVolume(psVolume, 0);
    1810             : 
    1811             :     /* -------------------------------------------------------------------- */
    1812             :     /*      Try to read the current file as an imagery file.                */
    1813             :     /* -------------------------------------------------------------------- */
    1814             : 
    1815           4 :     psVolume->ImagryOptionsFile = TRUE;
    1816           4 :     if (ProcessData(poDS->fpImage, CEOS_IMAGRY_OPT_FILE, psVolume, 4,
    1817           4 :                     VSI_L_OFFSET_MAX) != CE_None)
    1818             :     {
    1819           0 :         return nullptr;
    1820             :     }
    1821             : 
    1822             :     /* -------------------------------------------------------------------- */
    1823             :     /*      Try the various filenames.                                      */
    1824             :     /* -------------------------------------------------------------------- */
    1825           4 :     char *pszPath = CPLStrdup(CPLGetPath(poOpenInfo->pszFilename));
    1826           4 :     char *pszBasename = CPLStrdup(CPLGetBasename(poOpenInfo->pszFilename));
    1827           4 :     char *pszExtension = CPLStrdup(CPLGetExtension(poOpenInfo->pszFilename));
    1828             : 
    1829             :     int nBand;
    1830           4 :     if (strlen(pszBasename) > 4)
    1831           4 :         nBand = atoi(pszBasename + 4);
    1832             :     else
    1833           0 :         nBand = 0;
    1834             : 
    1835          24 :     for (int iFile = 0; iFile < 5; iFile++)
    1836             :     {
    1837             :         /* skip image file ... we already did it */
    1838          20 :         if (iFile == 2)
    1839           4 :             continue;
    1840             : 
    1841          16 :         int e = 0;
    1842         222 :         while (CeosExtension[e][iFile] != nullptr)
    1843             :         {
    1844         208 :             char *pszFilename = nullptr;
    1845             : 
    1846             :             /* build filename */
    1847         208 :             if (EQUAL(CeosExtension[e][5], "base"))
    1848             :             {
    1849             :                 char szMadeBasename[32];
    1850             : 
    1851          48 :                 snprintf(szMadeBasename, sizeof(szMadeBasename),
    1852          48 :                          CeosExtension[e][iFile], nBand);
    1853          48 :                 pszFilename = CPLStrdup(
    1854             :                     CPLFormFilename(pszPath, szMadeBasename, pszExtension));
    1855             :             }
    1856         160 :             else if (EQUAL(CeosExtension[e][5], "ext"))
    1857             :             {
    1858         128 :                 pszFilename = CPLStrdup(CPLFormFilename(
    1859         128 :                     pszPath, pszBasename, CeosExtension[e][iFile]));
    1860             :             }
    1861          32 :             else if (EQUAL(CeosExtension[e][5], "whole"))
    1862             :             {
    1863          16 :                 pszFilename = CPLStrdup(
    1864          16 :                     CPLFormFilename(pszPath, CeosExtension[e][iFile], ""));
    1865             :             }
    1866             : 
    1867             :             // This is for SAR SLC as per the SAR Toolbox (from ASF).
    1868          16 :             else if (EQUAL(CeosExtension[e][5], "ext2"))
    1869             :             {
    1870             :                 char szThisExtension[32];
    1871             : 
    1872          16 :                 if (strlen(pszExtension) > 3)
    1873           0 :                     snprintf(szThisExtension, sizeof(szThisExtension), "%s%s",
    1874           0 :                              CeosExtension[e][iFile], pszExtension + 3);
    1875             :                 else
    1876          16 :                     snprintf(szThisExtension, sizeof(szThisExtension), "%s",
    1877          16 :                              CeosExtension[e][iFile]);
    1878             : 
    1879          16 :                 pszFilename = CPLStrdup(
    1880             :                     CPLFormFilename(pszPath, pszBasename, szThisExtension));
    1881             :             }
    1882             : 
    1883         208 :             CPLAssert(pszFilename != nullptr);
    1884         208 :             if (pszFilename == nullptr)
    1885           0 :                 return nullptr;
    1886             : 
    1887             :             /* try to open */
    1888         208 :             VSILFILE *process_fp = VSIFOpenL(pszFilename, "rb");
    1889             : 
    1890             :             /* try upper case */
    1891         208 :             if (process_fp == nullptr)
    1892             :             {
    1893        3312 :                 for (int i = static_cast<int>(strlen(pszFilename)) - 1;
    1894        3312 :                      i >= 0 && pszFilename[i] != '/' && pszFilename[i] != '\\';
    1895             :                      i--)
    1896             :                 {
    1897        3106 :                     if (pszFilename[i] >= 'a' && pszFilename[i] <= 'z')
    1898        1480 :                         pszFilename[i] = pszFilename[i] - 'a' + 'A';
    1899             :                 }
    1900             : 
    1901         206 :                 process_fp = VSIFOpenL(pszFilename, "rb");
    1902             :             }
    1903             : 
    1904         208 :             if (process_fp != nullptr)
    1905             :             {
    1906           2 :                 CPLDebug("CEOS", "Opened %s.\n", pszFilename);
    1907             : 
    1908           4 :                 poDS->papszExtraFiles =
    1909           2 :                     CSLAddString(poDS->papszExtraFiles, pszFilename);
    1910             : 
    1911           2 :                 CPL_IGNORE_RET_VAL(VSIFSeekL(process_fp, 0, SEEK_END));
    1912           2 :                 if (ProcessData(process_fp, iFile, psVolume, -1,
    1913           2 :                                 VSIFTellL(process_fp)) == 0)
    1914             :                 {
    1915           2 :                     switch (iFile)
    1916             :                     {
    1917           0 :                         case 0:
    1918           0 :                             psVolume->VolumeDirectoryFile = TRUE;
    1919           0 :                             break;
    1920           2 :                         case 1:
    1921           2 :                             psVolume->SARLeaderFile = TRUE;
    1922           2 :                             break;
    1923           0 :                         case 3:
    1924           0 :                             psVolume->SARTrailerFile = TRUE;
    1925           0 :                             break;
    1926           0 :                         case 4:
    1927           0 :                             psVolume->NullVolumeDirectoryFile = TRUE;
    1928           0 :                             break;
    1929             :                     }
    1930             : 
    1931           2 :                     CPL_IGNORE_RET_VAL(VSIFCloseL(process_fp));
    1932           2 :                     CPLFree(pszFilename);
    1933           2 :                     break; /* Exit the while loop, we have this data type*/
    1934             :                 }
    1935             : 
    1936           0 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(process_fp));
    1937             :             }
    1938             : 
    1939         206 :             CPLFree(pszFilename);
    1940             : 
    1941         206 :             e++;
    1942             :         }
    1943             :     }
    1944             : 
    1945           4 :     CPLFree(pszPath);
    1946           4 :     CPLFree(pszBasename);
    1947           4 :     CPLFree(pszExtension);
    1948             : 
    1949             :     /* -------------------------------------------------------------------- */
    1950             :     /*      Check that we have an image description.                        */
    1951             :     /* -------------------------------------------------------------------- */
    1952           4 :     GetCeosSARImageDesc(psVolume);
    1953           4 :     struct CeosSARImageDesc *psImageDesc = &(psVolume->ImageDesc);
    1954           4 :     if (!psImageDesc->ImageDescValid)
    1955             :     {
    1956           0 :         CPLDebug("CEOS",
    1957             :                  "Unable to extract CEOS image description\n"
    1958             :                  "from %s.",
    1959             :                  poOpenInfo->pszFilename);
    1960             : 
    1961           0 :         return nullptr;
    1962             :     }
    1963             : 
    1964             :     /* -------------------------------------------------------------------- */
    1965             :     /*      Establish image type.                                           */
    1966             :     /* -------------------------------------------------------------------- */
    1967             :     GDALDataType eType;
    1968             : 
    1969           4 :     switch (psImageDesc->DataType)
    1970             :     {
    1971           2 :         case CEOS_TYP_CHAR:
    1972             :         case CEOS_TYP_UCHAR:
    1973           2 :             eType = GDT_Byte;
    1974           2 :             break;
    1975             : 
    1976           0 :         case CEOS_TYP_SHORT:
    1977           0 :             eType = GDT_Int16;
    1978           0 :             break;
    1979             : 
    1980           0 :         case CEOS_TYP_COMPLEX_SHORT:
    1981             :         case CEOS_TYP_PALSAR_COMPLEX_SHORT:
    1982           0 :             eType = GDT_CInt16;
    1983           0 :             break;
    1984             : 
    1985           2 :         case CEOS_TYP_USHORT:
    1986           2 :             eType = GDT_UInt16;
    1987           2 :             break;
    1988             : 
    1989           0 :         case CEOS_TYP_LONG:
    1990           0 :             eType = GDT_Int32;
    1991           0 :             break;
    1992             : 
    1993           0 :         case CEOS_TYP_ULONG:
    1994           0 :             eType = GDT_UInt32;
    1995           0 :             break;
    1996             : 
    1997           0 :         case CEOS_TYP_FLOAT:
    1998           0 :             eType = GDT_Float32;
    1999           0 :             break;
    2000             : 
    2001           0 :         case CEOS_TYP_DOUBLE:
    2002           0 :             eType = GDT_Float64;
    2003           0 :             break;
    2004             : 
    2005           0 :         case CEOS_TYP_COMPLEX_FLOAT:
    2006             :         case CEOS_TYP_CCP_COMPLEX_FLOAT:
    2007           0 :             eType = GDT_CFloat32;
    2008           0 :             break;
    2009             : 
    2010           0 :         default:
    2011           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2012             :                      "Unsupported CEOS image data type %d.\n",
    2013             :                      psImageDesc->DataType);
    2014           0 :             return nullptr;
    2015             :     }
    2016             : 
    2017             :     /* -------------------------------------------------------------------- */
    2018             :     /*      Capture some information from the file that is of interest.     */
    2019             :     /* -------------------------------------------------------------------- */
    2020           8 :     poDS->nRasterXSize = psImageDesc->PixelsPerLine +
    2021           4 :                          psImageDesc->LeftBorderPixels +
    2022           4 :                          psImageDesc->RightBorderPixels;
    2023           4 :     poDS->nRasterYSize = psImageDesc->Lines;
    2024             : 
    2025             :     /* -------------------------------------------------------------------- */
    2026             :     /*      Special case for compressed cross products.                     */
    2027             :     /* -------------------------------------------------------------------- */
    2028           4 :     if (psImageDesc->DataType == CEOS_TYP_CCP_COMPLEX_FLOAT)
    2029             :     {
    2030           0 :         for (int iBand = 0; iBand < psImageDesc->NumChannels; iBand++)
    2031             :         {
    2032           0 :             poDS->SetBand(
    2033           0 :                 poDS->nBands + 1,
    2034           0 :                 new CCPRasterBand(poDS.get(), poDS->nBands + 1, eType));
    2035             :         }
    2036             : 
    2037             :         /* mark this as a Scattering Matrix product */
    2038           0 :         if (poDS->GetRasterCount() == 4)
    2039             :         {
    2040           0 :             poDS->SetMetadataItem("MATRIX_REPRESENTATION", "SCATTERING");
    2041             :         }
    2042             :     }
    2043             : 
    2044             :     /* -------------------------------------------------------------------- */
    2045             :     /*      Special case for PALSAR data.                                   */
    2046             :     /* -------------------------------------------------------------------- */
    2047           4 :     else if (psImageDesc->DataType == CEOS_TYP_PALSAR_COMPLEX_SHORT)
    2048             :     {
    2049           0 :         for (int iBand = 0; iBand < psImageDesc->NumChannels; iBand++)
    2050             :         {
    2051           0 :             poDS->SetBand(poDS->nBands + 1,
    2052           0 :                           new PALSARRasterBand(poDS.get(), poDS->nBands + 1));
    2053             :         }
    2054             : 
    2055             :         /* mark this as a Symmetrized Covariance product if appropriate */
    2056           0 :         if (poDS->GetRasterCount() == 6)
    2057             :         {
    2058           0 :             poDS->SetMetadataItem("MATRIX_REPRESENTATION",
    2059           0 :                                   "SYMMETRIZED_COVARIANCE");
    2060             :         }
    2061             :     }
    2062             : 
    2063             :     /* -------------------------------------------------------------------- */
    2064             :     /*      Roll our own ...                                                */
    2065             :     /* -------------------------------------------------------------------- */
    2066           4 :     else if (psImageDesc->RecordsPerLine > 1 ||
    2067           4 :              psImageDesc->DataType == CEOS_TYP_CHAR ||
    2068           4 :              psImageDesc->DataType == CEOS_TYP_LONG ||
    2069           4 :              psImageDesc->DataType == CEOS_TYP_ULONG ||
    2070           4 :              psImageDesc->DataType == CEOS_TYP_DOUBLE)
    2071             :     {
    2072           0 :         for (int iBand = 0; iBand < psImageDesc->NumChannels; iBand++)
    2073             :         {
    2074           0 :             poDS->SetBand(
    2075           0 :                 poDS->nBands + 1,
    2076           0 :                 new SAR_CEOSRasterBand(poDS.get(), poDS->nBands + 1, eType));
    2077           0 :         }
    2078             :     }
    2079             : 
    2080             :     /* -------------------------------------------------------------------- */
    2081             :     /*      Use raw services for well behaved files.                        */
    2082             :     /* -------------------------------------------------------------------- */
    2083             :     else
    2084             :     {
    2085             :         int StartData;
    2086           4 :         CalcCeosSARImageFilePosition(psVolume, 1, 1, nullptr, &StartData);
    2087             : 
    2088             :         /*StartData += psImageDesc->ImageDataStart; */
    2089             : 
    2090             :         int nLineSize, nLineSize2;
    2091           4 :         CalcCeosSARImageFilePosition(psVolume, 1, 1, nullptr, &nLineSize);
    2092           4 :         CalcCeosSARImageFilePosition(psVolume, 1, 2, nullptr, &nLineSize2);
    2093             : 
    2094           4 :         nLineSize = nLineSize2 - nLineSize;
    2095             : 
    2096           8 :         for (int iBand = 0; iBand < psImageDesc->NumChannels; iBand++)
    2097             :         {
    2098             :             int nStartData, nPixelOffset, nLineOffset;
    2099             : 
    2100           4 :             if (psImageDesc->ChannelInterleaving == CEOS_IL_PIXEL)
    2101             :             {
    2102           0 :                 CalcCeosSARImageFilePosition(psVolume, 1, 1, nullptr,
    2103             :                                              &nStartData);
    2104             : 
    2105           0 :                 nStartData += psImageDesc->ImageDataStart;
    2106           0 :                 nStartData += psImageDesc->BytesPerPixel * iBand;
    2107             : 
    2108           0 :                 nPixelOffset =
    2109           0 :                     psImageDesc->BytesPerPixel * psImageDesc->NumChannels;
    2110           0 :                 nLineOffset = nLineSize;
    2111             :             }
    2112           4 :             else if (psImageDesc->ChannelInterleaving == CEOS_IL_LINE)
    2113             :             {
    2114           0 :                 CalcCeosSARImageFilePosition(psVolume, iBand + 1, 1, nullptr,
    2115             :                                              &nStartData);
    2116             : 
    2117           0 :                 nStartData += psImageDesc->ImageDataStart;
    2118           0 :                 nPixelOffset = psImageDesc->BytesPerPixel;
    2119           0 :                 nLineOffset = nLineSize * psImageDesc->NumChannels;
    2120             :             }
    2121           4 :             else if (psImageDesc->ChannelInterleaving == CEOS_IL_BAND)
    2122             :             {
    2123           4 :                 CalcCeosSARImageFilePosition(psVolume, iBand + 1, 1, nullptr,
    2124             :                                              &nStartData);
    2125             : 
    2126           4 :                 nStartData += psImageDesc->ImageDataStart;
    2127           4 :                 nPixelOffset = psImageDesc->BytesPerPixel;
    2128           4 :                 nLineOffset = nLineSize;
    2129             :             }
    2130             :             else
    2131             :             {
    2132           0 :                 CPLAssert(false);
    2133           0 :                 return nullptr;
    2134             :             }
    2135             : 
    2136             :             auto poBand = RawRasterBand::Create(
    2137          12 :                 poDS.get(), poDS->nBands + 1, poDS->fpImage, nStartData,
    2138             :                 nPixelOffset, nLineOffset, eType,
    2139             :                 RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
    2140           4 :                 RawRasterBand::OwnFP::NO);
    2141           4 :             if (!poBand)
    2142           0 :                 return nullptr;
    2143           4 :             poDS->SetBand(poDS->nBands + 1, std::move(poBand));
    2144             :         }
    2145             :     }
    2146             : 
    2147             :     /* -------------------------------------------------------------------- */
    2148             :     /*      Collect metadata.                                               */
    2149             :     /* -------------------------------------------------------------------- */
    2150           4 :     poDS->ScanForMetadata();
    2151             : 
    2152             :     /* -------------------------------------------------------------------- */
    2153             :     /*      Check for GCPs.                                                 */
    2154             :     /* -------------------------------------------------------------------- */
    2155           4 :     poDS->ScanForGCPs();
    2156             : 
    2157             :     /* -------------------------------------------------------------------- */
    2158             :     /*      Initialize any PAM information.                                 */
    2159             :     /* -------------------------------------------------------------------- */
    2160           4 :     poDS->SetDescription(poOpenInfo->pszFilename);
    2161           4 :     poDS->TryLoadXML();
    2162             : 
    2163             :     /* -------------------------------------------------------------------- */
    2164             :     /*      Open overviews.                                                 */
    2165             :     /* -------------------------------------------------------------------- */
    2166           4 :     poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
    2167             : 
    2168           4 :     return poDS.release();
    2169             : }
    2170             : 
    2171             : /************************************************************************/
    2172             : /*                            ProcessData()                             */
    2173             : /************************************************************************/
    2174           6 : static int ProcessData(VSILFILE *fp, int fileid, CeosSARVolume_t *sar,
    2175             :                        int max_records, vsi_l_offset max_bytes)
    2176             : 
    2177             : {
    2178             :     unsigned char temp_buffer[CEOS_HEADER_LENGTH];
    2179           6 :     unsigned char *temp_body = nullptr;
    2180           6 :     int start = 0;
    2181           6 :     int CurrentBodyLength = 0;
    2182           6 :     int CurrentType = 0;
    2183           6 :     int CurrentSequence = 0;
    2184           6 :     int iThisRecord = 0;
    2185             : 
    2186          42 :     while (max_records != 0 && max_bytes != 0)
    2187             :     {
    2188          36 :         iThisRecord++;
    2189             : 
    2190          72 :         if (VSIFSeekL(fp, start, SEEK_SET) != 0 ||
    2191          36 :             VSIFReadL(temp_buffer, 1, CEOS_HEADER_LENGTH, fp) !=
    2192             :                 CEOS_HEADER_LENGTH)
    2193             :         {
    2194           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2195             :                      "Corrupt CEOS File - cannot read record %d.", iThisRecord);
    2196           0 :             CPLFree(temp_body);
    2197           0 :             return CE_Failure;
    2198             :         }
    2199          36 :         CeosRecord_t *record = (CeosRecord_t *)CPLMalloc(sizeof(CeosRecord_t));
    2200          36 :         record->Length = DetermineCeosRecordBodyLength(temp_buffer);
    2201             : 
    2202          36 :         CeosToNative(&(record->Sequence), temp_buffer, 4, 4);
    2203             : 
    2204          36 :         if (iThisRecord != record->Sequence)
    2205             :         {
    2206           0 :             if (fileid == CEOS_IMAGRY_OPT_FILE && iThisRecord == 2)
    2207             :             {
    2208           0 :                 CPLDebug("SAR_CEOS",
    2209             :                          "Ignoring CEOS file with wrong second record sequence "
    2210             :                          "number - likely it has padded records.");
    2211           0 :                 CPLFree(record);
    2212           0 :                 CPLFree(temp_body);
    2213           0 :                 return CE_Warning;
    2214             :             }
    2215             :             else
    2216             :             {
    2217           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2218             :                          "Corrupt CEOS File - got record seq# %d instead of "
    2219             :                          "the expected %d.",
    2220             :                          record->Sequence, iThisRecord);
    2221           0 :                 CPLFree(record);
    2222           0 :                 CPLFree(temp_body);
    2223           0 :                 return CE_Failure;
    2224             :             }
    2225             :         }
    2226             : 
    2227          36 :         if (record->Length <= CEOS_HEADER_LENGTH)
    2228             :         {
    2229           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2230             :                      "Corrupt CEOS File - cannot read record %d.", iThisRecord);
    2231           0 :             CPLFree(record);
    2232           0 :             CPLFree(temp_body);
    2233           0 :             return CE_Failure;
    2234             :         }
    2235             : 
    2236          36 :         if (record->Length > CurrentBodyLength)
    2237             :         {
    2238             :             unsigned char *temp_body_new =
    2239          14 :                 (unsigned char *)VSI_REALLOC_VERBOSE(temp_body, record->Length);
    2240          14 :             if (temp_body_new == nullptr)
    2241             :             {
    2242           0 :                 CPLFree(record);
    2243           0 :                 CPLFree(temp_body);
    2244           0 :                 return CE_Failure;
    2245             :             }
    2246          14 :             temp_body = temp_body_new;
    2247          14 :             CurrentBodyLength = record->Length;
    2248             :         }
    2249             : 
    2250          36 :         int nToRead = record->Length - CEOS_HEADER_LENGTH;
    2251          36 :         if ((int)VSIFReadL(temp_body, 1, nToRead, fp) != nToRead)
    2252             :         {
    2253           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2254             :                      "Corrupt CEOS File - cannot read record %d.", iThisRecord);
    2255           0 :             CPLFree(record);
    2256           0 :             CPLFree(temp_body);
    2257           0 :             return CE_Failure;
    2258             :         }
    2259             : 
    2260          36 :         InitCeosRecordWithHeader(record, temp_buffer, temp_body);
    2261          36 :         if (record->Length == 0)
    2262             :         {
    2263           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2264             :                      "Corrupt CEOS File - invalid record %d.", iThisRecord);
    2265           0 :             CPLFree(record);
    2266           0 :             CPLFree(temp_body);
    2267           0 :             return CE_Failure;
    2268             :         }
    2269             : 
    2270          36 :         if (CurrentType == record->TypeCode.Int32Code)
    2271          10 :             record->Subsequence = ++CurrentSequence;
    2272             :         else
    2273             :         {
    2274          26 :             CurrentType = record->TypeCode.Int32Code;
    2275          26 :             record->Subsequence = 0;
    2276          26 :             CurrentSequence = 0;
    2277             :         }
    2278             : 
    2279          36 :         record->FileId = fileid;
    2280             : 
    2281          36 :         Link_t *TheLink = ceos2CreateLink(record);
    2282             : 
    2283          36 :         if (sar->RecordList == nullptr)
    2284           4 :             sar->RecordList = TheLink;
    2285             :         else
    2286          32 :             sar->RecordList = InsertLink(sar->RecordList, TheLink);
    2287             : 
    2288          36 :         start += record->Length;
    2289             : 
    2290          36 :         if (max_records > 0)
    2291          16 :             max_records--;
    2292          36 :         if (max_bytes > 0)
    2293             :         {
    2294          36 :             if ((vsi_l_offset)record->Length <= max_bytes)
    2295          36 :                 max_bytes -= record->Length;
    2296             :             else
    2297             :             {
    2298           0 :                 CPLDebug("SAR_CEOS",
    2299             :                          "Partial record found.  %d > " CPL_FRMT_GUIB,
    2300             :                          record->Length, max_bytes);
    2301           0 :                 max_bytes = 0;
    2302             :             }
    2303             :         }
    2304             :     }
    2305             : 
    2306           6 :     CPLFree(temp_body);
    2307             : 
    2308           6 :     return CE_None;
    2309             : }
    2310             : 
    2311             : /************************************************************************/
    2312             : /*                       GDALRegister_SAR_CEOS()                        */
    2313             : /************************************************************************/
    2314             : 
    2315        1595 : void GDALRegister_SAR_CEOS()
    2316             : 
    2317             : {
    2318        1595 :     if (GDALGetDriverByName("SAR_CEOS") != nullptr)
    2319         302 :         return;
    2320             : 
    2321        1293 :     GDALDriver *poDriver = new GDALDriver();
    2322             : 
    2323        1293 :     poDriver->SetDescription("SAR_CEOS");
    2324        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
    2325        1293 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "CEOS SAR Image");
    2326        1293 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
    2327        1293 :                               "drivers/raster/sar_ceos.html");
    2328        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
    2329             : 
    2330        1293 :     poDriver->pfnOpen = SAR_CEOSDataset::Open;
    2331             : 
    2332        1293 :     GetGDALDriverManager()->RegisterDriver(poDriver);
    2333             : }
    2334             : 
    2335             : /************************************************************************/
    2336             : /*                            GetFileList()                             */
    2337             : /************************************************************************/
    2338             : 
    2339           2 : char **SAR_CEOSDataset::GetFileList()
    2340             : 
    2341             : {
    2342           2 :     char **papszFileList = GDALPamDataset::GetFileList();
    2343             : 
    2344           2 :     papszFileList = CSLInsertStrings(papszFileList, -1, papszExtraFiles);
    2345             : 
    2346           2 :     return papszFileList;
    2347             : }

Generated by: LCOV version 1.14