LCOV - code coverage report
Current view: top level - frmts/pds - pdsdrivercore.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 188 191 98.4 %
Date: 2024-05-03 15:49:35 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Planetary drivers
       5             :  * Author:   Even Rouault
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2023, Even Rouault
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "pdsdrivercore.h"
      30             : 
      31             : #include "nasakeywordhandler.h"
      32             : 
      33             : /************************************************************************/
      34             : /*                     GetVICARLabelOffsetFromPDS3()                    */
      35             : /************************************************************************/
      36             : 
      37           3 : vsi_l_offset GetVICARLabelOffsetFromPDS3(const char *pszHdr, VSILFILE *fp,
      38             :                                          std::string &osVICARHeader)
      39             : {
      40           3 :     const char *pszPDSVersionID = strstr(pszHdr, "PDS_VERSION_ID");
      41           3 :     int nOffset = 0;
      42           3 :     if (pszPDSVersionID)
      43           3 :         nOffset = static_cast<int>(pszPDSVersionID - pszHdr);
      44             : 
      45           6 :     NASAKeywordHandler oKeywords;
      46           3 :     if (oKeywords.Ingest(fp, nOffset))
      47             :     {
      48             :         const int nRecordBytes =
      49           3 :             atoi(oKeywords.GetKeyword("RECORD_BYTES", "0"));
      50             :         const int nImageHeader =
      51           3 :             atoi(oKeywords.GetKeyword("^IMAGE_HEADER", "0"));
      52           3 :         if (nRecordBytes > 0 && nImageHeader > 0)
      53             :         {
      54           3 :             const auto nImgHeaderOffset =
      55           3 :                 static_cast<vsi_l_offset>(nImageHeader - 1) * nRecordBytes;
      56           3 :             osVICARHeader.resize(1024);
      57             :             size_t nMemb;
      58           3 :             if (VSIFSeekL(fp, nImgHeaderOffset, SEEK_SET) == 0 &&
      59           3 :                 (nMemb = VSIFReadL(&osVICARHeader[0], 1, osVICARHeader.size(),
      60           6 :                                    fp)) != 0 &&
      61           3 :                 osVICARHeader.find("LBLSIZE") != std::string::npos)
      62             :             {
      63           3 :                 osVICARHeader.resize(nMemb);
      64           3 :                 return nImgHeaderOffset;
      65             :             }
      66             :         }
      67             :     }
      68           0 :     return 0;
      69             : }
      70             : 
      71             : /************************************************************************/
      72             : /*                     PDSDriverIdentify()                              */
      73             : /************************************************************************/
      74             : 
      75       51397 : int PDSDriverIdentify(GDALOpenInfo *poOpenInfo)
      76             : 
      77             : {
      78       51397 :     if (poOpenInfo->pabyHeader == nullptr || poOpenInfo->fpL == nullptr)
      79       46089 :         return FALSE;
      80             : 
      81        5308 :     const char *pszHdr = reinterpret_cast<char *>(poOpenInfo->pabyHeader);
      82        5308 :     if (strstr(pszHdr, "PDS_VERSION_ID") == nullptr &&
      83        5231 :         strstr(pszHdr, "ODL_VERSION_ID") == nullptr)
      84             :     {
      85        5231 :         return FALSE;
      86             :     }
      87             : 
      88             :     // Some PDS3 images include a VICAR header pointed by ^IMAGE_HEADER.
      89             :     // If the user sets GDAL_TRY_PDS3_WITH_VICAR=YES, then we will gracefully
      90             :     // hand over the file to the VICAR dataset.
      91         154 :     std::string unused;
      92          77 :     if (CPLTestBool(CPLGetConfigOption("GDAL_TRY_PDS3_WITH_VICAR", "NO")) &&
      93          78 :         !STARTS_WITH(poOpenInfo->pszFilename, "/vsisubfile/") &&
      94           1 :         GetVICARLabelOffsetFromPDS3(pszHdr, poOpenInfo->fpL, unused) > 0)
      95             :     {
      96           1 :         CPLDebug("PDS3", "File is detected to have a VICAR header. "
      97             :                          "Handing it over to the VICAR driver");
      98           1 :         return FALSE;
      99             :     }
     100             : 
     101          76 :     return TRUE;
     102             : }
     103             : 
     104             : /************************************************************************/
     105             : /*                      PDSDriverSetCommonMetadata()                    */
     106             : /************************************************************************/
     107             : 
     108        1216 : void PDSDriverSetCommonMetadata(GDALDriver *poDriver)
     109             : {
     110        1216 :     poDriver->SetDescription(PDS_DRIVER_NAME);
     111        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     112        1216 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "NASA Planetary Data System");
     113        1216 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/pds.html");
     114        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     115             : 
     116        1216 :     poDriver->pfnIdentify = PDSDriverIdentify;
     117        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     118        1216 : }
     119             : 
     120             : /************************************************************************/
     121             : /*                         PDS4DriverIdentify()                         */
     122             : /************************************************************************/
     123             : 
     124       60796 : int PDS4DriverIdentify(GDALOpenInfo *poOpenInfo)
     125             : {
     126       60796 :     if (STARTS_WITH_CI(poOpenInfo->pszFilename, "PDS4:"))
     127          30 :         return TRUE;
     128       60766 :     if (poOpenInfo->nHeaderBytes == 0)
     129       48225 :         return FALSE;
     130             : 
     131       12542 :     const auto HasProductSomethingRootElement = [](const char *pszStr)
     132             :     {
     133       24640 :         return strstr(pszStr, "Product_Observational") != nullptr ||
     134       24640 :                strstr(pszStr, "Product_Ancillary") != nullptr ||
     135       24640 :                strstr(pszStr, "Product_Collection") != nullptr;
     136             :     };
     137       12542 :     const auto HasPDS4Schema = [](const char *pszStr)
     138       12542 :     { return strstr(pszStr, "://pds.nasa.gov/pds4/pds/v1") != nullptr; };
     139             : 
     140       12541 :     for (int i = 0; i < 2; ++i)
     141             :     {
     142       12542 :         const char *pszHeader =
     143             :             reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
     144       12542 :         int nMatches = 0;
     145       12542 :         if (HasProductSomethingRootElement(pszHeader))
     146         446 :             nMatches++;
     147       12542 :         if (HasPDS4Schema(pszHeader))
     148         446 :             nMatches++;
     149       12542 :         if (nMatches == 2)
     150             :         {
     151         446 :             return TRUE;
     152             :         }
     153       12096 :         if (i == 0)
     154             :         {
     155       12096 :             if (nMatches == 0 || poOpenInfo->nHeaderBytes >= 8192)
     156             :                 break;
     157             :             // If we have found one of the 2 matching elements to identify
     158             :             // PDS4 products, but have only ingested the default 1024 bytes,
     159             :             // then try to ingest more.
     160           0 :             poOpenInfo->TryToIngest(8192);
     161             :         }
     162             :     }
     163       12095 :     return FALSE;
     164             : }
     165             : 
     166             : /************************************************************************/
     167             : /*                      PDS4DriverSetCommonMetadata()                   */
     168             : /************************************************************************/
     169             : 
     170        1216 : void PDS4DriverSetCommonMetadata(GDALDriver *poDriver)
     171             : {
     172        1216 :     poDriver->SetDescription(PDS4_DRIVER_NAME);
     173        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
     174        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     175        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
     176        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
     177        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES");
     178        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_REORDER_FIELDS, "YES");
     179        1216 :     poDriver->SetMetadataItem(GDAL_DMD_ALTER_FIELD_DEFN_FLAGS,
     180        1216 :                               "Name Type WidthPrecision");
     181        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
     182             : 
     183        1216 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     184        1216 :                               "NASA Planetary Data System 4");
     185        1216 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/pds4.html");
     186        1216 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "xml");
     187        1216 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
     188             :                               "Byte Int8 UInt16 Int16 UInt32 Int32 Float32 "
     189        1216 :                               "Float64 CFloat32 CFloat64");
     190        1216 :     poDriver->SetMetadataItem(GDAL_DMD_OPENOPTIONLIST, "<OpenOptionList/>");
     191        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     192        1216 :     poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
     193        1216 :     poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
     194             : 
     195        1216 :     poDriver->SetMetadataItem(
     196             :         GDAL_DMD_OPENOPTIONLIST,
     197             :         "<OpenOptionList>"
     198             :         "  <Option name='LAT' type='string' scope='vector' description="
     199             :         "'Name of a field containing a Latitude value' default='Latitude'/>"
     200             :         "  <Option name='LONG' type='string' scope='vector' description="
     201             :         "'Name of a field containing a Longitude value' default='Longitude'/>"
     202             :         "  <Option name='ALT' type='string' scope='vector' description="
     203             :         "'Name of a field containing a Altitude value' default='Altitude'/>"
     204             :         "  <Option name='WKT' type='string' scope='vector' description="
     205             :         "'Name of a field containing a geometry encoded in the WKT format' "
     206             :         "default='WKT'/>"
     207             :         "  <Option name='KEEP_GEOM_COLUMNS' scope='vector' type='boolean' "
     208             :         "description="
     209             :         "'whether to add original x/y/geometry columns as regular fields.' "
     210             :         "default='NO' />"
     211        1216 :         "</OpenOptionList>");
     212             : 
     213        1216 :     poDriver->SetMetadataItem(
     214             :         GDAL_DMD_CREATIONOPTIONLIST,
     215             :         "<CreationOptionList>"
     216             :         "  <Option name='IMAGE_FILENAME' type='string' scope='raster' "
     217             :         "description="
     218             :         "'Image filename'/>"
     219             :         "  <Option name='IMAGE_EXTENSION' type='string' scope='raster' "
     220             :         "description="
     221             :         "'Extension of the binary raw/geotiff file'/>"
     222             :         "  <Option name='CREATE_LABEL_ONLY' scope='raster' type='boolean' "
     223             :         "description="
     224             :         "'whether to create only the XML label when converting from an "
     225             :         "existing raw format.' default='NO' />"
     226             :         "  <Option name='IMAGE_FORMAT' type='string-select' scope='raster' "
     227             :         "description='Format of the image file' default='RAW'>"
     228             :         "     <Value>RAW</Value>"
     229             :         "     <Value>GEOTIFF</Value>"
     230             :         "  </Option>"
     231             : #ifdef notdef
     232             :         "  <Option name='GEOTIFF_OPTIONS' type='string' scope='raster' "
     233             :         "description='Comma separated list of KEY=VALUE tuples to forward "
     234             :         "to the GeoTIFF driver'/>"
     235             : #endif
     236             :         "  <Option name='INTERLEAVE' type='string-select' scope='raster' "
     237             :         "description="
     238             :         "'Pixel organization' default='BSQ'>"
     239             :         "     <Value>BSQ</Value>"
     240             :         "     <Value>BIP</Value>"
     241             :         "     <Value>BIL</Value>"
     242             :         "  </Option>"
     243             :         "  <Option name='VAR_*' type='string' scope='raster,vector' "
     244             :         "description="
     245             :         "'Value to substitute to a variable in the template'/>"
     246             :         "  <Option name='TEMPLATE' type='string' scope='raster,vector' "
     247             :         "description="
     248             :         "'.xml template to use'/>"
     249             :         "  <Option name='USE_SRC_LABEL' type='boolean' scope='raster' "
     250             :         "description='Whether to use source label in PDS4 to PDS4 conversions' "
     251             :         "default='YES'/>"
     252             :         "  <Option name='LATITUDE_TYPE' type='string-select' "
     253             :         "scope='raster,vector' "
     254             :         "description='Value of latitude_type' default='Planetocentric'>"
     255             :         "     <Value>Planetocentric</Value>"
     256             :         "     <Value>Planetographic</Value>"
     257             :         "  </Option>"
     258             :         "  <Option name='LONGITUDE_DIRECTION' type='string-select' "
     259             :         "scope='raster,vector' "
     260             :         "description='Value of longitude_direction' "
     261             :         "default='Positive East'>"
     262             :         "     <Value>Positive East</Value>"
     263             :         "     <Value>Positive West</Value>"
     264             :         "  </Option>"
     265             :         "  <Option name='RADII' type='string' scope='raster,vector' "
     266             :         "description='Value of form "
     267             :         "semi_major_radius,semi_minor_radius to override the ones of the SRS'/>"
     268             :         "  <Option name='ARRAY_TYPE' type='string-select' scope='raster' "
     269             :         "description='Name of the "
     270             :         "Array XML element' default='Array_3D_Image'>"
     271             :         "     <Value>Array</Value>"
     272             :         "     <Value>Array_2D</Value>"
     273             :         "     <Value>Array_2D_Image</Value>"
     274             :         "     <Value>Array_2D_Map</Value>"
     275             :         "     <Value>Array_2D_Spectrum</Value>"
     276             :         "     <Value>Array_3D</Value>"
     277             :         "     <Value>Array_3D_Image</Value>"
     278             :         "     <Value>Array_3D_Movie</Value>"
     279             :         "     <Value>Array_3D_Spectrum</Value>"
     280             :         "  </Option>"
     281             :         "  <Option name='ARRAY_IDENTIFIER' type='string' scope='raster' "
     282             :         "description='Identifier to put in the Array element'/>"
     283             :         "  <Option name='UNIT' type='string' scope='raster' "
     284             :         "description='Name of the unit of the array elements'/>"
     285             :         "  <Option name='BOUNDING_DEGREES' type='string' scope='raster,vector' "
     286             :         "description='Manually set bounding box with the syntax "
     287             :         "west_lon,south_lat,east_lon,north_lat'/>"
     288        1216 :         "</CreationOptionList>");
     289             : 
     290        1216 :     poDriver->SetMetadataItem(
     291             :         GDAL_DS_LAYER_CREATIONOPTIONLIST,
     292             :         "<LayerCreationOptionList>"
     293             :         "  <Option name='TABLE_TYPE' type='string-select' description='Type of "
     294             :         "table' default='DELIMITED'>"
     295             :         "     <Value>DELIMITED</Value>"
     296             :         "     <Value>CHARACTER</Value>"
     297             :         "     <Value>BINARY</Value>"
     298             :         "  </Option>"
     299             :         "  <Option name='LINE_ENDING' type='string-select' description="
     300             :         "'end-of-line sequence. Only applies for "
     301             :         "TABLE_TYPE=DELIMITED/CHARACTER' "
     302             :         "default='CRLF'>"
     303             :         "    <Value>CRLF</Value>"
     304             :         "    <Value>LF</Value>"
     305             :         "  </Option>"
     306             :         "  <Option name='GEOM_COLUMNS' type='string-select' description='How "
     307             :         "geometry is encoded' default='AUTO'>"
     308             :         "     <Value>AUTO</Value>"
     309             :         "     <Value>WKT</Value>"
     310             :         "     <Value>LONG_LAT</Value>"
     311             :         "  </Option>"
     312             :         "  <Option name='CREATE_VRT' type='boolean' description='Whether to "
     313             :         "generate "
     314             :         "a OGR VRT file. Only applies for TABLE_TYPE=DELIMITED' default='YES'/>"
     315             :         "  <Option name='LAT' type='string' description="
     316             :         "'Name of a field containing a Latitude value' default='Latitude'/>"
     317             :         "  <Option name='LONG' type='string' description="
     318             :         "'Name of a field containing a Longitude value' default='Longitude'/>"
     319             :         "  <Option name='ALT' type='string' description="
     320             :         "'Name of a field containing a Altitude value' default='Altitude'/>"
     321             :         "  <Option name='WKT' type='string' description="
     322             :         "'Name of a field containing a WKT value' default='WKT'/>"
     323             :         "  <Option name='SAME_DIRECTORY' type='boolean' description="
     324             :         "'Whether table files should be created in the same "
     325             :         "directory, or in a subdirectory' default='NO'/>"
     326        1216 :         "</LayerCreationOptionList>");
     327             : 
     328        1216 :     poDriver->SetMetadataItem(
     329             :         GDAL_DMD_CREATIONFIELDDATATYPES,
     330        1216 :         "Integer Integer64 Real String Date DateTime Time");
     331        1216 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, "Boolean");
     332             : 
     333        1216 :     poDriver->pfnIdentify = PDS4DriverIdentify;
     334        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     335        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
     336        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
     337        1216 : }
     338             : 
     339             : /************************************************************************/
     340             : /*                         ISIS2DriverIdentify()                        */
     341             : /************************************************************************/
     342             : 
     343       51489 : int ISIS2DriverIdentify(GDALOpenInfo *poOpenInfo)
     344             : {
     345       51489 :     if (poOpenInfo->pabyHeader == nullptr)
     346       46067 :         return FALSE;
     347             : 
     348        5422 :     if (strstr((const char *)poOpenInfo->pabyHeader, "^QUBE") == nullptr)
     349        5332 :         return FALSE;
     350             : 
     351          90 :     return TRUE;
     352             : }
     353             : 
     354             : /************************************************************************/
     355             : /*                      ISIS2DriverSetCommonMetadata()                  */
     356             : /************************************************************************/
     357             : 
     358        1216 : void ISIS2DriverSetCommonMetadata(GDALDriver *poDriver)
     359             : {
     360        1216 :     poDriver->SetDescription(ISIS2_DRIVER_NAME);
     361        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     362        1216 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     363        1216 :                               "USGS Astrogeology ISIS cube (Version 2)");
     364        1216 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/isis2.html");
     365        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     366        1216 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
     367        1216 :                               "Byte Int16 UInt16 Float32 Float64");
     368             : 
     369        1216 :     poDriver->SetMetadataItem(
     370             :         GDAL_DMD_CREATIONOPTIONLIST,
     371             :         "<CreationOptionList>\n"
     372             :         "   <Option name='LABELING_METHOD' type='string-select' "
     373             :         "default='ATTACHED'>\n"
     374             :         "     <Value>ATTACHED</Value>"
     375             :         "     <Value>DETACHED</Value>"
     376             :         "   </Option>"
     377             :         "   <Option name='IMAGE_EXTENSION' type='string' default='cub'/>\n"
     378        1216 :         "</CreationOptionList>\n");
     379             : 
     380        1216 :     poDriver->pfnIdentify = ISIS2DriverIdentify;
     381        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     382        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
     383        1216 : }
     384             : 
     385             : /************************************************************************/
     386             : /*                         ISIS3DriverIdentify()                        */
     387             : /************************************************************************/
     388             : 
     389       52015 : int ISIS3DriverIdentify(GDALOpenInfo *poOpenInfo)
     390             : {
     391       52015 :     if (poOpenInfo->fpL != nullptr && poOpenInfo->pabyHeader != nullptr &&
     392        5854 :         strstr((const char *)poOpenInfo->pabyHeader, "IsisCube") != nullptr)
     393         531 :         return TRUE;
     394             : 
     395       51484 :     return FALSE;
     396             : }
     397             : 
     398             : /************************************************************************/
     399             : /*                      ISIS3DriverSetCommonMetadata()                  */
     400             : /************************************************************************/
     401             : 
     402        1216 : void ISIS3DriverSetCommonMetadata(GDALDriver *poDriver)
     403             : {
     404        1216 :     poDriver->SetDescription(ISIS3_DRIVER_NAME);
     405        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     406        1216 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     407        1216 :                               "USGS Astrogeology ISIS cube (Version 3)");
     408        1216 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/isis3.html");
     409        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     410        1216 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "lbl cub");
     411        1216 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
     412        1216 :                               "Byte UInt16 Int16 Float32");
     413        1216 :     poDriver->SetMetadataItem(GDAL_DMD_OPENOPTIONLIST, "<OpenOptionList/>");
     414        1216 :     poDriver->SetMetadataItem(
     415             :         GDAL_DMD_CREATIONOPTIONLIST,
     416             :         "<CreationOptionList>"
     417             :         "  <Option name='DATA_LOCATION' type='string-select' "
     418             :         "description='Location of pixel data' default='LABEL'>"
     419             :         "     <Value>LABEL</Value>"
     420             :         "     <Value>EXTERNAL</Value>"
     421             :         "     <Value>GEOTIFF</Value>"
     422             :         "  </Option>"
     423             :         "  <Option name='GEOTIFF_AS_REGULAR_EXTERNAL' type='boolean' "
     424             :         "description='Whether the GeoTIFF file, if uncompressed, should be "
     425             :         "registered as a regular raw file' default='YES'/>"
     426             :         "  <Option name='GEOTIFF_OPTIONS' type='string' "
     427             :         "description='Comma separated list of KEY=VALUE tuples to forward "
     428             :         "to the GeoTIFF driver'/>"
     429             :         "  <Option name='EXTERNAL_FILENAME' type='string' "
     430             :         "description='Override default external filename. "
     431             :         "Only for DATA_LOCATION=EXTERNAL or GEOTIFF'/>"
     432             :         "  <Option name='TILED' type='boolean' "
     433             :         "description='Whether the pixel data should be tiled' default='NO'/>"
     434             :         "  <Option name='BLOCKXSIZE' type='int' "
     435             :         "description='Tile width' default='256'/>"
     436             :         "  <Option name='BLOCKYSIZE' type='int' "
     437             :         "description='Tile height' default='256'/>"
     438             :         "  <Option name='COMMENT' type='string' "
     439             :         "description='Comment to add into the label'/>"
     440             :         "  <Option name='LATITUDE_TYPE' type='string-select' "
     441             :         "description='Value of Mapping.LatitudeType' default='Planetocentric'>"
     442             :         "     <Value>Planetocentric</Value>"
     443             :         "     <Value>Planetographic</Value>"
     444             :         "  </Option>"
     445             :         "  <Option name='LONGITUDE_DIRECTION' type='string-select' "
     446             :         "description='Value of Mapping.LongitudeDirection' "
     447             :         "default='PositiveEast'>"
     448             :         "     <Value>PositiveEast</Value>"
     449             :         "     <Value>PositiveWest</Value>"
     450             :         "  </Option>"
     451             :         "  <Option name='TARGET_NAME' type='string' description='Value of "
     452             :         "Mapping.TargetName'/>"
     453             :         "  <Option name='FORCE_360' type='boolean' "
     454             :         "description='Whether to force longitudes in [0,360] range' "
     455             :         "default='NO'/>"
     456             :         "  <Option name='WRITE_BOUNDING_DEGREES' type='boolean' "
     457             :         "description='Whether to write Min/MaximumLong/Latitude values' "
     458             :         "default='YES'/>"
     459             :         "  <Option name='BOUNDING_DEGREES' type='string' "
     460             :         "description='Manually set bounding box with the syntax "
     461             :         "min_long,min_lat,max_long,max_lat'/>"
     462             :         "  <Option name='USE_SRC_LABEL' type='boolean' "
     463             :         "description='Whether to use source label in ISIS3 to ISIS3 "
     464             :         "conversions' "
     465             :         "default='YES'/>"
     466             :         "  <Option name='USE_SRC_MAPPING' type='boolean' "
     467             :         "description='Whether to use Mapping group from source label in "
     468             :         "ISIS3 to ISIS3 conversions' "
     469             :         "default='NO'/>"
     470             :         "  <Option name='USE_SRC_HISTORY' type='boolean' "
     471             :         "description='Whether to use content pointed by the History object in "
     472             :         "ISIS3 to ISIS3 conversions' "
     473             :         "default='YES'/>"
     474             :         "  <Option name='ADD_GDAL_HISTORY' type='boolean' "
     475             :         "description='Whether to add GDAL specific history in the content "
     476             :         "pointed "
     477             :         "by the History object in "
     478             :         "ISIS3 to ISIS3 conversions' "
     479             :         "default='YES'/>"
     480             :         "  <Option name='GDAL_HISTORY' type='string' "
     481             :         "description='Manually defined GDAL history. Must be formatted as "
     482             :         "ISIS3 "
     483             :         "PDL. If not specified, it is automatically composed.'/>"
     484        1216 :         "</CreationOptionList>");
     485             : 
     486        1216 :     poDriver->pfnIdentify = ISIS3DriverIdentify;
     487        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     488        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
     489        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
     490        1216 : }
     491             : 
     492             : /************************************************************************/
     493             : /*                     VICARGetLabelOffset()                            */
     494             : /************************************************************************/
     495             : 
     496       60432 : int VICARGetLabelOffset(GDALOpenInfo *poOpenInfo)
     497             : 
     498             : {
     499       60432 :     if (poOpenInfo->pabyHeader == nullptr || poOpenInfo->fpL == nullptr)
     500       48208 :         return -1;
     501             : 
     502       24448 :     std::string osHeader;
     503       12224 :     const char *pszHeader =
     504             :         reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
     505             :     // Some PDS3 images include a VICAR header pointed by ^IMAGE_HEADER.
     506             :     // If the user sets GDAL_TRY_PDS3_WITH_VICAR=YES, then we will gracefully
     507             :     // hand over the file to the VICAR dataset.
     508       12224 :     vsi_l_offset nOffset = 0;
     509       12224 :     if (CPLTestBool(CPLGetConfigOption("GDAL_TRY_PDS3_WITH_VICAR", "NO")) &&
     510       12226 :         !STARTS_WITH(poOpenInfo->pszFilename, "/vsisubfile/") &&
     511           2 :         (nOffset = GetVICARLabelOffsetFromPDS3(pszHeader, poOpenInfo->fpL,
     512             :                                                osHeader)) > 0)
     513             :     {
     514           2 :         pszHeader = osHeader.c_str();
     515             :     }
     516             : 
     517       12224 :     if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
     518        7383 :         (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0)
     519             :     {
     520             :         // If opening in vector-only mode, then check when have NBB != 0
     521        6966 :         const char *pszNBB = strstr(pszHeader, "NBB");
     522        6966 :         if (pszNBB == nullptr)
     523        6963 :             return -1;
     524           3 :         const char *pszEqualSign = strchr(pszNBB, '=');
     525           3 :         if (pszEqualSign == nullptr)
     526           0 :             return -1;
     527           3 :         if (atoi(pszEqualSign + 1) == 0)
     528           1 :             return -1;
     529             :     }
     530        5260 :     if (strstr(pszHeader, "LBLSIZE") != nullptr &&
     531         225 :         strstr(pszHeader, "FORMAT") != nullptr &&
     532         225 :         strstr(pszHeader, "NL") != nullptr &&
     533         225 :         strstr(pszHeader, "NS") != nullptr &&
     534         225 :         strstr(pszHeader, "NB") != nullptr)
     535             :     {
     536         225 :         return static_cast<int>(nOffset);
     537             :     }
     538        5035 :     return -1;
     539             : }
     540             : 
     541             : /************************************************************************/
     542             : /*                         VICARDriverIdentify()                        */
     543             : /************************************************************************/
     544             : 
     545       60320 : static int VICARDriverIdentify(GDALOpenInfo *poOpenInfo)
     546             : {
     547       60320 :     return VICARGetLabelOffset(poOpenInfo) >= 0;
     548             : }
     549             : 
     550             : /************************************************************************/
     551             : /*                      VICARDriverSetCommonMetadata()                  */
     552             : /************************************************************************/
     553             : 
     554        1216 : void VICARDriverSetCommonMetadata(GDALDriver *poDriver)
     555             : {
     556        1216 :     poDriver->SetDescription(VICAR_DRIVER_NAME);
     557        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     558        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
     559        1216 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "MIPL VICAR file");
     560        1216 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/vicar.html");
     561        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     562        1216 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
     563        1216 :                               "Byte Int16 Int32 Float32 Float64 CFloat32");
     564        1216 :     poDriver->SetMetadataItem(
     565             :         GDAL_DMD_CREATIONOPTIONLIST,
     566             :         "<CreationOptionList>"
     567             :         "  <Option name='GEOREF_FORMAT' type='string-select' "
     568             :         "description='How to encode georeferencing information' "
     569             :         "default='MIPL'>"
     570             :         "     <Value>MIPL</Value>"
     571             :         "     <Value>GEOTIFF</Value>"
     572             :         "  </Option>"
     573             :         "  <Option name='COORDINATE_SYSTEM_NAME' type='string-select' "
     574             :         "description='Value of MAP.COORDINATE_SYSTEM_NAME' "
     575             :         "default='PLANETOCENTRIC'>"
     576             :         "     <Value>PLANETOCENTRIC</Value>"
     577             :         "     <Value>PLANETOGRAPHIC</Value>"
     578             :         "  </Option>"
     579             :         "  <Option name='POSITIVE_LONGITUDE_DIRECTION' type='string-select' "
     580             :         "description='Value of MAP.POSITIVE_LONGITUDE_DIRECTION' "
     581             :         "default='EAST'>"
     582             :         "     <Value>EAST</Value>"
     583             :         "     <Value>WEST</Value>"
     584             :         "  </Option>"
     585             :         "  <Option name='TARGET_NAME' type='string' description='Value of "
     586             :         "MAP.TARGET_NAME'/>"
     587             :         "  <Option name='USE_SRC_LABEL' type='boolean' "
     588             :         "description='Whether to use source label in VICAR to VICAR "
     589             :         "conversions' "
     590             :         "default='YES'/>"
     591             :         "  <Option name='USE_SRC_MAP' type='boolean' "
     592             :         "description='Whether to use MAP property from source label in "
     593             :         "VICAR to VICAR conversions' "
     594             :         "default='NO'/>"
     595             :         "  <Option name='LABEL' type='string' "
     596             :         "description='Label to use, either as a JSON string or a filename "
     597             :         "containing one'/>"
     598             :         "  <Option name='COMPRESS' type='string-select' "
     599             :         "description='Compression method' default='NONE'>"
     600             :         "     <Value>NONE</Value>"
     601             :         "     <Value>BASIC</Value>"
     602             :         "     <Value>BASIC2</Value>"
     603             :         "  </Option>"
     604        1216 :         "</CreationOptionList>");
     605             : 
     606        1216 :     poDriver->pfnIdentify = VICARDriverIdentify;
     607        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     608        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
     609        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
     610        1216 : }
     611             : 
     612             : /************************************************************************/
     613             : /*                     DeclareDeferredPDSPlugin()                       */
     614             : /************************************************************************/
     615             : 
     616             : #ifdef PLUGIN_FILENAME
     617             : void DeclareDeferredPDSPlugin()
     618             : {
     619             :     if (GDALGetDriverByName(PDS_DRIVER_NAME) != nullptr)
     620             :     {
     621             :         return;
     622             :     }
     623             :     {
     624             :         auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     625             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     626             :         poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     627             :                                   PLUGIN_INSTALLATION_MESSAGE);
     628             : #endif
     629             :         PDSDriverSetCommonMetadata(poDriver);
     630             :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     631             :     }
     632             :     {
     633             :         auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     634             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     635             :         poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     636             :                                   PLUGIN_INSTALLATION_MESSAGE);
     637             : #endif
     638             :         PDS4DriverSetCommonMetadata(poDriver);
     639             :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     640             :     }
     641             :     {
     642             :         auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     643             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     644             :         poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     645             :                                   PLUGIN_INSTALLATION_MESSAGE);
     646             : #endif
     647             :         ISIS2DriverSetCommonMetadata(poDriver);
     648             :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     649             :     }
     650             :     {
     651             :         auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     652             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     653             :         poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     654             :                                   PLUGIN_INSTALLATION_MESSAGE);
     655             : #endif
     656             :         ISIS3DriverSetCommonMetadata(poDriver);
     657             :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     658             :     }
     659             :     {
     660             :         auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     661             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     662             :         poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     663             :                                   PLUGIN_INSTALLATION_MESSAGE);
     664             : #endif
     665             :         VICARDriverSetCommonMetadata(poDriver);
     666             :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     667             :     }
     668             : }
     669             : #endif

Generated by: LCOV version 1.14