LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/s57 - ogrs57driver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 61 69 88.4 %
Date: 2024-11-25 13:07:18 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  S-57 Translator
       4             :  * Purpose:  Implements OGRS57Driver
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, Frank Warmerdam
       9             :  * Copyright (c) 2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "ogr_s57.h"
      15             : #include "cpl_conv.h"
      16             : #include "cpl_multiproc.h"
      17             : 
      18             : S57ClassRegistrar *OGRS57Driver::poRegistrar = nullptr;
      19             : static CPLMutex *hS57RegistrarMutex = nullptr;
      20             : 
      21             : /************************************************************************/
      22             : /*                            OGRS57Driver()                            */
      23             : /************************************************************************/
      24             : 
      25        1293 : OGRS57Driver::OGRS57Driver()
      26             : {
      27        1293 : }
      28             : 
      29             : /************************************************************************/
      30             : /*                           ~OGRS57Driver()                            */
      31             : /************************************************************************/
      32             : 
      33        1866 : OGRS57Driver::~OGRS57Driver()
      34             : 
      35             : {
      36         933 :     if (poRegistrar != nullptr)
      37             :     {
      38           2 :         delete poRegistrar;
      39           2 :         poRegistrar = nullptr;
      40             :     }
      41             : 
      42         933 :     if (hS57RegistrarMutex != nullptr)
      43             :     {
      44           2 :         CPLDestroyMutex(hS57RegistrarMutex);
      45           2 :         hS57RegistrarMutex = nullptr;
      46             :     }
      47        1866 : }
      48             : 
      49             : /************************************************************************/
      50             : /*                          OGRS57DriverIdentify()                      */
      51             : /************************************************************************/
      52             : 
      53       49333 : static int OGRS57DriverIdentify(GDALOpenInfo *poOpenInfo)
      54             : 
      55             : {
      56       49333 :     if (poOpenInfo->nHeaderBytes < 10)
      57       43919 :         return false;
      58        5414 :     const char *pachLeader = reinterpret_cast<char *>(poOpenInfo->pabyHeader);
      59        5414 :     if ((pachLeader[5] != '1' && pachLeader[5] != '2' &&
      60        4872 :          pachLeader[5] != '3') ||
      61         616 :         pachLeader[6] != 'L' || (pachLeader[8] != '1' && pachLeader[8] != ' '))
      62             :     {
      63        5340 :         return false;
      64             :     }
      65             :     // Test for S-57 DSID field structure (to distinguish it from S-101)
      66         148 :     return strstr(pachLeader, "DSID") != nullptr &&
      67          74 :            (strstr(pachLeader,
      68             :                    "RCNM!RCID!EXPP!INTU!DSNM!EDTN!UPDN!UADT!ISDT!"
      69           4 :                    "STED!PRSP!PSDN!PRED!PROF!AGEN!COMT") != nullptr ||
      70             :             // Below is for autotest/ogr/data/s57/fake_s57.000 fake dataset that has a shortened structure
      71          78 :             strstr(pachLeader, "RCNM!RCID!EXPP!xxxx") != nullptr);
      72             : }
      73             : 
      74             : /************************************************************************/
      75             : /*                                Open()                                */
      76             : /************************************************************************/
      77             : 
      78          37 : GDALDataset *OGRS57Driver::Open(GDALOpenInfo *poOpenInfo)
      79             : 
      80             : {
      81          37 :     if (!OGRS57DriverIdentify(poOpenInfo))
      82           0 :         return nullptr;
      83             : 
      84          37 :     OGRS57DataSource *poDS = new OGRS57DataSource(poOpenInfo->papszOpenOptions);
      85          37 :     if (!poDS->Open(poOpenInfo->pszFilename))
      86             :     {
      87           0 :         delete poDS;
      88           0 :         poDS = nullptr;
      89             :     }
      90             : 
      91          37 :     if (poDS && poOpenInfo->eAccess == GA_Update)
      92             :     {
      93           0 :         delete poDS;
      94           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
      95             :                  "S57 Driver doesn't support update.");
      96           0 :         return nullptr;
      97             :     }
      98             : 
      99          37 :     return poDS;
     100             : }
     101             : 
     102             : /************************************************************************/
     103             : /*                              Create()                                */
     104             : /************************************************************************/
     105             : 
     106          19 : GDALDataset *OGRS57Driver::Create(const char *pszName, int /* nBands */,
     107             :                                   int /* nXSize */, int /* nYSize */,
     108             :                                   GDALDataType /* eDT */, char **papszOptions)
     109             : {
     110          19 :     OGRS57DataSource *poDS = new OGRS57DataSource();
     111             : 
     112          19 :     if (poDS->Create(pszName, papszOptions))
     113          18 :         return poDS;
     114             : 
     115           1 :     delete poDS;
     116           1 :     return nullptr;
     117             : }
     118             : 
     119             : /************************************************************************/
     120             : /*                          GetS57Registrar()                           */
     121             : /************************************************************************/
     122             : 
     123        5447 : S57ClassRegistrar *OGRS57Driver::GetS57Registrar()
     124             : 
     125             : {
     126             :     /* -------------------------------------------------------------------- */
     127             :     /*      Instantiate the class registrar if possible.                    */
     128             :     /* -------------------------------------------------------------------- */
     129        5447 :     CPLMutexHolderD(&hS57RegistrarMutex);
     130             : 
     131        5447 :     if (poRegistrar == nullptr)
     132             :     {
     133           3 :         poRegistrar = new S57ClassRegistrar();
     134             : 
     135           3 :         if (!poRegistrar->LoadInfo(nullptr, nullptr, false))
     136             :         {
     137           0 :             delete poRegistrar;
     138           0 :             poRegistrar = nullptr;
     139             :         }
     140             :     }
     141             : 
     142       10894 :     return poRegistrar;
     143             : }
     144             : 
     145             : /************************************************************************/
     146             : /*                           RegisterOGRS57()                           */
     147             : /************************************************************************/
     148             : 
     149        1595 : void RegisterOGRS57()
     150             : 
     151             : {
     152        1595 :     if (GDALGetDriverByName("S57") != nullptr)
     153         302 :         return;
     154             : 
     155        1293 :     GDALDriver *poDriver = new OGRS57Driver();
     156             : 
     157        1293 :     poDriver->SetDescription("S57");
     158        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
     159        1293 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "IHO S-57 (ENC)");
     160        1293 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "000");
     161        1293 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/s57.html");
     162        1293 :     poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
     163             : 
     164        1293 :     poDriver->SetMetadataItem(
     165             :         GDAL_DMD_OPENOPTIONLIST,
     166             :         "<OpenOptionList>"
     167             :         "  <Option name='" S57O_UPDATES
     168             :         "' type='string-select' description='Should update files be "
     169             :         "incorporated into the base data on the fly' default='APPLY'>"
     170             :         "    <Value>APPLY</Value>"
     171             :         "    <Value>IGNORE</Value>"
     172             :         "  </Option>"
     173             :         "  <Option name='" S57O_SPLIT_MULTIPOINT
     174             :         "' type='boolean' description='Should multipoint soundings be split "
     175             :         "into many single point sounding features' default='NO'/>"
     176             :         "  <Option name='" S57O_ADD_SOUNDG_DEPTH
     177             :         "' type='boolean' description='Should a DEPTH attribute be added on "
     178             :         "SOUNDG features and assign the depth of the sounding' default='NO'/>"
     179             :         "  <Option name='" S57O_RETURN_PRIMITIVES
     180             :         "' type='boolean' description='Should all the low level geometry "
     181             :         "primitives be returned as special IsolatedNode, ConnectedNode, Edge "
     182             :         "and Face layers' default='NO'/>"
     183             :         "  <Option name='" S57O_PRESERVE_EMPTY_NUMBERS
     184             :         "' type='boolean' description='If enabled, numeric attributes assigned "
     185             :         "an empty string as a value will be preserved as a special numeric "
     186             :         "value' default='NO'/>"
     187             :         "  <Option name='" S57O_LNAM_REFS
     188             :         "' type='boolean' description='Should LNAM and LNAM_REFS fields be "
     189             :         "attached to features capturing the feature to feature relationships "
     190             :         "in the FFPT group of the S-57 file' default='NO'/>"
     191             :         "  <Option name='" S57O_RETURN_LINKAGES
     192             :         "' type='boolean' description='Should additional attributes relating "
     193             :         "features to their underlying geometric primitives be attached' "
     194             :         "default='NO'/>"
     195             :         "  <Option name='" S57O_RECODE_BY_DSSI
     196             :         "' type='boolean' description='Should attribute values be recoded to "
     197             :         "UTF-8 from the character encoding specified in the S57 DSSI record.' "
     198             :         "default='YES'/>"
     199             :         "  <Option name='" S57O_LIST_AS_STRING
     200             :         "' type='boolean' description='Whether attributes tagged as list in "
     201             :         "S57 dictionaries should be reported as a String field' default='NO'/>"
     202        1293 :         "</OpenOptionList>");
     203        1293 :     poDriver->SetMetadataItem(
     204             :         GDAL_DMD_CREATIONOPTIONLIST,
     205             :         "<CreationOptionList>"
     206             :         "   <Option name='S57_EXPP' type='int' description='Exchange purpose' "
     207             :         "default='1'/>"
     208             :         "   <Option name='S57_INTU' type='int' description='Intended usage' "
     209             :         "default='4'/>"
     210             :         "   <Option name='S57_EDTN' type='string' description='Edition number' "
     211             :         "default='2'/>"
     212             :         "   <Option name='S57_UPDN' type='string' description='Update number' "
     213             :         "default='0'/>"
     214             :         "   <Option name='S57_UADT' type='string' description='Update "
     215             :         "application date' default='20030801'/>"
     216             :         "   <Option name='S57_ISDT' type='string' description='Issue date' "
     217             :         "default='20030801'/>"
     218             :         "   <Option name='S57_STED' type='string' description='Edition number "
     219             :         "of S-57' default='03.1'/>"
     220             :         "   <Option name='S57_AGEN' type='int' description='Producing agency' "
     221             :         "default='540'/>"
     222             :         "   <Option name='S57_COMT' type='string' description='Comment' "
     223             :         "default=''/>"
     224             :         "   <Option name='S57_AALL' type='int' description='Lexical level used "
     225             :         "for the ATTF fields' default='0'/>"
     226             :         "   <Option name='S57_NALL' type='int' description='Lexical level used "
     227             :         "for the NATF fields' default='0'/>"
     228             :         "   <Option name='S57_NOMR' type='int' description='Number of meta "
     229             :         "records (objects with acronym starting with \"M_\")' default='0'/>"
     230             :         "   <Option name='S57_NOGR' type='int' description='Number of geo "
     231             :         "records' default='0'/>"
     232             :         "   <Option name='S57_NOLR' type='int' description='Number of "
     233             :         "collection records' default='0'/>"
     234             :         "   <Option name='S57_NOIN' type='int' description='Number of isolated "
     235             :         "node records' default='0'/>"
     236             :         "   <Option name='S57_NOCN' type='int' description='Number of "
     237             :         "connected node records' default='0'/>"
     238             :         "   <Option name='S57_NOED' type='int' description='Number of edge "
     239             :         "records' default='0'/>"
     240             :         "   <Option name='S57_HDAT' type='int' description='Horizontal "
     241             :         "geodetic datum' default='2'/>"
     242             :         "   <Option name='S57_VDAT' type='int' description='Vertical datum' "
     243             :         "default='17'/>"
     244             :         "   <Option name='S57_SDAT' type='int' description='Sounding datum' "
     245             :         "default='23'/>"
     246             :         "   <Option name='S57_CSCL' type='int' description='Compilation scale "
     247             :         "of data (1:X)' default='52000'/>"
     248             :         "   <Option name='S57_COMF' type='int' description='Floating-point to "
     249             :         "integer multiplication factor for coordinate values' "
     250             :         "default='10000000'/>"
     251             :         "   <Option name='S57_SOMF' type='int' description='Floating point to "
     252             :         "integer multiplication factor for 3-D (sounding) values' "
     253             :         "default='10'/>"
     254        1293 :         "</CreationOptionList>");
     255             : 
     256        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     257        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES");
     258        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
     259             : 
     260        1293 :     poDriver->pfnOpen = OGRS57Driver::Open;
     261        1293 :     poDriver->pfnIdentify = OGRS57DriverIdentify;
     262        1293 :     poDriver->pfnCreate = OGRS57Driver::Create;
     263             : 
     264        1293 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     265             : }

Generated by: LCOV version 1.14