LCOV - code coverage report
Current view: top level - frmts/adrg - srpdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 605 782 77.4 %
Date: 2024-11-21 22:18:42 Functions: 21 22 95.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * Purpose:  ASRP/USRP Reader
       3             :  * Author:   Frank Warmerdam (warmerdam@pobox.com)
       4             :  *
       5             :  * Derived from ADRG driver by Even Rouault, even.rouault at spatialys.com.
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
       9             :  * Copyright (c) 2009, Frank Warmerdam
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_string.h"
      15             : #include "gdal_pam.h"
      16             : #include "gdal_frmts.h"
      17             : #include "iso8211.h"
      18             : #include "ogr_spatialref.h"
      19             : 
      20             : #include <cstdlib>
      21             : #include <algorithm>
      22             : #include <limits>
      23             : 
      24             : // Uncomment to recognize also .gen files in addition to .img files
      25             : // #define OPEN_GEN
      26             : 
      27             : class SRPDataset final : public GDALPamDataset
      28             : {
      29             :     friend class SRPRasterBand;
      30             : 
      31             :     static CPLString ResetTo01(const char *str);
      32             : 
      33             :     VSILFILE *fdIMG;
      34             :     int *TILEINDEX;
      35             :     int offsetInIMG;
      36             :     CPLString osProduct;
      37             :     OGRSpatialReference m_oSRS{};
      38             :     CPLString osGENFileName;
      39             :     CPLString osQALFileName;
      40             :     CPLString osIMGFileName;
      41             :     int NFC;
      42             :     int NFL;
      43             :     int ZNA;
      44             :     double LSO;
      45             :     double PSO;
      46             :     double LOD;
      47             :     double LAD;
      48             :     int ARV;
      49             :     int BRV;
      50             :     int PCB;
      51             :     int PVB;
      52             : 
      53             :     char **papszSubDatasets;
      54             : 
      55             :     GDALColorTable oCT;
      56             : 
      57             :     static char **GetGENListFromTHF(const char *pszFileName);
      58             :     static char **GetIMGListFromGEN(const char *pszFileName,
      59             :                                     int *pnRecordIndex = nullptr);
      60             :     static SRPDataset *OpenDataset(const char *pszGENFileName,
      61             :                                    const char *pszIMGFileName,
      62             :                                    DDFRecord *record = nullptr);
      63             :     static DDFRecord *FindRecordInGENForIMG(DDFModule &module,
      64             :                                             const char *pszGENFileName,
      65             :                                             const char *pszIMGFileName);
      66             : 
      67             :   public:
      68             :     SRPDataset();
      69             :     ~SRPDataset() override;
      70             : 
      71             :     const OGRSpatialReference *GetSpatialRef() const override;
      72             :     CPLErr GetGeoTransform(double *padfGeoTransform) override;
      73             : 
      74             :     char **GetMetadata(const char *pszDomain = "") override;
      75             : 
      76             :     char **GetFileList() override;
      77             : 
      78             :     bool GetFromRecord(const char *pszFileName, DDFRecord *record);
      79             :     void AddSubDataset(const char *pszGENFileName, const char *pszIMGFileName);
      80             :     void AddMetadatafromFromTHF(const char *pszFileName);
      81             : 
      82             :     static GDALDataset *Open(GDALOpenInfo *);
      83             : };
      84             : 
      85             : /************************************************************************/
      86             : /* ==================================================================== */
      87             : /*                            SRPRasterBand                            */
      88             : /* ==================================================================== */
      89             : /************************************************************************/
      90             : 
      91             : class SRPRasterBand final : public GDALPamRasterBand
      92             : {
      93             :     friend class SRPDataset;
      94             : 
      95             :   public:
      96             :     SRPRasterBand(SRPDataset *, int);
      97             : 
      98             :     CPLErr IReadBlock(int, int, void *) override;
      99             : 
     100             :     double GetNoDataValue(int *pbSuccess = nullptr) override;
     101             : 
     102             :     GDALColorInterp GetColorInterpretation() override;
     103             :     GDALColorTable *GetColorTable() override;
     104             : };
     105             : 
     106             : /************************************************************************/
     107             : /*                           SRPRasterBand()                            */
     108             : /************************************************************************/
     109             : 
     110          12 : SRPRasterBand::SRPRasterBand(SRPDataset *poDSIn, int nBandIn)
     111             : 
     112             : {
     113          12 :     poDS = poDSIn;
     114          12 :     nBand = nBandIn;
     115             : 
     116          12 :     eDataType = GDT_Byte;
     117             : 
     118          12 :     nBlockXSize = 128;
     119          12 :     nBlockYSize = 128;
     120          12 : }
     121             : 
     122             : /************************************************************************/
     123             : /*                            GetNoDataValue()                          */
     124             : /************************************************************************/
     125             : 
     126           0 : double SRPRasterBand::GetNoDataValue(int *pbSuccess)
     127             : {
     128           0 :     if (pbSuccess)
     129           0 :         *pbSuccess = TRUE;
     130             : 
     131           0 :     return 0;
     132             : }
     133             : 
     134             : /************************************************************************/
     135             : /*                       GetColorInterpretation()                       */
     136             : /************************************************************************/
     137             : 
     138           3 : GDALColorInterp SRPRasterBand::GetColorInterpretation()
     139             : 
     140             : {
     141           3 :     SRPDataset *l_poDS = (SRPDataset *)this->poDS;
     142             : 
     143           3 :     if (l_poDS->oCT.GetColorEntryCount() > 0)
     144           3 :         return GCI_PaletteIndex;
     145             :     else
     146           0 :         return GCI_GrayIndex;
     147             : }
     148             : 
     149             : /************************************************************************/
     150             : /*                           GetColorTable()                            */
     151             : /************************************************************************/
     152             : 
     153           3 : GDALColorTable *SRPRasterBand::GetColorTable()
     154             : 
     155             : {
     156           3 :     SRPDataset *l_poDS = (SRPDataset *)this->poDS;
     157             : 
     158           3 :     if (l_poDS->oCT.GetColorEntryCount() > 0)
     159           3 :         return &(l_poDS->oCT);
     160             :     else
     161           0 :         return nullptr;
     162             : }
     163             : 
     164             : /************************************************************************/
     165             : /*                             IReadBlock()                             */
     166             : /************************************************************************/
     167             : 
     168           5 : CPLErr SRPRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
     169             : 
     170             : {
     171           5 :     SRPDataset *l_poDS = (SRPDataset *)this->poDS;
     172             :     vsi_l_offset offset;
     173           5 :     int nBlock = nBlockYOff * l_poDS->NFC + nBlockXOff;
     174           5 :     if (nBlockXOff >= l_poDS->NFC || nBlockYOff >= l_poDS->NFL)
     175             :     {
     176           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     177             :                  "nBlockXOff=%d, NFC=%d, nBlockYOff=%d, NFL=%d", nBlockXOff,
     178             :                  l_poDS->NFC, nBlockYOff, l_poDS->NFL);
     179           0 :         return CE_Failure;
     180             :     }
     181             : 
     182             :     /* -------------------------------------------------------------------- */
     183             :     /*      Is this a null block?                                           */
     184             :     /* -------------------------------------------------------------------- */
     185           5 :     if (l_poDS->TILEINDEX && l_poDS->TILEINDEX[nBlock] <= 0)
     186             :     {
     187           0 :         memset(pImage, 0, 128 * 128);
     188           0 :         return CE_None;
     189             :     }
     190             : 
     191             :     /* -------------------------------------------------------------------- */
     192             :     /*      Compute the offset to the block.                                */
     193             :     /* -------------------------------------------------------------------- */
     194           5 :     if (l_poDS->TILEINDEX)
     195             :     {
     196           3 :         if (l_poDS->PCB == 0)  // uncompressed
     197           0 :             offset = l_poDS->offsetInIMG +
     198           0 :                      static_cast<vsi_l_offset>(l_poDS->TILEINDEX[nBlock] - 1) *
     199           0 :                          128 * 128;
     200             :         else  // compressed
     201           3 :             offset = l_poDS->offsetInIMG +
     202           3 :                      static_cast<vsi_l_offset>(l_poDS->TILEINDEX[nBlock] - 1);
     203             :     }
     204             :     else
     205           2 :         offset =
     206           2 :             l_poDS->offsetInIMG + static_cast<vsi_l_offset>(nBlock) * 128 * 128;
     207             : 
     208             :     /* -------------------------------------------------------------------- */
     209             :     /*      Seek to target location.                                        */
     210             :     /* -------------------------------------------------------------------- */
     211           5 :     if (VSIFSeekL(l_poDS->fdIMG, offset, SEEK_SET) != 0)
     212             :     {
     213           0 :         CPLError(CE_Failure, CPLE_FileIO,
     214             :                  "Cannot seek to offset " CPL_FRMT_GUIB, offset);
     215           0 :         return CE_Failure;
     216             :     }
     217             : 
     218             :     /* -------------------------------------------------------------------- */
     219             :     /*      For uncompressed case we read the 128x128 and return with no    */
     220             :     /*      further processing.                                             */
     221             :     /* -------------------------------------------------------------------- */
     222           5 :     if (l_poDS->PCB == 0)
     223             :     {
     224           2 :         if (VSIFReadL(pImage, 1, 128 * 128, l_poDS->fdIMG) != 128 * 128)
     225             :         {
     226           0 :             CPLError(CE_Failure, CPLE_FileIO,
     227             :                      "Cannot read data at offset " CPL_FRMT_GUIB, offset);
     228           0 :             return CE_Failure;
     229             :         }
     230             :     }
     231             : 
     232             :     /* -------------------------------------------------------------------- */
     233             :     /*      If this is compressed data, we read a goodly chunk of data      */
     234             :     /*      and then decode it.                                             */
     235             :     /* -------------------------------------------------------------------- */
     236             :     else
     237             :     {
     238           3 :         const int nBufSize = 128 * 128 * 2;
     239           3 :         GByte *pabyCData = (GByte *)CPLCalloc(nBufSize, 1);
     240             : 
     241             :         const int nBytesRead =
     242           3 :             static_cast<int>(VSIFReadL(pabyCData, 1, nBufSize, l_poDS->fdIMG));
     243           3 :         if (nBytesRead == 0)
     244             :         {
     245           0 :             CPLError(CE_Failure, CPLE_FileIO,
     246             :                      "Cannot read data at offset " CPL_FRMT_GUIB, offset);
     247           0 :             CPLFree(pabyCData);
     248           0 :             return CE_Failure;
     249             :         }
     250             : 
     251           3 :         CPLAssert(l_poDS->PVB == 8);
     252           3 :         CPLAssert(l_poDS->PCB == 4 || l_poDS->PCB == 8);
     253             : 
     254           3 :         bool bHalfByteUsed = false;
     255        3201 :         for (int iSrc = 0, iPixel = 0; iPixel < 128 * 128;)
     256             :         {
     257        3198 :             if (iSrc + 2 > nBytesRead)
     258             :             {
     259           0 :                 CPLFree(pabyCData);
     260           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     261             :                          "Out of data decoding image block, only %d available.",
     262             :                          iSrc);
     263           0 :                 return CE_Failure;
     264             :             }
     265             : 
     266        3198 :             int nCount = 0;
     267        3198 :             int nValue = 0;
     268             : 
     269        3198 :             if (l_poDS->PCB == 8)
     270             :             {
     271         640 :                 nCount = pabyCData[iSrc++];
     272         640 :                 nValue = pabyCData[iSrc++];
     273             :             }
     274        2558 :             else if (l_poDS->PCB == 4)
     275             :             {
     276        2558 :                 if ((iPixel % 128) == 0 && bHalfByteUsed)
     277             :                 {
     278         254 :                     iSrc++;
     279         254 :                     bHalfByteUsed = false;
     280         254 :                     continue;
     281             :                 }
     282             : 
     283        2304 :                 if (bHalfByteUsed)
     284             :                 {
     285        1024 :                     nCount = pabyCData[iSrc++] & 0xf;
     286        1024 :                     nValue = pabyCData[iSrc++];
     287        1024 :                     bHalfByteUsed = false;
     288             :                 }
     289             :                 else
     290             :                 {
     291        1280 :                     nCount = pabyCData[iSrc] >> 4;
     292        1280 :                     nValue = ((pabyCData[iSrc] & 0xf) << 4) +
     293        1280 :                              (pabyCData[iSrc + 1] >> 4);
     294        1280 :                     bHalfByteUsed = true;
     295        1280 :                     iSrc++;
     296             :                 }
     297             :             }
     298             : 
     299        2944 :             if (iPixel + nCount > 128 * 128)
     300             :             {
     301           0 :                 CPLFree(pabyCData);
     302           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     303             :                          "Too much data decoding image block, likely corrupt.");
     304           0 :                 return CE_Failure;
     305             :             }
     306             : 
     307       52096 :             while (nCount > 0)
     308             :             {
     309       49152 :                 ((GByte *)pImage)[iPixel++] = (GByte)nValue;
     310       49152 :                 nCount--;
     311             :             }
     312             :         }
     313             : 
     314           3 :         CPLFree(pabyCData);
     315             :     }
     316             : 
     317           5 :     return CE_None;
     318             : }
     319             : 
     320             : /************************************************************************/
     321             : /*                          SRPDataset()                               */
     322             : /************************************************************************/
     323             : 
     324          13 : SRPDataset::SRPDataset()
     325             :     : fdIMG(nullptr), TILEINDEX(nullptr), offsetInIMG(0), NFC(0), NFL(0),
     326             :       ZNA(0), LSO(0.0), PSO(0.0), LOD(0.0), LAD(0.0), ARV(0), BRV(0), PCB(0),
     327          13 :       PVB(0), papszSubDatasets(nullptr)
     328             : {
     329          13 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     330          13 : }
     331             : 
     332             : /************************************************************************/
     333             : /*                          ~SRPDataset()                              */
     334             : /************************************************************************/
     335             : 
     336          26 : SRPDataset::~SRPDataset()
     337             : {
     338          13 :     CSLDestroy(papszSubDatasets);
     339             : 
     340          13 :     if (fdIMG)
     341             :     {
     342          12 :         VSIFCloseL(fdIMG);
     343             :     }
     344             : 
     345          13 :     if (TILEINDEX)
     346             :     {
     347           7 :         delete[] TILEINDEX;
     348             :     }
     349          26 : }
     350             : 
     351             : /************************************************************************/
     352             : /*                          ResetTo01()                                 */
     353             : /* Replace the DD in ZZZZZZDD.XXX with 01.                              */
     354             : /************************************************************************/
     355             : 
     356           9 : CPLString SRPDataset::ResetTo01(const char *str)
     357             : {
     358           9 :     CPLString osResult = str;
     359             : 
     360           9 :     osResult[6] = '0';
     361           9 :     osResult[7] = '1';
     362             : 
     363           9 :     return osResult;
     364             : }
     365             : 
     366             : /************************************************************************/
     367             : /*                        GetSpatialRef()                               */
     368             : /************************************************************************/
     369             : 
     370           3 : const OGRSpatialReference *SRPDataset::GetSpatialRef() const
     371             : {
     372           3 :     return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
     373             : }
     374             : 
     375             : /************************************************************************/
     376             : /*                        GetGeoTransform()                             */
     377             : /************************************************************************/
     378             : 
     379           3 : CPLErr SRPDataset::GetGeoTransform(double *padfGeoTransform)
     380             : {
     381           3 :     if (EQUAL(osProduct, "ASRP"))
     382             :     {
     383           0 :         if (ARV == 0)
     384           0 :             return CE_Failure;
     385           0 :         if (ZNA == 9)
     386             :         {
     387             :             // North Polar Case
     388           0 :             padfGeoTransform[0] = 111319.4907933 * (90.0 - PSO / 3600.0) *
     389           0 :                                   sin(LSO * M_PI / 648000.0);
     390           0 :             padfGeoTransform[1] = 40075016.68558 / ARV;
     391           0 :             padfGeoTransform[2] = 0.0;
     392           0 :             padfGeoTransform[3] = -111319.4907933 * (90.0 - PSO / 3600.0) *
     393           0 :                                   cos(LSO * M_PI / 648000.0);
     394           0 :             padfGeoTransform[4] = 0.0;
     395           0 :             padfGeoTransform[5] = -40075016.68558 / ARV;
     396             :         }
     397           0 :         else if (ZNA == 18)
     398             :         {
     399             :             // South Polar Case
     400           0 :             padfGeoTransform[0] = 111319.4907933 * (90.0 + PSO / 3600.0) *
     401           0 :                                   sin(LSO * M_PI / 648000.0);
     402           0 :             padfGeoTransform[1] = 40075016.68558 / ARV;
     403           0 :             padfGeoTransform[2] = 0.0;
     404           0 :             padfGeoTransform[3] = 111319.4907933 * (90.0 + PSO / 3600.0) *
     405           0 :                                   cos(LSO * M_PI / 648000.0);
     406           0 :             padfGeoTransform[4] = 0.0;
     407           0 :             padfGeoTransform[5] = -40075016.68558 / ARV;
     408             :         }
     409             :         else
     410             :         {
     411           0 :             if (BRV == 0)
     412           0 :                 return CE_Failure;
     413           0 :             padfGeoTransform[0] = LSO / 3600.0;
     414           0 :             padfGeoTransform[1] = 360. / ARV;
     415           0 :             padfGeoTransform[2] = 0.0;
     416           0 :             padfGeoTransform[3] = PSO / 3600.0;
     417           0 :             padfGeoTransform[4] = 0.0;
     418           0 :             padfGeoTransform[5] = -360. / BRV;
     419             :         }
     420             : 
     421           0 :         return CE_None;
     422             :     }
     423           3 :     else if (EQUAL(osProduct, "USRP"))
     424             :     {
     425           3 :         padfGeoTransform[0] = LSO;
     426           3 :         padfGeoTransform[1] = LOD;
     427           3 :         padfGeoTransform[2] = 0.0;
     428           3 :         padfGeoTransform[3] = PSO;
     429           3 :         padfGeoTransform[4] = 0.0;
     430           3 :         padfGeoTransform[5] = -LAD;
     431           3 :         return CE_None;
     432             :     }
     433             : 
     434           0 :     return CE_Failure;
     435             : }
     436             : 
     437             : /************************************************************************/
     438             : /*                           GetFromRecord()                            */
     439             : /************************************************************************/
     440             : 
     441          12 : bool SRPDataset::GetFromRecord(const char *pszFileName, DDFRecord *record)
     442             : {
     443             :     int bSuccess;
     444             : 
     445             :     /* -------------------------------------------------------------------- */
     446             :     /*      Read a variety of header fields of interest from the .GEN       */
     447             :     /*      file.                                                           */
     448             :     /* -------------------------------------------------------------------- */
     449          12 :     const int nSTR = record->GetIntSubfield("GEN", 0, "STR", 0, &bSuccess);
     450          12 :     if (!bSuccess || nSTR != 4)
     451             :     {
     452           0 :         CPLDebug("SRP", "Failed to extract STR, or not 4.");
     453           0 :         return false;
     454             :     }
     455             : 
     456          12 :     const int SCA = record->GetIntSubfield("GEN", 0, "SCA", 0, &bSuccess);
     457          12 :     CPLDebug("SRP", "SCA=%d", SCA);
     458             : 
     459          12 :     ZNA = record->GetIntSubfield("GEN", 0, "ZNA", 0, &bSuccess);
     460          12 :     CPLDebug("SRP", "ZNA=%d", ZNA);
     461             : 
     462          12 :     const double PSP = record->GetFloatSubfield("GEN", 0, "PSP", 0, &bSuccess);
     463          12 :     CPLDebug("SRP", "PSP=%f", PSP);
     464             : 
     465          12 :     ARV = record->GetIntSubfield("GEN", 0, "ARV", 0, &bSuccess);
     466          12 :     CPLDebug("SRP", "ARV=%d", ARV);
     467             : 
     468          12 :     BRV = record->GetIntSubfield("GEN", 0, "BRV", 0, &bSuccess);
     469          12 :     CPLDebug("SRP", "BRV=%d", BRV);
     470             : 
     471          12 :     LSO = record->GetFloatSubfield("GEN", 0, "LSO", 0, &bSuccess);
     472          12 :     CPLDebug("SRP", "LSO=%f", LSO);
     473             : 
     474          12 :     PSO = record->GetFloatSubfield("GEN", 0, "PSO", 0, &bSuccess);
     475          12 :     CPLDebug("SRP", "PSO=%f", PSO);
     476             : 
     477          12 :     LAD = record->GetFloatSubfield("GEN", 0, "LAD", 0);
     478          12 :     LOD = record->GetFloatSubfield("GEN", 0, "LOD", 0);
     479             : 
     480          12 :     NFL = record->GetIntSubfield("SPR", 0, "NFL", 0, &bSuccess);
     481          12 :     CPLDebug("SRP", "NFL=%d", NFL);
     482             : 
     483          12 :     NFC = record->GetIntSubfield("SPR", 0, "NFC", 0, &bSuccess);
     484          12 :     CPLDebug("SRP", "NFC=%d", NFC);
     485             : 
     486          12 :     const auto knIntMax = std::numeric_limits<int>::max();
     487          12 :     if (NFL <= 0 || NFC <= 0 || NFL > knIntMax / 128 || NFC > knIntMax / 128 ||
     488          12 :         NFL > knIntMax / NFC)
     489             :     {
     490           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid NFL / NFC values");
     491           0 :         return false;
     492             :     }
     493             : 
     494          12 :     const int PNC = record->GetIntSubfield("SPR", 0, "PNC", 0, &bSuccess);
     495          12 :     CPLDebug("SRP", "PNC=%d", PNC);
     496             : 
     497          12 :     const int PNL = record->GetIntSubfield("SPR", 0, "PNL", 0, &bSuccess);
     498          12 :     CPLDebug("SRP", "PNL=%d", PNL);
     499             : 
     500          12 :     if (PNL != 128 || PNC != 128)
     501             :     {
     502           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Unsupported PNL or PNC value.");
     503           0 :         return false;
     504             :     }
     505             : 
     506          12 :     PCB = record->GetIntSubfield("SPR", 0, "PCB", 0);
     507          12 :     PVB = record->GetIntSubfield("SPR", 0, "PVB", 0);
     508          12 :     if ((PCB != 8 && PCB != 4 && PCB != 0) || PVB != 8)
     509             :     {
     510           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     511             :                  "PCB(%d) or PVB(%d) value unsupported.", PCB, PVB);
     512           0 :         return false;
     513             :     }
     514             : 
     515             :     const char *pszBAD =
     516          12 :         record->GetStringSubfield("SPR", 0, "BAD", 0, &bSuccess);
     517          12 :     if (pszBAD == nullptr)
     518           0 :         return false;
     519          24 :     const CPLString osBAD = pszBAD;
     520             :     {
     521          12 :         char *c = (char *)strchr(osBAD, ' ');
     522          12 :         if (c)
     523           0 :             *c = 0;
     524             :     }
     525          12 :     CPLDebug("SRP", "BAD=%s", osBAD.c_str());
     526             : 
     527             :     /* -------------------------------------------------------------------- */
     528             :     /*      Read the tile map if available.                                 */
     529             :     /* -------------------------------------------------------------------- */
     530          12 :     const char *pszTIF = record->GetStringSubfield("SPR", 0, "TIF", 0);
     531          12 :     const bool TIF = pszTIF != nullptr && EQUAL(pszTIF, "Y");
     532          12 :     CPLDebug("SRP", "TIF=%s", TIF ? "true" : "false");
     533             : 
     534          12 :     if (TIF)
     535             :     {
     536           7 :         DDFField *field = record->FindField("TIM");
     537           7 :         if (field == nullptr)
     538           0 :             return false;
     539             : 
     540           7 :         DDFFieldDefn *fieldDefn = field->GetFieldDefn();
     541           7 :         DDFSubfieldDefn *subfieldDefn = fieldDefn->FindSubfieldDefn("TSI");
     542           7 :         if (subfieldDefn == nullptr)
     543           0 :             return false;
     544             : 
     545           7 :         const int nIndexValueWidth = subfieldDefn->GetWidth();
     546             : 
     547           7 :         char offset[30] = {0};
     548             :         /* Should be strict comparison, but apparently a few datasets */
     549             :         /* have GetDataSize() greater than the required minimum (#3862) */
     550          14 :         if (nIndexValueWidth <= 0 ||
     551           7 :             static_cast<size_t>(nIndexValueWidth) >= sizeof(offset) ||
     552          21 :             nIndexValueWidth > (INT_MAX - 1) / (NFL * NFC) ||
     553           7 :             field->GetDataSize() < nIndexValueWidth * NFL * NFC + 1)
     554             :         {
     555           0 :             return false;
     556             :         }
     557             : 
     558             :         try
     559             :         {
     560           7 :             TILEINDEX = new int[NFL * NFC];
     561             :         }
     562           0 :         catch (const std::exception &)
     563             :         {
     564           0 :             return false;
     565             :         }
     566           7 :         const char *ptr = field->GetData();
     567           7 :         offset[nIndexValueWidth] = '\0';
     568             : 
     569          14 :         for (int i = 0; i < NFL * NFC; i++)
     570             :         {
     571           7 :             strncpy(offset, ptr, nIndexValueWidth);
     572           7 :             ptr += nIndexValueWidth;
     573           7 :             TILEINDEX[i] = atoi(offset);
     574             :             // CPLDebug("SRP", "TSI[%d]=%d", i, TILEINDEX[i]);
     575             :         }
     576             :     }
     577             : 
     578             :     /* -------------------------------------------------------------------- */
     579             :     /*      Open the .IMG file.  Try to recover gracefully if the case      */
     580             :     /*      of the filename is wrong.                                       */
     581             :     /* -------------------------------------------------------------------- */
     582          24 :     const CPLString osDirname = CPLGetDirname(pszFileName);
     583          24 :     const CPLString osImgName = CPLFormCIFilename(osDirname, osBAD, nullptr);
     584             : 
     585          12 :     fdIMG = VSIFOpenL(osImgName, "rb");
     586          12 :     if (fdIMG == nullptr)
     587             :     {
     588           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s",
     589             :                  osImgName.c_str());
     590           0 :         return false;
     591             :     }
     592             : 
     593             :     /* -------------------------------------------------------------------- */
     594             :     /*      Establish the offset to the first byte of actual image data     */
     595             :     /*      in the IMG file, skipping the ISO8211 header.                   */
     596             :     /*                                                                      */
     597             :     /*      This code is awfully fragile!                                   */
     598             :     /* -------------------------------------------------------------------- */
     599             :     char c;
     600          12 :     if (VSIFReadL(&c, 1, 1, fdIMG) != 1)
     601             :     {
     602           0 :         return false;
     603             :     }
     604        2604 :     while (!VSIFEofL(fdIMG))
     605             :     {
     606        2604 :         if (c == 30)
     607             :         {
     608          72 :             char recordName[3] = {};
     609          72 :             if (VSIFReadL(recordName, 1, 3, fdIMG) != 3)
     610             :             {
     611           0 :                 return false;
     612             :             }
     613          72 :             offsetInIMG += 3;
     614          72 :             if (STARTS_WITH(recordName, "IMG"))
     615             :             {
     616          12 :                 offsetInIMG += 4;
     617          12 :                 if (VSIFSeekL(fdIMG, 3, SEEK_CUR) != 0)
     618             :                 {
     619           0 :                     return false;
     620             :                 }
     621          12 :                 if (VSIFReadL(&c, 1, 1, fdIMG) != 1)
     622             :                 {
     623           0 :                     return false;
     624             :                 }
     625       46296 :                 while (c != 30)
     626             :                 {
     627       46284 :                     offsetInIMG++;
     628       46284 :                     if (VSIFReadL(&c, 1, 1, fdIMG) != 1)
     629             :                     {
     630           0 :                         return false;
     631             :                     }
     632             :                 }
     633          12 :                 offsetInIMG++;
     634          12 :                 break;
     635             :             }
     636             :         }
     637             : 
     638        2592 :         offsetInIMG++;
     639        2592 :         if (VSIFReadL(&c, 1, 1, fdIMG) != 1)
     640             :         {
     641           0 :             return false;
     642             :         }
     643             :     }
     644             : 
     645          12 :     if (VSIFEofL(fdIMG))
     646             :     {
     647           0 :         return false;
     648             :     }
     649             : 
     650          12 :     CPLDebug("SRP", "Img offset data = %d", offsetInIMG);
     651             : 
     652             :     /* -------------------------------------------------------------------- */
     653             :     /*      Establish the SRP Dataset.                                     */
     654             :     /* -------------------------------------------------------------------- */
     655          12 :     nRasterXSize = NFC * 128;
     656          12 :     nRasterYSize = NFL * 128;
     657             : 
     658          12 :     char szValue[32] = {};
     659          12 :     snprintf(szValue, sizeof(szValue), "%d", SCA);
     660          12 :     SetMetadataItem("SRP_SCA", szValue);
     661             : 
     662             :     // PSP Pixel Spacing, Microns at capture stage {000.0 - 100.0}
     663          12 :     snprintf(szValue, sizeof(szValue), "%3.1f", PSP);
     664          12 :     SetMetadataItem("SRP_PSP", szValue);
     665             : 
     666          12 :     nBands = 1;
     667          24 :     for (int i = 0; i < nBands; i++)
     668          12 :         SetBand(i + 1, new SRPRasterBand(this, i + 1));
     669             : 
     670             :     /* -------------------------------------------------------------------- */
     671             :     /*      Try to collect a color map from the .QAL file.                  */
     672             :     /* -------------------------------------------------------------------- */
     673          24 :     const CPLString osBasename = CPLGetBasename(pszFileName);
     674          12 :     osQALFileName = CPLFormCIFilename(osDirname, osBasename, "QAL");
     675             : 
     676          12 :     DDFModule oQALModule;
     677             : 
     678          12 :     if (oQALModule.Open(osQALFileName, TRUE))
     679             :     {
     680          48 :         while ((record = oQALModule.ReadRecord()) != nullptr)
     681             :         {
     682          36 :             if (record->FindField("COL") != nullptr)
     683             :             {
     684             :                 const int nColorCount =
     685          12 :                     std::min(256, record->FindField("COL")->GetRepeatCount());
     686             : 
     687          60 :                 for (int iColor = 0; iColor < nColorCount; iColor++)
     688             :                 {
     689          48 :                     const int nCCD = record->GetIntSubfield("COL", 0, "CCD",
     690             :                                                             iColor, &bSuccess);
     691          48 :                     if (!bSuccess || nCCD < 0 || nCCD > 255)
     692             :                         break;
     693             : 
     694          48 :                     int nNSR = record->GetIntSubfield("COL", 0, "NSR", iColor);
     695          48 :                     int nNSG = record->GetIntSubfield("COL", 0, "NSG", iColor);
     696          48 :                     int nNSB = record->GetIntSubfield("COL", 0, "NSB", iColor);
     697             : 
     698          48 :                     GDALColorEntry sEntry = {static_cast<short>(nNSR),
     699             :                                              static_cast<short>(nNSG),
     700          48 :                                              static_cast<short>(nNSB), 255};
     701             : 
     702          48 :                     oCT.SetColorEntry(nCCD, &sEntry);
     703             :                 }
     704             :             }
     705             : 
     706          36 :             if (record->FindField("QUV") != nullptr)
     707             :             {
     708             :                 // TODO: Translate to English or state why this should not be in
     709             :                 // English.
     710             :                 // Date de production du produit : QAL.QUV.DAT1
     711             :                 // Numero d'edition  du produit : QAL.QUV.EDN
     712             : 
     713             :                 const int EDN =
     714          12 :                     record->GetIntSubfield("QUV", 0, "EDN", 0, &bSuccess);
     715          12 :                 if (bSuccess)
     716             :                 {
     717          12 :                     CPLDebug("SRP", "EDN=%d", EDN);
     718          12 :                     snprintf(szValue, sizeof(szValue), "%d", EDN);
     719          12 :                     SetMetadataItem("SRP_EDN", szValue);
     720             :                 }
     721             : 
     722             :                 const char *pszCDV07 =
     723          12 :                     record->GetStringSubfield("QUV", 0, "CDV07", 0);
     724          12 :                 if (pszCDV07 != nullptr)
     725           0 :                     SetMetadataItem("SRP_CREATIONDATE", pszCDV07);
     726             :                 else
     727             :                 { /*USRP1.2*/
     728             :                     const char *pszDAT =
     729          12 :                         record->GetStringSubfield("QUV", 0, "DAT1", 0);
     730          12 :                     if (pszDAT != nullptr && strlen(pszDAT) >= 12)
     731             :                     {
     732             :                         char dat[9];
     733          12 :                         strncpy(dat, pszDAT + 4, 8);
     734          12 :                         dat[8] = '\0';
     735          12 :                         CPLDebug("SRP", "Record DAT %s", dat);
     736          12 :                         SetMetadataItem("SRP_CREATIONDATE", dat);
     737             :                     }
     738             :                 }
     739             : 
     740             :                 const char *pszCDV24 =
     741          12 :                     record->GetStringSubfield("QUV", 0, "CDV24", 0);
     742          12 :                 if (pszCDV24 != nullptr)
     743             :                 {
     744           0 :                     SetMetadataItem("SRP_REVISIONDATE", pszCDV24);
     745             :                 }
     746             :                 else
     747             :                 { /*USRP1.2*/
     748             :                     const char *pszDAT =
     749          12 :                         record->GetStringSubfield("QUV", 0, "DAT2", 0);
     750          12 :                     if (pszDAT != nullptr && strlen(pszDAT) >= 12)
     751             :                     {
     752             :                         char dat[9];
     753          12 :                         strncpy(dat, pszDAT + 4, 8);
     754          12 :                         dat[8] = '\0';
     755          12 :                         CPLDebug("SRP", "Record DAT %s", dat);
     756          12 :                         SetMetadataItem("SRP_REVISIONDATE", dat);
     757             :                     }
     758             :                 }
     759             : 
     760             :                 const char *pszQSS =
     761          12 :                     record->GetStringSubfield("QSR", 0, "QSS", 0);
     762          12 :                 if (pszQSS != nullptr)
     763          12 :                     SetMetadataItem("SRP_CLASSIFICATION", pszQSS);
     764             :             }
     765             :         }
     766             :     }
     767             :     else
     768             :     {
     769           0 :         osQALFileName = "";
     770           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     771             :                  "Unable to find .QAL file, no color table applied.");
     772             :     }
     773             : 
     774             :     /* -------------------------------------------------------------------- */
     775             :     /*      Derive the coordinate system.                                   */
     776             :     /* -------------------------------------------------------------------- */
     777          12 :     if (EQUAL(osProduct, "ASRP"))
     778             :     {
     779           0 :         m_oSRS.importFromWkt(SRS_WKT_WGS84_LAT_LONG);
     780             : 
     781           0 :         if (ZNA == 9)
     782             :         {
     783           0 :             m_oSRS.importFromWkt(
     784             :                 "PROJCS[\"ARC_System_Zone_09\",GEOGCS[\"GCS_Sphere\","
     785             :                 "DATUM[\"D_Sphere\",SPHEROID[\"Sphere\",6378137.0,0.0]],"
     786             :                 "PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433]],"
     787             :                 "PROJECTION[\"Azimuthal_Equidistant\"],"
     788             :                 "PARAMETER[\"latitude_of_center\",90],"
     789             :                 "PARAMETER[\"longitude_of_center\",0],"
     790             :                 "PARAMETER[\"false_easting\",0],"
     791             :                 "PARAMETER[\"false_northing\",0],"
     792             :                 "UNIT[\"metre\",1]]");
     793             :         }
     794             : 
     795           0 :         if (ZNA == 18)
     796             :         {
     797           0 :             m_oSRS.importFromWkt(
     798             :                 "PROJCS[\"ARC_System_Zone_18\",GEOGCS[\"GCS_Sphere\","
     799             :                 "DATUM[\"D_Sphere\",SPHEROID[\"Sphere\",6378137.0,0.0]],"
     800             :                 "PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433]],"
     801             :                 "PROJECTION[\"Azimuthal_Equidistant\"],"
     802             :                 "PARAMETER[\"latitude_of_center\",-90],"
     803             :                 "PARAMETER[\"longitude_of_center\",0],"
     804             :                 "PARAMETER[\"false_easting\",0],"
     805             :                 "PARAMETER[\"false_northing\",0],"
     806             :                 "UNIT[\"metre\",1]]");
     807             :         }
     808             :     }
     809             :     else
     810             :     {
     811          12 :         if (ZNA >= -60 && ZNA <= 60 && ZNA != 0)
     812             :         {
     813          12 :             m_oSRS.SetUTM(std::abs(ZNA), ZNA > 0);
     814          12 :             m_oSRS.SetWellKnownGeogCS("WGS84");
     815             :         }
     816           0 :         else if (ZNA == 61)
     817             :         {
     818           0 :             m_oSRS.importFromEPSG(32661);  // WGS84 UPS North
     819             :         }
     820           0 :         else if (ZNA == -61)
     821             :         {
     822           0 :             m_oSRS.importFromEPSG(32761);  // WGS84 UPS South
     823             :         }
     824             :     }
     825             : 
     826          12 :     snprintf(szValue, sizeof(szValue), "%d", ZNA);
     827          12 :     SetMetadataItem("SRP_ZNA", szValue);
     828             : 
     829          12 :     return true;
     830             : }
     831             : 
     832             : /************************************************************************/
     833             : /*                            GetFileList()                             */
     834             : /************************************************************************/
     835             : 
     836           5 : char **SRPDataset::GetFileList()
     837             : 
     838             : {
     839           5 :     char **papszFileList = GDALPamDataset::GetFileList();
     840           5 :     if (!osGENFileName.empty() && !osIMGFileName.empty())
     841             :     {
     842          10 :         CPLString osMainFilename = GetDescription();
     843             :         VSIStatBufL sStat;
     844             : 
     845           5 :         const bool bMainFileReal = VSIStatL(osMainFilename, &sStat) == 0;
     846           5 :         if (bMainFileReal)
     847             :         {
     848           8 :             CPLString osShortMainFilename = CPLGetFilename(osMainFilename);
     849           8 :             CPLString osShortGENFileName = CPLGetFilename(osGENFileName);
     850           4 :             if (!EQUAL(osShortMainFilename.c_str(), osShortGENFileName.c_str()))
     851             :                 papszFileList =
     852           4 :                     CSLAddString(papszFileList, osGENFileName.c_str());
     853             :         }
     854             :         else
     855             :         {
     856           1 :             papszFileList = CSLAddString(papszFileList, osGENFileName.c_str());
     857             :         }
     858             : 
     859           5 :         papszFileList = CSLAddString(papszFileList, osIMGFileName.c_str());
     860             : 
     861           5 :         if (!osQALFileName.empty())
     862           5 :             papszFileList = CSLAddString(papszFileList, osQALFileName);
     863             :     }
     864           5 :     return papszFileList;
     865             : }
     866             : 
     867             : /************************************************************************/
     868             : /*                           AddSubDataset()                            */
     869             : /************************************************************************/
     870             : 
     871           1 : void SRPDataset::AddSubDataset(const char *pszGENFileName,
     872             :                                const char *pszIMGFileName)
     873             : {
     874           1 :     const int nCount = CSLCount(papszSubDatasets) / 2;
     875             : 
     876           1 :     CPLString osSubDatasetName = "SRP:";
     877           1 :     osSubDatasetName += pszGENFileName;
     878           1 :     osSubDatasetName += ",";
     879           1 :     osSubDatasetName += pszIMGFileName;
     880             : 
     881             :     char szName[80];
     882           1 :     snprintf(szName, sizeof(szName), "SUBDATASET_%d_NAME", nCount + 1);
     883           1 :     papszSubDatasets =
     884           1 :         CSLSetNameValue(papszSubDatasets, szName, osSubDatasetName);
     885             : 
     886           1 :     snprintf(szName, sizeof(szName), "SUBDATASET_%d_DESC", nCount + 1);
     887           1 :     papszSubDatasets =
     888           1 :         CSLSetNameValue(papszSubDatasets, szName, osSubDatasetName);
     889           1 : }
     890             : 
     891             : /************************************************************************/
     892             : /*                            GetMetadata()                             */
     893             : /************************************************************************/
     894             : 
     895           5 : char **SRPDataset::GetMetadata(const char *pszDomain)
     896             : 
     897             : {
     898           5 :     if (pszDomain != nullptr && EQUAL(pszDomain, "SUBDATASETS"))
     899           1 :         return papszSubDatasets;
     900             : 
     901           4 :     return GDALPamDataset::GetMetadata(pszDomain);
     902             : }
     903             : 
     904             : /************************************************************************/
     905             : /*                      FindRecordInGENForIMG()                         */
     906             : /************************************************************************/
     907             : 
     908           3 : DDFRecord *SRPDataset::FindRecordInGENForIMG(DDFModule &module,
     909             :                                              const char *pszGENFileName,
     910             :                                              const char *pszIMGFileName)
     911             : {
     912             :     /* Finds the GEN file corresponding to the IMG file */
     913           3 :     if (!module.Open(pszGENFileName, TRUE))
     914           0 :         return nullptr;
     915             : 
     916           6 :     CPLString osShortIMGFilename = CPLGetFilename(pszIMGFileName);
     917             : 
     918           3 :     DDFField *field = nullptr;
     919           3 :     DDFFieldDefn *fieldDefn = nullptr;
     920             : 
     921             :     // Now finds the record.
     922             :     while (true)
     923             :     {
     924           3 :         CPLPushErrorHandler(CPLQuietErrorHandler);
     925           3 :         DDFRecord *record = module.ReadRecord();
     926           3 :         CPLPopErrorHandler();
     927           3 :         CPLErrorReset();
     928           3 :         if (record == nullptr)
     929           0 :             return nullptr;
     930             : 
     931           3 :         if (record->GetFieldCount() >= 5)
     932             :         {
     933           3 :             field = record->GetField(0);
     934           3 :             fieldDefn = field->GetFieldDefn();
     935           6 :             if (!(strcmp(fieldDefn->GetName(), "001") == 0 &&
     936           3 :                   fieldDefn->GetSubfieldCount() == 2))
     937             :             {
     938           0 :                 continue;
     939             :             }
     940             : 
     941           3 :             const char *RTY = record->GetStringSubfield("001", 0, "RTY", 0);
     942           3 :             if (RTY == nullptr)
     943           0 :                 continue;
     944             :             /* Ignore overviews */
     945           3 :             if (strcmp(RTY, "OVV") == 0)
     946           0 :                 continue;
     947             : 
     948           3 :             if (strcmp(RTY, "GIN") != 0)
     949           0 :                 continue;
     950             : 
     951           3 :             field = record->GetField(3);
     952           3 :             fieldDefn = field->GetFieldDefn();
     953             : 
     954           6 :             if (!(strcmp(fieldDefn->GetName(), "SPR") == 0 &&
     955           3 :                   fieldDefn->GetSubfieldCount() == 15))
     956             :             {
     957           0 :                 continue;
     958             :             }
     959             : 
     960           3 :             const char *pszBAD = record->GetStringSubfield("SPR", 0, "BAD", 0);
     961           3 :             if (pszBAD == nullptr || strlen(pszBAD) != 12)
     962           0 :                 continue;
     963           3 :             const CPLString osBAD = pszBAD;
     964             :             {
     965           3 :                 char *c = (char *)strchr(osBAD.c_str(), ' ');
     966           3 :                 if (c)
     967           0 :                     *c = 0;
     968             :             }
     969             : 
     970           3 :             if (EQUAL(osShortIMGFilename.c_str(), osBAD.c_str()))
     971             :             {
     972           3 :                 return record;
     973             :             }
     974             :         }
     975           0 :     }
     976             : }
     977             : 
     978             : /************************************************************************/
     979             : /*                           OpenDataset()                              */
     980             : /************************************************************************/
     981             : 
     982          12 : SRPDataset *SRPDataset::OpenDataset(const char *pszGENFileName,
     983             :                                     const char *pszIMGFileName,
     984             :                                     DDFRecord *record)
     985             : {
     986          24 :     DDFModule module;  // Don't move this line as it holds ownership of record.
     987             : 
     988          12 :     if (record == nullptr)
     989             :     {
     990           3 :         record = FindRecordInGENForIMG(module, pszGENFileName, pszIMGFileName);
     991           3 :         if (record == nullptr)
     992           0 :             return nullptr;
     993             :     }
     994             : 
     995          12 :     DDFField *field = record->GetField(1);
     996          12 :     if (field == nullptr)
     997           0 :         return nullptr;
     998          12 :     DDFFieldDefn *fieldDefn = field->GetFieldDefn();
     999             : 
    1000          24 :     if (!(strcmp(fieldDefn->GetName(), "DSI") == 0 &&
    1001          12 :           fieldDefn->GetSubfieldCount() == 2))
    1002             :     {
    1003           0 :         return nullptr;
    1004             :     }
    1005             : 
    1006          12 :     const char *pszPRT = record->GetStringSubfield("DSI", 0, "PRT", 0);
    1007          12 :     if (pszPRT == nullptr)
    1008           0 :         return nullptr;
    1009             : 
    1010          24 :     CPLString osPRT = pszPRT;
    1011          12 :     osPRT.resize(4);
    1012          12 :     CPLDebug("SRP", "osPRT=%s", osPRT.c_str());
    1013          12 :     if (!EQUAL(osPRT, "ASRP") && !EQUAL(osPRT, "USRP"))
    1014           0 :         return nullptr;
    1015             : 
    1016          12 :     const char *pszNAM = record->GetStringSubfield("DSI", 0, "NAM", 0);
    1017          12 :     if (pszNAM == nullptr)
    1018           0 :         return nullptr;
    1019             : 
    1020          24 :     const CPLString osNAM = pszNAM;
    1021          12 :     CPLDebug("SRP", "osNAM=%s", osNAM.c_str());
    1022          12 :     if (strlen(pszNAM) != 8)
    1023             :     {
    1024          12 :         CPLDebug("SRP", "Name Size=%d", (int)strlen(pszNAM));
    1025             :     }
    1026             : 
    1027          12 :     SRPDataset *poDS = new SRPDataset();
    1028             : 
    1029          12 :     poDS->osProduct = osPRT;
    1030          12 :     poDS->osGENFileName = pszGENFileName;
    1031          12 :     poDS->osIMGFileName = pszIMGFileName;
    1032             : 
    1033          12 :     poDS->SetMetadataItem("SRP_NAM", osNAM);
    1034          12 :     poDS->SetMetadataItem("SRP_PRODUCT", osPRT);
    1035             : 
    1036          12 :     if (!poDS->GetFromRecord(pszGENFileName, record))
    1037             :     {
    1038           0 :         delete poDS;
    1039           0 :         return nullptr;
    1040             :     }
    1041             : 
    1042          12 :     return poDS;
    1043             : }
    1044             : 
    1045             : /************************************************************************/
    1046             : /*                          GetGENListFromTHF()                         */
    1047             : /************************************************************************/
    1048             : 
    1049           4 : char **SRPDataset::GetGENListFromTHF(const char *pszFileName)
    1050             : {
    1051           8 :     DDFModule module;
    1052           4 :     DDFRecord *record = nullptr;
    1053           4 :     DDFField *field = nullptr;
    1054           4 :     DDFFieldDefn *fieldDefn = nullptr;
    1055           4 :     int nFilenames = 0;
    1056             : 
    1057           4 :     char **papszFileNames = nullptr;
    1058           4 :     if (!module.Open(pszFileName, TRUE))
    1059           0 :         return papszFileNames;
    1060             : 
    1061           4 :     CPLString osDirName(CPLGetDirname(pszFileName));
    1062             : 
    1063             :     while (true)
    1064             :     {
    1065          14 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    1066          14 :         record = module.ReadRecord();
    1067          14 :         CPLPopErrorHandler();
    1068          14 :         CPLErrorReset();
    1069          14 :         if (record == nullptr)
    1070           4 :             break;
    1071          10 :         if (record->GetFieldCount() > 2)
    1072             :         {
    1073          10 :             field = record->GetField(0);
    1074          10 :             fieldDefn = field->GetFieldDefn();
    1075          20 :             if (!(strcmp(fieldDefn->GetName(), "001") == 0 &&
    1076          10 :                   fieldDefn->GetSubfieldCount() == 2))
    1077             :             {
    1078           0 :                 continue;
    1079             :             }
    1080             : 
    1081          10 :             const char *RTY = record->GetStringSubfield("001", 0, "RTY", 0);
    1082          10 :             if (RTY == nullptr)
    1083             :             {
    1084           0 :                 continue;
    1085             :             }
    1086             : 
    1087          10 :             if (strcmp(RTY, "THF") == 0)
    1088             :             {
    1089           3 :                 field = record->GetField(1);
    1090           3 :                 fieldDefn = field->GetFieldDefn();
    1091           6 :                 if (!(strcmp(fieldDefn->GetName(), "VDR") == 0 &&
    1092           3 :                       fieldDefn->GetSubfieldCount() == 8))
    1093             :                 {
    1094           0 :                     continue;
    1095             :                 }
    1096             : 
    1097           3 :                 int iFDRFieldInstance = 0;
    1098           6 :                 for (int i = 2; i < record->GetFieldCount(); i++)
    1099             :                 {
    1100           3 :                     field = record->GetField(i);
    1101           3 :                     fieldDefn = field->GetFieldDefn();
    1102             : 
    1103           6 :                     if (!(strcmp(fieldDefn->GetName(), "FDR") == 0 &&
    1104           3 :                           fieldDefn->GetSubfieldCount() == 7))
    1105             :                     {
    1106           0 :                         CPLDebug("SRP", "Record FDR  %d",
    1107             :                                  fieldDefn->GetSubfieldCount());
    1108           0 :                         continue;
    1109             :                     }
    1110             : 
    1111           3 :                     const char *pszNAM = record->GetStringSubfield(
    1112             :                         "FDR", iFDRFieldInstance++, "NAM", 0);
    1113           3 :                     if (pszNAM == nullptr)
    1114           0 :                         continue;
    1115             : 
    1116           6 :                     CPLString osName = CPLString(pszNAM);
    1117             : 
    1118             :                     /* Define a subdirectory from Dataset but with only 6
    1119             :                      * characters */
    1120           6 :                     CPLString osDirDataset = pszNAM;
    1121           3 :                     osDirDataset.resize(6);
    1122             :                     CPLString osDatasetDir = CPLFormFilename(
    1123           6 :                         osDirName.c_str(), osDirDataset.c_str(), nullptr);
    1124             : 
    1125           6 :                     CPLString osGENFileName = "";
    1126             : 
    1127           3 :                     int bFound = 0;
    1128             : 
    1129             :                     {
    1130             :                         char **papszDirContent =
    1131           3 :                             VSIReadDir(osDatasetDir.c_str());
    1132           3 :                         char **ptrDir = papszDirContent;
    1133           3 :                         if (ptrDir)
    1134             :                         {
    1135           0 :                             while (*ptrDir)
    1136             :                             {
    1137           0 :                                 if (EQUAL(CPLGetExtension(*ptrDir), "GEN"))
    1138             :                                 {
    1139           0 :                                     bFound = 1;
    1140             :                                     osGENFileName = CPLFormFilename(
    1141           0 :                                         osDatasetDir.c_str(), *ptrDir, nullptr);
    1142           0 :                                     CPLDebug("SRP",
    1143             :                                              "Building GEN full file name : %s",
    1144             :                                              osGENFileName.c_str());
    1145           0 :                                     break;
    1146             :                                 }
    1147           0 :                                 ptrDir++;
    1148             :                             }
    1149           0 :                             CSLDestroy(papszDirContent);
    1150             :                         }
    1151             :                     }
    1152             : 
    1153             :                     /* If not found in sub directory then search in the same
    1154             :                      * directory of the THF file */
    1155           3 :                     if (bFound == 0)
    1156             :                     {
    1157           3 :                         char **papszDirContent = VSIReadDir(osDirName.c_str());
    1158           3 :                         char **ptrDir = papszDirContent;
    1159           3 :                         if (ptrDir)
    1160             :                         {
    1161           7 :                             while (*ptrDir)
    1162             :                             {
    1163          10 :                                 if (EQUAL(CPLGetExtension(*ptrDir), "GEN") &&
    1164           3 :                                     EQUALN(CPLGetBasename(*ptrDir), osName, 6))
    1165             :                                 {
    1166           3 :                                     bFound = 1;
    1167             :                                     osGENFileName = CPLFormFilename(
    1168           3 :                                         osDirName.c_str(), *ptrDir, nullptr);
    1169           3 :                                     CPLDebug("SRP",
    1170             :                                              "Building GEN full file name : %s",
    1171             :                                              osGENFileName.c_str());
    1172           3 :                                     break;
    1173             :                                 }
    1174           4 :                                 ptrDir++;
    1175             :                             }
    1176           3 :                             CSLDestroy(papszDirContent);
    1177             :                         }
    1178             :                     }
    1179             : 
    1180           3 :                     if (bFound == 1)
    1181             :                     {
    1182           6 :                         papszFileNames = (char **)CPLRealloc(
    1183           3 :                             papszFileNames, sizeof(char *) * (nFilenames + 2));
    1184           6 :                         papszFileNames[nFilenames] =
    1185           3 :                             CPLStrdup(osGENFileName.c_str());
    1186           3 :                         papszFileNames[nFilenames + 1] = nullptr;
    1187           3 :                         nFilenames++;
    1188             :                     }
    1189             :                 }
    1190             :             }
    1191             :         }
    1192          10 :     }
    1193           4 :     return papszFileNames;
    1194             : }
    1195             : 
    1196             : /************************************************************************/
    1197             : /*                          AddMetadatafromFromTHF()                         */
    1198             : /************************************************************************/
    1199             : 
    1200           1 : void SRPDataset::AddMetadatafromFromTHF(const char *pszFileName)
    1201             : {
    1202           1 :     DDFModule module;
    1203           1 :     DDFRecord *record = nullptr;
    1204           1 :     DDFField *field = nullptr;
    1205           1 :     DDFFieldDefn *fieldDefn = nullptr;
    1206             : 
    1207           1 :     int bSuccess = 0;
    1208           1 :     if (!module.Open(pszFileName, TRUE))
    1209           0 :         return;
    1210             : 
    1211             :     while (true)
    1212             :     {
    1213           3 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    1214           3 :         record = module.ReadRecord();
    1215           3 :         CPLPopErrorHandler();
    1216           3 :         CPLErrorReset();
    1217           3 :         if (record == nullptr || record->GetFieldCount() <= 2)
    1218           1 :             break;
    1219             : 
    1220           2 :         field = record->GetField(0);
    1221           2 :         fieldDefn = field->GetFieldDefn();
    1222           4 :         if (!(strcmp(fieldDefn->GetName(), "001") == 0) ||
    1223           2 :             fieldDefn->GetSubfieldCount() != 2)
    1224           0 :             break;
    1225             : 
    1226           2 :         const char *RTY = record->GetStringSubfield("001", 0, "RTY", 0);
    1227           2 :         if (RTY != nullptr && strcmp(RTY, "THF") == 0)
    1228             :         {
    1229           1 :             field = record->GetField(1);
    1230           1 :             fieldDefn = field->GetFieldDefn();
    1231           2 :             if ((strcmp(fieldDefn->GetName(), "VDR") == 0 &&
    1232           1 :                  fieldDefn->GetSubfieldCount() == 8))
    1233             :             {
    1234             : 
    1235             :                 const char *pszVOO =
    1236           1 :                     record->GetStringSubfield("VDR", 0, "VOO", 0);
    1237           1 :                 if (pszVOO != nullptr)
    1238             :                 {
    1239           1 :                     CPLDebug("SRP", "Record VOO %s", pszVOO);
    1240           1 :                     SetMetadataItem("SRP_VOO", pszVOO);
    1241             :                 }
    1242             : 
    1243           1 :                 int EDN = record->GetIntSubfield("VDR", 0, "EDN", 0, &bSuccess);
    1244           1 :                 if (bSuccess)
    1245             :                 {
    1246           1 :                     CPLDebug("SRP", "Record EDN %d", EDN);
    1247             :                     char szValue[5];
    1248           1 :                     snprintf(szValue, sizeof(szValue), "%d", EDN);
    1249           1 :                     SetMetadataItem("SRP_EDN", szValue);
    1250             :                 }
    1251             : 
    1252             :                 const char *pszCDV07 =
    1253           1 :                     record->GetStringSubfield("VDR", 0, "CDV07", 0);
    1254           1 :                 if (pszCDV07 != nullptr)
    1255             :                 {
    1256           0 :                     CPLDebug("SRP", "Record pszCDV07 %s", pszCDV07);
    1257           0 :                     SetMetadataItem("SRP_CREATIONDATE", pszCDV07);
    1258             :                 }
    1259             :                 else
    1260             :                 { /*USRP1.2*/
    1261             :                     const char *pszDAT =
    1262           1 :                         record->GetStringSubfield("VDR", 0, "DAT", 0);
    1263           1 :                     if (pszDAT != nullptr)
    1264             :                     {
    1265             :                         char dat[9];
    1266           1 :                         strncpy(dat, pszDAT + 4, 8);
    1267           1 :                         dat[8] = '\0';
    1268           1 :                         CPLDebug("SRP", "Record DAT %s", dat);
    1269           1 :                         SetMetadataItem("SRP_CREATIONDATE", dat);
    1270             :                     }
    1271             :                 }
    1272             :             }
    1273             :         } /* End of THF part */
    1274             : 
    1275           2 :         if (RTY != nullptr && strcmp(RTY, "LCF") == 0)
    1276             :         {
    1277           1 :             field = record->GetField(1);
    1278           1 :             fieldDefn = field->GetFieldDefn();
    1279           2 :             if ((strcmp(fieldDefn->GetName(), "QSR") == 0 &&
    1280           1 :                  fieldDefn->GetSubfieldCount() == 4))
    1281             :             {
    1282             : 
    1283             :                 const char *pszQSS =
    1284           1 :                     record->GetStringSubfield("QSR", 0, "QSS", 0);
    1285           1 :                 if (pszQSS != nullptr)
    1286             :                 {
    1287           1 :                     CPLDebug("SRP", "Record Classification %s", pszQSS);
    1288           1 :                     SetMetadataItem("SRP_CLASSIFICATION", pszQSS);
    1289             :                 }
    1290             :             }
    1291             : 
    1292           1 :             field = record->GetField(2);
    1293           1 :             fieldDefn = field->GetFieldDefn();
    1294           2 :             if ((strcmp(fieldDefn->GetName(), "QUV") == 0 &&
    1295           1 :                  fieldDefn->GetSubfieldCount() == 6))
    1296             :             {
    1297             :                 const char *pszSRC2 =
    1298           0 :                     record->GetStringSubfield("QUV", 0, "SRC1", 0);
    1299           0 :                 if (pszSRC2 != nullptr)
    1300             :                 {
    1301           0 :                     SetMetadataItem("SRP_PRODUCTVERSION", pszSRC2);
    1302             :                 }
    1303             :                 else
    1304             :                 {
    1305             :                     const char *pszSRC =
    1306           0 :                         record->GetStringSubfield("QUV", 0, "SRC", 0);
    1307           0 :                     if (pszSRC != nullptr)
    1308             :                     {
    1309           0 :                         SetMetadataItem("SRP_PRODUCTVERSION", pszSRC);
    1310             :                     }
    1311             :                 }
    1312             :             }
    1313             :         } /* End of LCF part */
    1314           2 :     }
    1315             : }
    1316             : 
    1317             : /************************************************************************/
    1318             : /*                          GetIMGListFromGEN()                         */
    1319             : /************************************************************************/
    1320             : 
    1321           3 : char **SRPDataset::GetIMGListFromGEN(const char *pszFileName,
    1322             :                                      int *pnRecordIndex)
    1323             : {
    1324           3 :     DDFRecord *record = nullptr;
    1325           3 :     DDFField *field = nullptr;
    1326           3 :     DDFFieldDefn *fieldDefn = nullptr;
    1327           3 :     int nFilenames = 0;
    1328           3 :     char **papszFileNames = nullptr;
    1329           3 :     int nRecordIndex = -1;
    1330             : 
    1331           3 :     if (pnRecordIndex)
    1332           2 :         *pnRecordIndex = -1;
    1333             : 
    1334           6 :     DDFModule module;
    1335           3 :     if (!module.Open(pszFileName, TRUE))
    1336           0 :         return nullptr;
    1337             : 
    1338             :     while (true)
    1339             :     {
    1340           9 :         nRecordIndex++;
    1341             : 
    1342           9 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    1343           9 :         record = module.ReadRecord();
    1344           9 :         CPLPopErrorHandler();
    1345           9 :         CPLErrorReset();
    1346           9 :         if (record == nullptr)
    1347           3 :             break;
    1348             : 
    1349           6 :         if (record->GetFieldCount() >= 5)
    1350             :         {
    1351           3 :             field = record->GetField(0);
    1352           3 :             fieldDefn = field->GetFieldDefn();
    1353           6 :             if (!(strcmp(fieldDefn->GetName(), "001") == 0 &&
    1354           3 :                   fieldDefn->GetSubfieldCount() == 2))
    1355             :             {
    1356           0 :                 continue;
    1357             :             }
    1358             : 
    1359           3 :             const char *RTY = record->GetStringSubfield("001", 0, "RTY", 0);
    1360           3 :             if (RTY == nullptr)
    1361           0 :                 continue;
    1362             :             /* Ignore overviews */
    1363           3 :             if (strcmp(RTY, "OVV") == 0)
    1364           0 :                 continue;
    1365             : 
    1366           3 :             if (strcmp(RTY, "GIN") != 0)
    1367           0 :                 continue;
    1368             : 
    1369             :             /* make sure that the GEN file is part of a SRP dataset, not an ADRG
    1370             :              * dataset, by checking that the GEN field does not contain a NOW
    1371             :              * subfield */
    1372           3 :             const char *NWO = record->GetStringSubfield("GEN", 0, "NWO", 0);
    1373           3 :             if (NWO)
    1374             :             {
    1375           0 :                 CSLDestroy(papszFileNames);
    1376           0 :                 return nullptr;
    1377             :             }
    1378             : 
    1379           3 :             field = record->GetField(3);
    1380           3 :             if (field == nullptr)
    1381           0 :                 continue;
    1382           3 :             fieldDefn = field->GetFieldDefn();
    1383             : 
    1384           6 :             if (!(strcmp(fieldDefn->GetName(), "SPR") == 0 &&
    1385           3 :                   fieldDefn->GetSubfieldCount() == 15))
    1386             :             {
    1387           0 :                 continue;
    1388             :             }
    1389             : 
    1390           3 :             const char *pszBAD = record->GetStringSubfield("SPR", 0, "BAD", 0);
    1391           3 :             if (pszBAD == nullptr || strlen(pszBAD) != 12)
    1392           0 :                 continue;
    1393           6 :             CPLString osBAD = pszBAD;
    1394             :             {
    1395           3 :                 char *c = (char *)strchr(osBAD.c_str(), ' ');
    1396           3 :                 if (c)
    1397           0 :                     *c = 0;
    1398             :             }
    1399           3 :             CPLDebug("SRP", "BAD=%s", osBAD.c_str());
    1400             : 
    1401             :             /* Build full IMG file name from BAD value */
    1402           6 :             const CPLString osGENDir(CPLGetDirname(pszFileName));
    1403             : 
    1404             :             const CPLString osFileName =
    1405           3 :                 CPLFormFilename(osGENDir.c_str(), osBAD.c_str(), nullptr);
    1406             :             VSIStatBufL sStatBuf;
    1407           3 :             if (VSIStatL(osFileName, &sStatBuf) == 0)
    1408             :             {
    1409           3 :                 osBAD = osFileName;
    1410           3 :                 CPLDebug("SRP", "Building IMG full file name : %s",
    1411             :                          osBAD.c_str());
    1412             :             }
    1413             :             else
    1414             :             {
    1415           0 :                 char **papszDirContent = nullptr;
    1416           0 :                 if (strcmp(osGENDir.c_str(), "/vsimem") == 0)
    1417             :                 {
    1418           0 :                     CPLString osTmp = osGENDir + "/";
    1419           0 :                     papszDirContent = VSIReadDir(osTmp);
    1420             :                 }
    1421             :                 else
    1422           0 :                     papszDirContent = VSIReadDir(osGENDir);
    1423           0 :                 char **ptrDir = papszDirContent;
    1424           0 :                 while (ptrDir && *ptrDir)
    1425             :                 {
    1426           0 :                     if (EQUAL(*ptrDir, osBAD.c_str()))
    1427             :                     {
    1428             :                         osBAD =
    1429           0 :                             CPLFormFilename(osGENDir.c_str(), *ptrDir, nullptr);
    1430           0 :                         CPLDebug("SRP", "Building IMG full file name : %s",
    1431             :                                  osBAD.c_str());
    1432           0 :                         break;
    1433             :                     }
    1434           0 :                     ptrDir++;
    1435             :                 }
    1436           0 :                 CSLDestroy(papszDirContent);
    1437             :             }
    1438             : 
    1439           3 :             if (nFilenames == 0 && pnRecordIndex)
    1440           2 :                 *pnRecordIndex = nRecordIndex;
    1441             : 
    1442           6 :             papszFileNames = (char **)CPLRealloc(
    1443           3 :                 papszFileNames, sizeof(char *) * (nFilenames + 2));
    1444           3 :             papszFileNames[nFilenames] = CPLStrdup(osBAD.c_str());
    1445           3 :             papszFileNames[nFilenames + 1] = nullptr;
    1446           3 :             nFilenames++;
    1447             :         }
    1448           6 :     }
    1449             : 
    1450           3 :     return papszFileNames;
    1451             : }
    1452             : 
    1453             : /************************************************************************/
    1454             : /*                                Open()                                */
    1455             : /************************************************************************/
    1456             : 
    1457       29844 : GDALDataset *SRPDataset::Open(GDALOpenInfo *poOpenInfo)
    1458             : {
    1459       29844 :     int nRecordIndex = -1;
    1460       59677 :     CPLString osGENFileName;
    1461       59652 :     CPLString osIMGFileName;
    1462       29825 :     int bFromSubdataset = FALSE;
    1463       29825 :     int bTHFWithSingleGEN = FALSE;
    1464             : 
    1465       29825 :     if (STARTS_WITH_CI(poOpenInfo->pszFilename, "SRP:"))
    1466             :     {
    1467             :         char **papszTokens =
    1468           1 :             CSLTokenizeString2(poOpenInfo->pszFilename + 4, ",", 0);
    1469           1 :         if (CSLCount(papszTokens) == 2)
    1470             :         {
    1471           1 :             osGENFileName = papszTokens[0];
    1472           1 :             osIMGFileName = papszTokens[1];
    1473           1 :             bFromSubdataset = TRUE;
    1474             :         }
    1475           1 :         CSLDestroy(papszTokens);
    1476             :     }
    1477             :     else
    1478             :     {
    1479       29824 :         if (poOpenInfo->nHeaderBytes < 500)
    1480       27875 :             return nullptr;
    1481        1991 :         CPLString osFileName(poOpenInfo->pszFilename);
    1482             : 
    1483        1991 :         if (EQUAL(CPLGetExtension(osFileName.c_str()), "THF"))
    1484             :         {
    1485             : 
    1486           4 :             CPLDebug("SRP", "Read THF");
    1487             : 
    1488           4 :             char **papszFileNames = GetGENListFromTHF(osFileName.c_str());
    1489           4 :             if (papszFileNames == nullptr)
    1490           1 :                 return nullptr;
    1491           6 :             if (papszFileNames[1] == nullptr &&
    1492           3 :                 CPLTestBool(CPLGetConfigOption(
    1493             :                     "SRP_SINGLE_GEN_IN_THF_AS_DATASET", "TRUE")))
    1494             :             {
    1495           2 :                 osFileName = papszFileNames[0];
    1496           2 :                 CSLDestroy(papszFileNames);
    1497           2 :                 bTHFWithSingleGEN = TRUE;
    1498             :             }
    1499             :             else
    1500             :             {
    1501           1 :                 char **ptr = papszFileNames;
    1502           1 :                 SRPDataset *poDS = new SRPDataset();
    1503           1 :                 poDS->AddMetadatafromFromTHF(osFileName.c_str());
    1504           2 :                 while (*ptr)
    1505             :                 {
    1506           1 :                     char **papszIMGFileNames = GetIMGListFromGEN(*ptr);
    1507           1 :                     char **papszIMGIter = papszIMGFileNames;
    1508           2 :                     while (papszIMGIter && *papszIMGIter)
    1509             :                     {
    1510           1 :                         poDS->AddSubDataset(*ptr, *papszIMGIter);
    1511           1 :                         papszIMGIter++;
    1512             :                     }
    1513           1 :                     CSLDestroy(papszIMGFileNames);
    1514             : 
    1515           1 :                     ptr++;
    1516             :                 }
    1517           1 :                 CSLDestroy(papszFileNames);
    1518           1 :                 return poDS;
    1519             :             }
    1520             :         }
    1521             : 
    1522        1989 :         if (bTHFWithSingleGEN
    1523             : #ifdef OPEN_GEN
    1524             :             || EQUAL(CPLGetExtension(osFileName.c_str()), "GEN")
    1525             : #endif
    1526             :         )
    1527             :         {
    1528           2 :             osGENFileName = osFileName;
    1529             : 
    1530             :             char **papszFileNames =
    1531           2 :                 GetIMGListFromGEN(osFileName.c_str(), &nRecordIndex);
    1532           2 :             if (papszFileNames == nullptr)
    1533           0 :                 return nullptr;
    1534           2 :             if (papszFileNames[1] == nullptr)
    1535             :             {
    1536           2 :                 osIMGFileName = papszFileNames[0];
    1537           2 :                 CSLDestroy(papszFileNames);
    1538             :             }
    1539             :             else
    1540             :             {
    1541           0 :                 char **ptr = papszFileNames;
    1542           0 :                 SRPDataset *poDS = new SRPDataset();
    1543           0 :                 while (*ptr)
    1544             :                 {
    1545           0 :                     poDS->AddSubDataset(osFileName.c_str(), *ptr);
    1546           0 :                     ptr++;
    1547             :                 }
    1548           0 :                 CSLDestroy(papszFileNames);
    1549           0 :                 return poDS;
    1550             :             }
    1551             :         }
    1552             : 
    1553        1989 :         if (EQUAL(CPLGetExtension(osFileName.c_str()), "IMG"))
    1554             :         {
    1555             : 
    1556          49 :             osIMGFileName = osFileName;
    1557             : 
    1558          49 :             constexpr int nLeaderSize = 24;
    1559             : 
    1560          49 :             int i = 0;  // Used after for.
    1561         511 :             for (; i < nLeaderSize; i++)
    1562             :             {
    1563         498 :                 if (poOpenInfo->pabyHeader[i] < 32 ||
    1564         472 :                     poOpenInfo->pabyHeader[i] > 126)
    1565          40 :                     return nullptr;
    1566             :             }
    1567             : 
    1568          13 :             if (poOpenInfo->pabyHeader[5] != '1' &&
    1569          13 :                 poOpenInfo->pabyHeader[5] != '2' &&
    1570           4 :                 poOpenInfo->pabyHeader[5] != '3')
    1571           4 :                 return nullptr;
    1572             : 
    1573           9 :             if (poOpenInfo->pabyHeader[6] != 'L')
    1574           0 :                 return nullptr;
    1575           9 :             if (poOpenInfo->pabyHeader[8] != '1' &&
    1576           9 :                 poOpenInfo->pabyHeader[8] != ' ')
    1577           0 :                 return nullptr;
    1578             : 
    1579             :             // --------------------------------------------------------------------
    1580             :             //      Find and open the .GEN file.
    1581             :             // --------------------------------------------------------------------
    1582             :             VSIStatBufL sStatBuf;
    1583             : 
    1584           9 :             CPLString basename = CPLGetBasename(osFileName);
    1585           9 :             if (basename.size() != 8)
    1586             :             {
    1587           0 :                 CPLDebug("SRP", "Invalid basename file");
    1588           0 :                 return nullptr;
    1589             :             }
    1590             : 
    1591           9 :             nRecordIndex = static_cast<int>(CPLScanLong(basename + 6, 2));
    1592             : 
    1593           9 :             CPLString path = CPLGetDirname(osFileName);
    1594           9 :             CPLString basename01 = ResetTo01(basename);
    1595           9 :             osFileName = CPLFormFilename(path, basename01, ".IMG");
    1596             : 
    1597           9 :             osFileName = CPLResetExtension(osFileName, "GEN");
    1598           9 :             if (VSIStatL(osFileName, &sStatBuf) != 0)
    1599             :             {
    1600           0 :                 osFileName = CPLResetExtension(osFileName, "gen");
    1601           0 :                 if (VSIStatL(osFileName, &sStatBuf) != 0)
    1602           0 :                     return nullptr;
    1603             :             }
    1604             : 
    1605           9 :             osGENFileName = std::move(osFileName);
    1606             :         }
    1607             :     }
    1608             : 
    1609        1950 :     if (!osGENFileName.empty() && !osIMGFileName.empty())
    1610             :     {
    1611             : 
    1612          12 :         if (poOpenInfo->eAccess == GA_Update)
    1613             :         {
    1614           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    1615             :                      "The SRP driver does not support update access to existing"
    1616             :                      " datasets.\n");
    1617          12 :             return nullptr;
    1618             :         }
    1619             : 
    1620          12 :         DDFModule module;
    1621          12 :         DDFRecord *record = nullptr;
    1622          12 :         if (nRecordIndex >= 0 && module.Open(osGENFileName.c_str(), TRUE))
    1623             :         {
    1624          20 :             for (int i = 0; i < nRecordIndex; i++)
    1625             :             {
    1626           9 :                 CPLPushErrorHandler(CPLQuietErrorHandler);
    1627           9 :                 record = module.ReadRecord();
    1628           9 :                 CPLPopErrorHandler();
    1629           9 :                 CPLErrorReset();
    1630           9 :                 if (record == nullptr)
    1631           0 :                     break;
    1632             :             }
    1633             :         }
    1634             :         SRPDataset *poDS =
    1635          12 :             OpenDataset(osGENFileName.c_str(), osIMGFileName.c_str(), record);
    1636             : 
    1637          12 :         if (poDS)
    1638             :         {
    1639             :             /* ---------------------------------------------------------- */
    1640             :             /*      Initialize any PAM information.                       */
    1641             :             /* ---------------------------------------------------------- */
    1642          12 :             poDS->SetDescription(poOpenInfo->pszFilename);
    1643          12 :             poDS->TryLoadXML();
    1644             : 
    1645             :             /* ---------------------------------------------------------- */
    1646             :             /*      Check for external overviews.                         */
    1647             :             /* ---------------------------------------------------------- */
    1648          12 :             if (bFromSubdataset)
    1649           1 :                 poDS->oOvManager.Initialize(poDS, osIMGFileName.c_str());
    1650             :             else
    1651          11 :                 poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
    1652             : 
    1653          12 :             return poDS;
    1654             :         }
    1655             :     }
    1656             : 
    1657        1938 :     return nullptr;
    1658             : }
    1659             : 
    1660             : /************************************************************************/
    1661             : /*                         GDALRegister_SRP()                          */
    1662             : /************************************************************************/
    1663             : 
    1664        1595 : void GDALRegister_SRP()
    1665             : 
    1666             : {
    1667        1595 :     if (GDALGetDriverByName("SRP") != nullptr)
    1668         302 :         return;
    1669             : 
    1670        1293 :     GDALDriver *poDriver = new GDALDriver();
    1671             : 
    1672        1293 :     poDriver->SetDescription("SRP");
    1673        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
    1674        1293 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
    1675        1293 :                               "Standard Raster Product (ASRP/USRP)");
    1676        1293 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/srp.html");
    1677        1293 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "img");
    1678        1293 :     poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
    1679        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
    1680             : 
    1681        1293 :     poDriver->pfnOpen = SRPDataset::Open;
    1682             : 
    1683        1293 :     GetGDALDriverManager()->RegisterDriver(poDriver);
    1684             : }

Generated by: LCOV version 1.14