LCOV - code coverage report
Current view: top level - frmts/pds - isis2dataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 200 333 60.1 %
Date: 2025-03-28 21:34:50 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  ISIS Version 2 Driver
       4             :  * Purpose:  Implementation of ISIS2Dataset
       5             :  * Author:   Trent Hare (thare@usgs.gov),
       6             :  *           Robert Soricone (rsoricone@usgs.gov)
       7             :  *           Ludovic Mercier (ludovic.mercier@gmail.com)
       8             :  *           Frank Warmerdam (warmerdam@pobox.com)
       9             :  *
      10             :  * NOTE: Original code authored by Trent and Robert and placed in the public
      11             :  * domain as per US government policy.  I have (within my rights) appropriated
      12             :  * it and placed it under the following license.  This is not intended to
      13             :  * diminish Trent and Roberts contribution.
      14             :  ******************************************************************************
      15             :  * Copyright (c) 2006, Frank Warmerdam <warmerdam@pobox.com>
      16             :  * Copyright (c) 2008-2011, Even Rouault <even dot rouault at spatialys.com>
      17             :  *
      18             :  * SPDX-License-Identifier: MIT
      19             :  ****************************************************************************/
      20             : 
      21             : constexpr int NULL1 = 0;
      22             : constexpr int NULL2 = -32768;
      23             : constexpr double NULL3 = -3.4028226550889044521e+38;
      24             : 
      25             : #include "cpl_string.h"
      26             : #include "gdal_frmts.h"
      27             : #include "nasakeywordhandler.h"
      28             : #include "ogr_spatialref.h"
      29             : #include "rawdataset.h"
      30             : #include "pdsdrivercore.h"
      31             : 
      32             : /************************************************************************/
      33             : /* ==================================================================== */
      34             : /*                      ISISDataset     version2                        */
      35             : /* ==================================================================== */
      36             : /************************************************************************/
      37             : 
      38             : class ISIS2Dataset final : public RawDataset
      39             : {
      40             :     VSILFILE *fpImage;  // image data file.
      41             :     CPLString osExternalCube;
      42             : 
      43             :     NASAKeywordHandler oKeywords;
      44             : 
      45             :     int bGotTransform;
      46             :     double adfGeoTransform[6];
      47             : 
      48             :     OGRSpatialReference m_oSRS{};
      49             : 
      50             :     int parse_label(const char *file, char *keyword, char *value);
      51             :     int strstrip(char instr[], char outstr[], int position);
      52             : 
      53             :     CPLString oTempResult;
      54             : 
      55             :     static void CleanString(CPLString &osInput);
      56             : 
      57             :     const char *GetKeyword(const char *pszPath, const char *pszDefault = "");
      58             :     const char *GetKeywordSub(const char *pszPath, int iSubscript,
      59             :                               const char *pszDefault = "");
      60             : 
      61             :     CPLErr Close() override;
      62             : 
      63             :   public:
      64             :     ISIS2Dataset();
      65             :     virtual ~ISIS2Dataset();
      66             : 
      67             :     virtual CPLErr GetGeoTransform(double *padfTransform) override;
      68             :     const OGRSpatialReference *GetSpatialRef() const override;
      69             : 
      70             :     virtual char **GetFileList() override;
      71             : 
      72             :     static GDALDataset *Open(GDALOpenInfo *);
      73             : };
      74             : 
      75             : /************************************************************************/
      76             : /*                            ISIS2Dataset()                            */
      77             : /************************************************************************/
      78             : 
      79           2 : ISIS2Dataset::ISIS2Dataset() : fpImage(nullptr), bGotTransform(FALSE)
      80             : {
      81           2 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
      82           2 :     adfGeoTransform[0] = 0.0;
      83           2 :     adfGeoTransform[1] = 1.0;
      84           2 :     adfGeoTransform[2] = 0.0;
      85           2 :     adfGeoTransform[3] = 0.0;
      86           2 :     adfGeoTransform[4] = 0.0;
      87           2 :     adfGeoTransform[5] = 1.0;
      88           2 : }
      89             : 
      90             : /************************************************************************/
      91             : /*                            ~ISIS2Dataset()                            */
      92             : /************************************************************************/
      93             : 
      94           4 : ISIS2Dataset::~ISIS2Dataset()
      95             : 
      96             : {
      97           2 :     ISIS2Dataset::Close();
      98           4 : }
      99             : 
     100             : /************************************************************************/
     101             : /*                              Close()                                 */
     102             : /************************************************************************/
     103             : 
     104           4 : CPLErr ISIS2Dataset::Close()
     105             : {
     106           4 :     CPLErr eErr = CE_None;
     107           4 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
     108             :     {
     109           2 :         if (ISIS2Dataset::FlushCache(true) != CE_None)
     110           0 :             eErr = CE_Failure;
     111           2 :         if (fpImage != nullptr)
     112             :         {
     113           2 :             if (VSIFCloseL(fpImage) != 0)
     114           0 :                 eErr = CE_Failure;
     115             :         }
     116           2 :         if (GDALPamDataset::Close() != CE_None)
     117           0 :             eErr = CE_Failure;
     118             :     }
     119           4 :     return eErr;
     120             : }
     121             : 
     122             : /************************************************************************/
     123             : /*                            GetFileList()                             */
     124             : /************************************************************************/
     125             : 
     126           1 : char **ISIS2Dataset::GetFileList()
     127             : 
     128             : {
     129           1 :     char **papszFileList = GDALPamDataset::GetFileList();
     130             : 
     131           1 :     if (!osExternalCube.empty())
     132           0 :         papszFileList = CSLAddString(papszFileList, osExternalCube);
     133             : 
     134           1 :     return papszFileList;
     135             : }
     136             : 
     137             : /************************************************************************/
     138             : /*                         GetSpatialRef()                              */
     139             : /************************************************************************/
     140             : 
     141           1 : const OGRSpatialReference *ISIS2Dataset::GetSpatialRef() const
     142             : {
     143           1 :     if (!m_oSRS.IsEmpty())
     144           1 :         return &m_oSRS;
     145           0 :     return GDALPamDataset::GetSpatialRef();
     146             : }
     147             : 
     148             : /************************************************************************/
     149             : /*                          GetGeoTransform()                           */
     150             : /************************************************************************/
     151             : 
     152           1 : CPLErr ISIS2Dataset::GetGeoTransform(double *padfTransform)
     153             : 
     154             : {
     155           1 :     if (bGotTransform)
     156             :     {
     157           1 :         memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
     158           1 :         return CE_None;
     159             :     }
     160             : 
     161           0 :     return GDALPamDataset::GetGeoTransform(padfTransform);
     162             : }
     163             : 
     164             : /************************************************************************/
     165             : /*                                Open()                                */
     166             : /************************************************************************/
     167             : 
     168           2 : GDALDataset *ISIS2Dataset::Open(GDALOpenInfo *poOpenInfo)
     169             : {
     170             :     /* -------------------------------------------------------------------- */
     171             :     /*      Does this look like a CUBE or an IMAGE Primary Data Object?     */
     172             :     /* -------------------------------------------------------------------- */
     173           2 :     if (!ISIS2DriverIdentify(poOpenInfo) || poOpenInfo->fpL == nullptr)
     174           0 :         return nullptr;
     175             : 
     176           2 :     VSILFILE *fpQube = poOpenInfo->fpL;
     177           2 :     poOpenInfo->fpL = nullptr;
     178             : 
     179           4 :     auto poDS = std::make_unique<ISIS2Dataset>();
     180             : 
     181           2 :     if (!poDS->oKeywords.Ingest(fpQube, 0))
     182             :     {
     183           0 :         VSIFCloseL(fpQube);
     184           0 :         return nullptr;
     185             :     }
     186             : 
     187           2 :     VSIFCloseL(fpQube);
     188             : 
     189             :     /* -------------------------------------------------------------------- */
     190             :     /*      We assume the user is pointing to the label (i.e. .lab) file.   */
     191             :     /* -------------------------------------------------------------------- */
     192             :     // QUBE can be inline or detached and point to an image name
     193             :     // ^QUBE = 76
     194             :     // ^QUBE = ("ui31s015.img",6441<BYTES>) - has another label on the image
     195             :     // ^QUBE = "ui31s015.img" - which implies no label or skip value
     196             : 
     197           2 :     const char *pszQube = poDS->GetKeyword("^QUBE");
     198           2 :     int nQube = 0;
     199           2 :     int bByteLocation = FALSE;
     200           4 :     CPLString osTargetFile = poOpenInfo->pszFilename;
     201             : 
     202           2 :     if (pszQube[0] == '"')
     203             :     {
     204           0 :         const CPLString osTPath = CPLGetPathSafe(poOpenInfo->pszFilename);
     205           0 :         CPLString osFilename = pszQube;
     206           0 :         poDS->CleanString(osFilename);
     207           0 :         osTargetFile = CPLFormCIFilenameSafe(osTPath, osFilename, nullptr);
     208           0 :         poDS->osExternalCube = osTargetFile;
     209             :     }
     210           2 :     else if (pszQube[0] == '(')
     211             :     {
     212           0 :         const CPLString osTPath = CPLGetPathSafe(poOpenInfo->pszFilename);
     213           0 :         CPLString osFilename = poDS->GetKeywordSub("^QUBE", 1, "");
     214           0 :         poDS->CleanString(osFilename);
     215           0 :         osTargetFile = CPLFormCIFilenameSafe(osTPath, osFilename, nullptr);
     216           0 :         poDS->osExternalCube = osTargetFile;
     217             : 
     218           0 :         nQube = atoi(poDS->GetKeywordSub("^QUBE", 2, "1"));
     219           0 :         if (strstr(poDS->GetKeywordSub("^QUBE", 2, "1"), "<BYTES>") != nullptr)
     220           0 :             bByteLocation = true;
     221             :     }
     222             :     else
     223             :     {
     224           2 :         nQube = atoi(pszQube);
     225           2 :         if (strstr(pszQube, "<BYTES>") != nullptr)
     226           0 :             bByteLocation = true;
     227             :     }
     228             : 
     229             :     /* -------------------------------------------------------------------- */
     230             :     /*      Check if file an ISIS2 header file?  Read a few lines of text   */
     231             :     /*      searching for something starting with nrows or ncols.           */
     232             :     /* -------------------------------------------------------------------- */
     233             : 
     234             :     /* -------------------------------------------------------------------- */
     235             :     /*      Checks to see if this is valid ISIS2 cube                       */
     236             :     /*      SUFFIX_ITEM tag in .cub file should be (0,0,0); no side-planes  */
     237             :     /* -------------------------------------------------------------------- */
     238           2 :     const int s_ix = atoi(poDS->GetKeywordSub("QUBE.SUFFIX_ITEMS", 1));
     239           2 :     const int s_iy = atoi(poDS->GetKeywordSub("QUBE.SUFFIX_ITEMS", 2));
     240           2 :     const int s_iz = atoi(poDS->GetKeywordSub("QUBE.SUFFIX_ITEMS", 3));
     241             : 
     242           2 :     if (s_ix != 0 || s_iy != 0 || s_iz != 0)
     243             :     {
     244           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     245             :                  "*** ISIS 2 cube file has invalid SUFFIX_ITEMS parameters:\n"
     246             :                  "*** gdal isis2 driver requires (0, 0, 0), thus no sideplanes "
     247             :                  "or backplanes\n"
     248             :                  "found: (%i, %i, %i)\n\n",
     249             :                  s_ix, s_iy, s_iz);
     250           0 :         return nullptr;
     251             :     }
     252             : 
     253             :     /**************** end SUFFIX_ITEM check ***********************/
     254             : 
     255             :     /***********   Grab layout type (BSQ, BIP, BIL) ************/
     256             :     //  AXIS_NAME = (SAMPLE,LINE,BAND)
     257             :     /***********************************************************/
     258             : 
     259           2 :     char szLayout[10] = "BSQ";  // default to band seq.
     260           2 :     const char *value = poDS->GetKeyword("QUBE.AXIS_NAME", "");
     261           2 :     if (EQUAL(value, "(SAMPLE,LINE,BAND)"))
     262           2 :         strcpy(szLayout, "BSQ");
     263           0 :     else if (EQUAL(value, "(BAND,LINE,SAMPLE)"))
     264           0 :         strcpy(szLayout, "BIP");
     265           0 :     else if (EQUAL(value, "(SAMPLE,BAND,LINE)") || EQUAL(value, ""))
     266           0 :         strcpy(szLayout, "BSQ");
     267             :     else
     268             :     {
     269           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     270             :                  "%s layout not supported. Abort\n\n", value);
     271           0 :         return nullptr;
     272             :     }
     273             : 
     274             :     /***********   Grab samples lines band ************/
     275           2 :     const int nCols = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS", 1));
     276           2 :     const int nRows = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS", 2));
     277           2 :     const int nBands = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS", 3));
     278             : 
     279             :     /***********   Grab Qube record bytes  **********/
     280           2 :     const int record_bytes = atoi(poDS->GetKeyword("RECORD_BYTES"));
     281           2 :     if (record_bytes < 0)
     282             :     {
     283           0 :         return nullptr;
     284             :     }
     285             : 
     286           2 :     GUIntBig nSkipBytes = 0;
     287           2 :     if (nQube > 0 && bByteLocation)
     288           0 :         nSkipBytes = (nQube - 1);
     289           2 :     else if (nQube > 0)
     290           2 :         nSkipBytes = static_cast<GUIntBig>(nQube - 1) * record_bytes;
     291             :     else
     292           0 :         nSkipBytes = 0;
     293             : 
     294             :     /***********   Grab samples lines band ************/
     295           2 :     char chByteOrder = 'M';  // default to MSB
     296           4 :     CPLString osCoreItemType = poDS->GetKeyword("QUBE.CORE_ITEM_TYPE");
     297           2 :     if ((EQUAL(osCoreItemType, "PC_INTEGER")) ||
     298           4 :         (EQUAL(osCoreItemType, "PC_UNSIGNED_INTEGER")) ||
     299           2 :         (EQUAL(osCoreItemType, "PC_REAL")))
     300             :     {
     301           0 :         chByteOrder = 'I';
     302             :     }
     303             : 
     304             :     /********   Grab format type - isis2 only supports 8,16,32 *******/
     305           2 :     GDALDataType eDataType = GDT_Byte;
     306           2 :     bool bNoDataSet = false;
     307           2 :     double dfNoData = 0.0;
     308             : 
     309           2 :     int itype = atoi(poDS->GetKeyword("QUBE.CORE_ITEM_BYTES", ""));
     310           2 :     switch (itype)
     311             :     {
     312           0 :         case 1:
     313           0 :             eDataType = GDT_Byte;
     314           0 :             dfNoData = NULL1;
     315           0 :             bNoDataSet = true;
     316           0 :             break;
     317           0 :         case 2:
     318           0 :             if (strstr(osCoreItemType, "UNSIGNED") != nullptr)
     319             :             {
     320           0 :                 dfNoData = 0;
     321           0 :                 eDataType = GDT_UInt16;
     322             :             }
     323             :             else
     324             :             {
     325           0 :                 dfNoData = NULL2;
     326           0 :                 eDataType = GDT_Int16;
     327             :             }
     328           0 :             bNoDataSet = true;
     329           0 :             break;
     330           2 :         case 4:
     331           2 :             eDataType = GDT_Float32;
     332           2 :             dfNoData = NULL3;
     333           2 :             bNoDataSet = true;
     334           2 :             break;
     335           0 :         case 8:
     336           0 :             eDataType = GDT_Float64;
     337           0 :             dfNoData = NULL3;
     338           0 :             bNoDataSet = true;
     339           0 :             break;
     340           0 :         default:
     341           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     342             :                      "Itype of %d is not supported in ISIS 2.", itype);
     343           0 :             return nullptr;
     344             :     }
     345             : 
     346             :     /***********   Grab Cellsize ************/
     347           2 :     double dfXDim = 1.0;
     348           2 :     double dfYDim = 1.0;
     349             : 
     350           2 :     value = poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.MAP_SCALE");
     351           2 :     if (strlen(value) > 0)
     352             :     {
     353             :         // Convert km to m
     354           2 :         dfXDim = static_cast<float>(CPLAtof(value) * 1000.0);
     355           2 :         dfYDim = static_cast<float>(CPLAtof(value) * 1000.0 * -1);
     356             :     }
     357             : 
     358             :     /***********   Grab LINE_PROJECTION_OFFSET ************/
     359           2 :     double dfULYMap = 0.5;
     360             : 
     361             :     value =
     362           2 :         poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.LINE_PROJECTION_OFFSET");
     363           2 :     if (strlen(value) > 0)
     364             :     {
     365           2 :         const double yulcenter = static_cast<float>(CPLAtof(value)) * dfYDim;
     366           2 :         dfULYMap = yulcenter - (dfYDim / 2);
     367             :     }
     368             : 
     369             :     /***********   Grab SAMPLE_PROJECTION_OFFSET ************/
     370           2 :     double dfULXMap = 0.5;
     371             : 
     372             :     value =
     373           2 :         poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.SAMPLE_PROJECTION_OFFSET");
     374           2 :     if (strlen(value) > 0)
     375             :     {
     376           2 :         const double xulcenter = static_cast<float>(CPLAtof(value)) * dfXDim;
     377           2 :         dfULXMap = xulcenter - (dfXDim / 2);
     378             :     }
     379             : 
     380             :     /***********  Grab TARGET_NAME  ************/
     381             :     /**** This is the planets name i.e. MARS ***/
     382           4 :     const CPLString target_name = poDS->GetKeyword("QUBE.TARGET_NAME");
     383             : 
     384             :     /***********   Grab MAP_PROJECTION_TYPE ************/
     385             :     CPLString map_proj_name =
     386           4 :         poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.MAP_PROJECTION_TYPE");
     387           2 :     poDS->CleanString(map_proj_name);
     388             : 
     389             :     /***********   Grab SEMI-MAJOR ************/
     390             :     const double semi_major =
     391           2 :         CPLAtof(poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.A_AXIS_RADIUS")) *
     392           2 :         1000.0;
     393             : 
     394             :     /***********   Grab semi-minor ************/
     395             :     const double semi_minor =
     396           2 :         CPLAtof(poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.C_AXIS_RADIUS")) *
     397           2 :         1000.0;
     398             : 
     399             :     /***********   Grab CENTER_LAT ************/
     400             :     const double center_lat =
     401           2 :         CPLAtof(poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.CENTER_LATITUDE"));
     402             : 
     403             :     /***********   Grab CENTER_LON ************/
     404             :     const double center_lon =
     405           2 :         CPLAtof(poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.CENTER_LONGITUDE"));
     406             : 
     407             :     /***********   Grab 1st std parallel ************/
     408           2 :     const double first_std_parallel = CPLAtof(
     409             :         poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.FIRST_STANDARD_PARALLEL"));
     410             : 
     411             :     /***********   Grab 2nd std parallel ************/
     412           2 :     const double second_std_parallel = CPLAtof(
     413             :         poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.SECOND_STANDARD_PARALLEL"));
     414             : 
     415             :     /*** grab  PROJECTION_LATITUDE_TYPE = "PLANETOCENTRIC" ****/
     416             :     // Need to further study how ocentric/ographic will effect the gdal library.
     417             :     // So far we will use this fact to define a sphere or ellipse for some
     418             :     // projections Frank - may need to talk this over
     419           2 :     bool bIsGeographic = true;
     420             :     value =
     421           2 :         poDS->GetKeyword("CUBE.IMAGE_MAP_PROJECTION.PROJECTION_LATITUDE_TYPE");
     422           2 :     if (EQUAL(value, "\"PLANETOCENTRIC\""))
     423           0 :         bIsGeographic = false;
     424             : 
     425           2 :     CPLDebug("ISIS2", "using projection %s", map_proj_name.c_str());
     426             : 
     427           4 :     OGRSpatialReference oSRS;
     428           2 :     oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     429           2 :     bool bProjectionSet = true;
     430             : 
     431             :     // Set oSRS projection and parameters
     432           2 :     if ((EQUAL(map_proj_name, "EQUIRECTANGULAR_CYLINDRICAL")) ||
     433           4 :         (EQUAL(map_proj_name, "EQUIRECTANGULAR")) ||
     434           2 :         (EQUAL(map_proj_name, "SIMPLE_CYLINDRICAL")))
     435             :     {
     436           2 :         oSRS.OGRSpatialReference::SetEquirectangular2(0.0, center_lon,
     437             :                                                       center_lat, 0, 0);
     438             :     }
     439           0 :     else if (EQUAL(map_proj_name, "ORTHOGRAPHIC"))
     440             :     {
     441           0 :         oSRS.OGRSpatialReference::SetOrthographic(center_lat, center_lon, 0, 0);
     442             :     }
     443           0 :     else if ((EQUAL(map_proj_name, "SINUSOIDAL")) ||
     444           0 :              (EQUAL(map_proj_name, "SINUSOIDAL_EQUAL-AREA")))
     445             :     {
     446           0 :         oSRS.OGRSpatialReference::SetSinusoidal(center_lon, 0, 0);
     447             :     }
     448           0 :     else if (EQUAL(map_proj_name, "MERCATOR"))
     449             :     {
     450           0 :         oSRS.OGRSpatialReference::SetMercator(center_lat, center_lon, 1, 0, 0);
     451             :     }
     452           0 :     else if (EQUAL(map_proj_name, "POLAR_STEREOGRAPHIC"))
     453             :     {
     454           0 :         oSRS.OGRSpatialReference::SetPS(center_lat, center_lon, 1, 0, 0);
     455             :     }
     456           0 :     else if (EQUAL(map_proj_name, "TRANSVERSE_MERCATOR"))
     457             :     {
     458           0 :         oSRS.OGRSpatialReference::SetTM(center_lat, center_lon, 1, 0, 0);
     459             :     }
     460           0 :     else if (EQUAL(map_proj_name, "LAMBERT_CONFORMAL_CONIC"))
     461             :     {
     462           0 :         oSRS.OGRSpatialReference::SetLCC(first_std_parallel,
     463             :                                          second_std_parallel, center_lat,
     464             :                                          center_lon, 0, 0);
     465             :     }
     466           0 :     else if (EQUAL(map_proj_name, ""))
     467             :     {
     468             :         /* no projection */
     469           0 :         bProjectionSet = false;
     470             :     }
     471             :     else
     472             :     {
     473           0 :         CPLDebug("ISIS2",
     474             :                  "Dataset projection %s is not supported. Continuing...",
     475             :                  map_proj_name.c_str());
     476           0 :         bProjectionSet = false;
     477             :     }
     478             : 
     479           2 :     if (bProjectionSet)
     480             :     {
     481             :         // Create projection name, i.e. MERCATOR MARS and set as ProjCS keyword
     482           6 :         const CPLString proj_target_name = map_proj_name + " " + target_name;
     483           2 :         oSRS.SetProjCS(proj_target_name);  // set ProjCS keyword
     484             : 
     485             :         // The geographic/geocentric name will be the same basic name as the
     486             :         // body name 'GCS' = Geographic/Geocentric Coordinate System
     487           4 :         const CPLString geog_name = "GCS_" + target_name;
     488             : 
     489             :         // The datum and sphere names will be the same basic name aas the planet
     490           4 :         const CPLString datum_name = "D_" + target_name;
     491             :         // Might not be IAU defined so don't add.
     492           4 :         CPLString sphere_name = target_name;  // + "_IAU_IAG");
     493             : 
     494             :         // calculate inverse flattening from major and minor axis: 1/f = a/(a-b)
     495           2 :         double iflattening = 0.0;
     496           2 :         if ((semi_major - semi_minor) < 0.0000001)
     497           2 :             iflattening = 0;
     498             :         else
     499           0 :             iflattening = semi_major / (semi_major - semi_minor);
     500             : 
     501             :         // Set the body size but take into consideration which proj is being
     502             :         // used to help w/ proj4 compatibility The use of a Sphere, polar radius
     503             :         // or ellipse here is based on how ISIS does it internally
     504           2 :         if (((EQUAL(map_proj_name, "STEREOGRAPHIC") &&
     505           4 :               (fabs(center_lat) == 90))) ||
     506           2 :             (EQUAL(map_proj_name, "POLAR_STEREOGRAPHIC")))
     507             :         {
     508           0 :             if (bIsGeographic)
     509             :             {
     510             :                 // Geograpraphic, so set an ellipse
     511           0 :                 oSRS.SetGeogCS(geog_name, datum_name, sphere_name, semi_major,
     512             :                                iflattening, "Reference_Meridian", 0.0);
     513             :             }
     514             :             else
     515             :             {
     516             :                 // Geocentric, so force a sphere using the semi-minor axis. I
     517             :                 // hope...
     518           0 :                 sphere_name += "_polarRadius";
     519           0 :                 oSRS.SetGeogCS(geog_name, datum_name, sphere_name, semi_minor,
     520             :                                0.0, "Reference_Meridian", 0.0);
     521             :             }
     522             :         }
     523           2 :         else if ((EQUAL(map_proj_name, "SIMPLE_CYLINDRICAL")) ||
     524           0 :                  (EQUAL(map_proj_name, "ORTHOGRAPHIC")) ||
     525           0 :                  (EQUAL(map_proj_name, "STEREOGRAPHIC")) ||
     526           2 :                  (EQUAL(map_proj_name, "SINUSOIDAL_EQUAL-AREA")) ||
     527           0 :                  (EQUAL(map_proj_name, "SINUSOIDAL")))
     528             :         {
     529             :             // ISIS uses the spherical equation for these projections so force
     530             :             // a sphere.
     531           2 :             oSRS.SetGeogCS(geog_name, datum_name, sphere_name, semi_major, 0.0,
     532             :                            "Reference_Meridian", 0.0);
     533             :         }
     534           0 :         else if ((EQUAL(map_proj_name, "EQUIRECTANGULAR_CYLINDRICAL")) ||
     535           0 :                  (EQUAL(map_proj_name, "EQUIRECTANGULAR")))
     536             :         {
     537             :             // Calculate localRadius using ISIS3 simple elliptical method
     538             :             //   not the more standard Radius of Curvature method
     539             :             // PI = 4 * atan(1);
     540           0 :             if (center_lon == 0)
     541             :             {  // No need to calculate local radius
     542           0 :                 oSRS.SetGeogCS(geog_name, datum_name, sphere_name, semi_major,
     543             :                                0.0, "Reference_Meridian", 0.0);
     544             :             }
     545             :             else
     546             :             {
     547           0 :                 const double radLat = center_lat * M_PI / 180;  // in radians
     548             :                 const double localRadius =
     549           0 :                     semi_major * semi_minor /
     550           0 :                     sqrt(pow(semi_minor * cos(radLat), 2) +
     551           0 :                          pow(semi_major * sin(radLat), 2));
     552           0 :                 sphere_name += "_localRadius";
     553           0 :                 oSRS.SetGeogCS(geog_name, datum_name, sphere_name, localRadius,
     554             :                                0.0, "Reference_Meridian", 0.0);
     555           0 :                 CPLDebug("ISIS2", "local radius: %f", localRadius);
     556             :             }
     557             :         }
     558             :         else
     559             :         {
     560             :             // All other projections: Mercator, Transverse Mercator, Lambert
     561             :             // Conformal, etc. Geographic, so set an ellipse
     562           0 :             if (bIsGeographic)
     563             :             {
     564           0 :                 oSRS.SetGeogCS(geog_name, datum_name, sphere_name, semi_major,
     565             :                                iflattening, "Reference_Meridian", 0.0);
     566             :             }
     567             :             else
     568             :             {
     569             :                 // Geocentric, so force a sphere. I hope...
     570           0 :                 oSRS.SetGeogCS(geog_name, datum_name, sphere_name, semi_major,
     571             :                                0.0, "Reference_Meridian", 0.0);
     572             :             }
     573             :         }
     574             : 
     575             :         // translate back into a projection string.
     576           2 :         poDS->m_oSRS = std::move(oSRS);
     577             :     }
     578             : 
     579             :     /* END ISIS2 Label Read */
     580             :     /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
     581             : 
     582             :     /* -------------------------------------------------------------------- */
     583             :     /*      Did we get the required keywords?  If not we return with        */
     584             :     /*      this never having been considered to be a match. This isn't     */
     585             :     /*      an error!                                                       */
     586             :     /* -------------------------------------------------------------------- */
     587           4 :     if (!GDALCheckDatasetDimensions(nCols, nRows) ||
     588           2 :         !GDALCheckBandCount(nBands, false))
     589             :     {
     590           0 :         return nullptr;
     591             :     }
     592             : 
     593             :     /* -------------------------------------------------------------------- */
     594             :     /*      Capture some information from the file that is of interest.     */
     595             :     /* -------------------------------------------------------------------- */
     596           2 :     poDS->nRasterXSize = nCols;
     597           2 :     poDS->nRasterYSize = nRows;
     598             : 
     599             :     /* -------------------------------------------------------------------- */
     600             :     /*      Open target binary file.                                        */
     601             :     /* -------------------------------------------------------------------- */
     602             : 
     603           2 :     if (poOpenInfo->eAccess == GA_ReadOnly)
     604           2 :         poDS->fpImage = VSIFOpenL(osTargetFile, "rb");
     605             :     else
     606           0 :         poDS->fpImage = VSIFOpenL(osTargetFile, "r+b");
     607             : 
     608           2 :     if (poDS->fpImage == nullptr)
     609             :     {
     610           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     611             :                  "Failed to open %s with write permission.\n%s",
     612           0 :                  osTargetFile.c_str(), VSIStrerror(errno));
     613           0 :         return nullptr;
     614             :     }
     615             : 
     616           2 :     poDS->eAccess = poOpenInfo->eAccess;
     617             : 
     618             :     /* -------------------------------------------------------------------- */
     619             :     /*      Compute the line offset.                                        */
     620             :     /* -------------------------------------------------------------------- */
     621           2 :     int nItemSize = GDALGetDataTypeSizeBytes(eDataType);
     622             :     int nLineOffset, nPixelOffset;
     623             :     vsi_l_offset nBandOffset;
     624             : 
     625           2 :     if (EQUAL(szLayout, "BIP"))
     626             :     {
     627           0 :         nPixelOffset = nItemSize * nBands;
     628           0 :         if (nPixelOffset > INT_MAX / nBands)
     629             :         {
     630           0 :             return nullptr;
     631             :         }
     632           0 :         nLineOffset = nPixelOffset * nCols;
     633           0 :         nBandOffset = nItemSize;
     634             :     }
     635           2 :     else if (EQUAL(szLayout, "BSQ"))
     636             :     {
     637           2 :         nPixelOffset = nItemSize;
     638           2 :         if (nPixelOffset > INT_MAX / nCols)
     639             :         {
     640           0 :             return nullptr;
     641             :         }
     642           2 :         nLineOffset = nPixelOffset * nCols;
     643           2 :         nBandOffset = static_cast<vsi_l_offset>(nLineOffset) * nRows;
     644             :     }
     645             :     else /* assume BIL */
     646             :     {
     647           0 :         nPixelOffset = nItemSize;
     648           0 :         if (nPixelOffset > INT_MAX / nBands ||
     649           0 :             nPixelOffset * nBands > INT_MAX / nCols)
     650             :         {
     651           0 :             return nullptr;
     652             :         }
     653           0 :         nLineOffset = nItemSize * nBands * nCols;
     654           0 :         nBandOffset = static_cast<vsi_l_offset>(nItemSize) * nCols;
     655             :     }
     656             : 
     657             :     /* -------------------------------------------------------------------- */
     658             :     /*      Create band information objects.                                */
     659             :     /* -------------------------------------------------------------------- */
     660           4 :     for (int i = 0; i < nBands; i++)
     661             :     {
     662             :         auto poBand = RawRasterBand::Create(
     663           4 :             poDS.get(), i + 1, poDS->fpImage, nSkipBytes + nBandOffset * i,
     664             :             nPixelOffset, nLineOffset, eDataType,
     665             :             chByteOrder == 'I' || chByteOrder == 'L'
     666           2 :                 ? RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN
     667             :                 : RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
     668           2 :             RawRasterBand::OwnFP::NO);
     669           2 :         if (!poBand)
     670           0 :             return nullptr;
     671             : 
     672           2 :         if (bNoDataSet)
     673           2 :             poBand->SetNoDataValue(dfNoData);
     674             : 
     675             :         // Set offset/scale values at the PAM level.
     676           2 :         poBand->SetOffset(CPLAtofM(poDS->GetKeyword("QUBE.CORE_BASE", "0.0")));
     677           4 :         poBand->SetScale(
     678           2 :             CPLAtofM(poDS->GetKeyword("QUBE.CORE_MULTIPLIER", "1.0")));
     679             : 
     680           2 :         poDS->SetBand(i + 1, std::move(poBand));
     681             :     }
     682             : 
     683             :     /* -------------------------------------------------------------------- */
     684             :     /*      Check for a .prj file. For isis2 I would like to keep this in   */
     685             :     /* -------------------------------------------------------------------- */
     686           4 :     const CPLString osPath = CPLGetPathSafe(poOpenInfo->pszFilename);
     687           4 :     const CPLString osName = CPLGetBasenameSafe(poOpenInfo->pszFilename);
     688           4 :     const std::string osPrjFile = CPLFormCIFilenameSafe(osPath, osName, "prj");
     689             : 
     690           2 :     VSILFILE *fp = VSIFOpenL(osPrjFile.c_str(), "r");
     691           2 :     if (fp != nullptr)
     692             :     {
     693           0 :         VSIFCloseL(fp);
     694             : 
     695           0 :         char **papszLines = CSLLoad(osPrjFile.c_str());
     696             : 
     697           0 :         poDS->m_oSRS.importFromESRI(papszLines);
     698             : 
     699           0 :         CSLDestroy(papszLines);
     700             :     }
     701             : 
     702           2 :     if (dfULXMap != 0.5 || dfULYMap != 0.5 || dfXDim != 1.0 || dfYDim != 1.0)
     703             :     {
     704           2 :         poDS->bGotTransform = TRUE;
     705           2 :         poDS->adfGeoTransform[0] = dfULXMap;
     706           2 :         poDS->adfGeoTransform[1] = dfXDim;
     707           2 :         poDS->adfGeoTransform[2] = 0.0;
     708           2 :         poDS->adfGeoTransform[3] = dfULYMap;
     709           2 :         poDS->adfGeoTransform[4] = 0.0;
     710           2 :         poDS->adfGeoTransform[5] = dfYDim;
     711             :     }
     712             : 
     713           2 :     if (!poDS->bGotTransform)
     714           0 :         poDS->bGotTransform = GDALReadWorldFile(poOpenInfo->pszFilename, "cbw",
     715           0 :                                                 poDS->adfGeoTransform);
     716             : 
     717           2 :     if (!poDS->bGotTransform)
     718           0 :         poDS->bGotTransform = GDALReadWorldFile(poOpenInfo->pszFilename, "wld",
     719           0 :                                                 poDS->adfGeoTransform);
     720             : 
     721             :     /* -------------------------------------------------------------------- */
     722             :     /*      Initialize any PAM information.                                 */
     723             :     /* -------------------------------------------------------------------- */
     724           2 :     poDS->SetDescription(poOpenInfo->pszFilename);
     725           2 :     poDS->TryLoadXML();
     726             : 
     727             :     /* -------------------------------------------------------------------- */
     728             :     /*      Check for overviews.                                            */
     729             :     /* -------------------------------------------------------------------- */
     730           2 :     poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
     731             : 
     732           2 :     return poDS.release();
     733             : }
     734             : 
     735             : /************************************************************************/
     736             : /*                             GetKeyword()                             */
     737             : /************************************************************************/
     738             : 
     739          38 : const char *ISIS2Dataset::GetKeyword(const char *pszPath,
     740             :                                      const char *pszDefault)
     741             : 
     742             : {
     743          38 :     return oKeywords.GetKeyword(pszPath, pszDefault);
     744             : }
     745             : 
     746             : /************************************************************************/
     747             : /*                            GetKeywordSub()                           */
     748             : /************************************************************************/
     749             : 
     750          12 : const char *ISIS2Dataset::GetKeywordSub(const char *pszPath, int iSubscript,
     751             :                                         const char *pszDefault)
     752             : 
     753             : {
     754          12 :     const char *pszResult = oKeywords.GetKeyword(pszPath, nullptr);
     755             : 
     756          12 :     if (pszResult == nullptr)
     757           0 :         return pszDefault;
     758             : 
     759          12 :     if (pszResult[0] != '(')
     760           0 :         return pszDefault;
     761             : 
     762             :     char **papszTokens =
     763          12 :         CSLTokenizeString2(pszResult, "(,)", CSLT_HONOURSTRINGS);
     764             : 
     765          12 :     if (iSubscript <= CSLCount(papszTokens))
     766             :     {
     767          12 :         oTempResult = papszTokens[iSubscript - 1];
     768          12 :         CSLDestroy(papszTokens);
     769          12 :         return oTempResult.c_str();
     770             :     }
     771             : 
     772           0 :     CSLDestroy(papszTokens);
     773           0 :     return pszDefault;
     774             : }
     775             : 
     776             : /************************************************************************/
     777             : /*                            CleanString()                             */
     778             : /*                                                                      */
     779             : /* Removes single or double quotes, and converts spaces to underscores. */
     780             : /* The change is made in-place to CPLString.                            */
     781             : /************************************************************************/
     782             : 
     783           2 : void ISIS2Dataset::CleanString(CPLString &osInput)
     784             : 
     785             : {
     786           4 :     if ((osInput.size() < 2) ||
     787           2 :         ((osInput.at(0) != '"' || osInput.back() != '"') &&
     788           2 :          (osInput.at(0) != '\'' || osInput.back() != '\'')))
     789           2 :         return;
     790             : 
     791           0 :     char *pszWrk = CPLStrdup(osInput.c_str() + 1);
     792             : 
     793           0 :     pszWrk[strlen(pszWrk) - 1] = '\0';
     794             : 
     795           0 :     for (int i = 0; pszWrk[i] != '\0'; i++)
     796             :     {
     797           0 :         if (pszWrk[i] == ' ')
     798           0 :             pszWrk[i] = '_';
     799             :     }
     800             : 
     801           0 :     osInput = pszWrk;
     802           0 :     CPLFree(pszWrk);
     803             : }
     804             : 
     805             : /************************************************************************/
     806             : /*                         GDALRegister_ISIS2()                         */
     807             : /************************************************************************/
     808             : 
     809        1667 : void GDALRegister_ISIS2()
     810             : 
     811             : {
     812        1667 :     if (GDALGetDriverByName(ISIS2_DRIVER_NAME) != nullptr)
     813         282 :         return;
     814             : 
     815        1385 :     GDALDriver *poDriver = new GDALDriver();
     816        1385 :     ISIS2DriverSetCommonMetadata(poDriver);
     817             : 
     818        1385 :     poDriver->pfnOpen = ISIS2Dataset::Open;
     819             : 
     820        1385 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     821             : }

Generated by: LCOV version 1.14