LCOV - code coverage report
Current view: top level - frmts/netcdf - netcdfdrivercore.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 155 161 96.3 %
Date: 2024-11-21 22:18:42 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  netCDF driver
       5             :  * Author:   Even Rouault, <even.rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2023, Even Rouault, <even.rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "ogrsf_frmts.h"
      14             : #include "gdal_priv.h"
      15             : 
      16             : #include "netcdfdrivercore.h"
      17             : 
      18             : #include <algorithm>
      19             : #include <cctype>
      20             : #include <string_view>
      21             : 
      22             : #ifdef HAS_NETCDF_H
      23             : #include "netcdfdataset.h"
      24             : #ifdef NETCDF_HAS_NC2
      25             : #define NETCDF_CORE_HAS_NC2 1
      26             : #endif
      27             : #else
      28             : // We don't have an easy way to guess that without accessing netcdf.h, so
      29             : // assume it is present
      30             : #ifndef NETCDF_CORE_HAS_NC2
      31             : #define NETCDF_CORE_HAS_NC2 1
      32             : #endif
      33             : #endif
      34             : 
      35             : /************************************************************************/
      36             : /*                      netCDFIdentifyFormat()                          */
      37             : /************************************************************************/
      38             : 
      39       66908 : NetCDFFormatEnum netCDFIdentifyFormat(GDALOpenInfo *poOpenInfo, bool bCheckExt)
      40             : {
      41             :     // Does this appear to be a netcdf file? If so, which format?
      42             :     // http://www.unidata.ucar.edu/software/netcdf/docs/faq.html#fv1_5
      43             : 
      44       66908 :     if (STARTS_WITH_CI(poOpenInfo->pszFilename, "NETCDF:"))
      45           0 :         return NCDF_FORMAT_UNKNOWN;
      46       66908 :     if (poOpenInfo->nHeaderBytes < 4)
      47       52227 :         return NCDF_FORMAT_NONE;
      48       14681 :     const char *pszHeader =
      49             :         reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
      50             : 
      51             : #ifdef ENABLE_NCDUMP
      52       14681 :     if (poOpenInfo->fpL != nullptr && STARTS_WITH(pszHeader, "netcdf ") &&
      53           9 :         strstr(pszHeader, "dimensions:") && strstr(pszHeader, "variables:"))
      54             :     {
      55           9 :         if (strstr(pszHeader, "// NC4C"))
      56           0 :             return NCDF_FORMAT_NC4C;
      57           9 :         else if (strstr(pszHeader, "// NC4"))
      58           0 :             return NCDF_FORMAT_NC4;
      59             :         else
      60           9 :             return NCDF_FORMAT_NC;
      61             :     }
      62             : #endif  // ENABLE_NCDUMP
      63             : 
      64             : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
      65             :     // We don't necessarily want to catch bugs in libnetcdf ...
      66             :     if (CPLGetConfigOption("DISABLE_OPEN_REAL_NETCDF_FILES", nullptr))
      67             :     {
      68             :         return NCDF_FORMAT_NONE;
      69             :     }
      70             : #endif
      71             : 
      72       14672 :     if (STARTS_WITH_CI(pszHeader, "CDF\001"))
      73             :     {
      74         880 :         return NCDF_FORMAT_NC;
      75             :     }
      76             : 
      77       13792 :     if (STARTS_WITH_CI(pszHeader, "CDF\002"))
      78             :     {
      79          14 :         return NCDF_FORMAT_NC2;
      80             :     }
      81             : 
      82       13778 :     constexpr char HDF5_SIG[] = "\211HDF\r\n\032\n";
      83       13778 :     constexpr int HDF5_SIG_LEN = int(std::char_traits<char>::length(HDF5_SIG));
      84             :     static_assert(HDF5_SIG_LEN == 8);
      85             :     // First non-zero offset at which the HDF5 signature can be found.
      86       13778 :     constexpr int HDF5_SIG_OFFSET = 512;
      87       13778 :     if (STARTS_WITH_CI(pszHeader, HDF5_SIG) ||
      88       13021 :         (poOpenInfo->nHeaderBytes > HDF5_SIG_OFFSET + HDF5_SIG_LEN &&
      89        8294 :          memcmp(pszHeader + HDF5_SIG_OFFSET, HDF5_SIG, HDF5_SIG_LEN) == 0))
      90             :     {
      91             :         // Requires netCDF-4/HDF5 support in libnetcdf (not just libnetcdf-v4).
      92             : 
      93             :         // If only the netCDF driver is allowed, immediately recognize the file
      94         757 :         if (poOpenInfo->IsSingleAllowedDriver("netCDF"))
      95             :         {
      96          19 :             return NCDF_FORMAT_NC4;
      97             :         }
      98             : 
      99             :         // If there is a HDF5 GDAL driver available, delegate to it.
     100             :         // Otherwise open it with this driver.
     101             :         // If the user really wants to open with this driver, use NETCDF:file.h5
     102             :         // format.
     103             : 
     104             :         // Check for HDF5 driver availability.
     105         739 :         if (bCheckExt)
     106             :         {
     107             :             // Check by default.
     108         723 :             const char *pszExtension = CPLGetExtension(poOpenInfo->pszFilename);
     109         723 :             if (!(EQUAL(pszExtension, "nc") || EQUAL(pszExtension, "cdf") ||
     110         388 :                   EQUAL(pszExtension, "nc2") || EQUAL(pszExtension, "nc4") ||
     111         388 :                   EQUAL(pszExtension, "nc3") || EQUAL(pszExtension, "grd") ||
     112         388 :                   EQUAL(pszExtension, "gmac")))
     113             :             {
     114         286 :                 if (GDALGetDriverByName("HDF5") != nullptr)
     115             :                 {
     116         286 :                     return NCDF_FORMAT_HDF5;
     117             :                 }
     118             :             }
     119             :         }
     120             : 
     121         453 :         return NCDF_FORMAT_NC4;
     122             :     }
     123       13021 :     else if (STARTS_WITH_CI(pszHeader, "\016\003\023\001"))
     124             :     {
     125             : #ifdef NETCDF_HAS_HDF4
     126             :         // There is HDF4 support in libnetcdf and only the netCDF driver is
     127             :         // allowed ==> immediately recognize the file.
     128             :         if (poOpenInfo->IsSingleAllowedDriver("netCDF"))
     129             :         {
     130             :             return NCDF_FORMAT_HDF4;
     131             :         }
     132             : #endif
     133             : 
     134             :         // If there is a HDF4 GDAL driver available, delegate to it.
     135             :         // Otherwise open it with this driver.
     136             :         // If the user really wants to open with this driver, use NETCDF:file.hdf
     137             :         // format.
     138             : 
     139             :         // Check for HDF4 driver availability.
     140         313 :         if (bCheckExt && GDALGetDriverByName("HDF4") != nullptr)
     141             :         {
     142             :             // Check by default.
     143             :             // Always treat as HDF4 file.
     144         313 :             return NCDF_FORMAT_HDF4;
     145             :         }
     146             : 
     147             : #ifdef NETCDF_HAS_HDF4
     148             :         // There is HDF4 support in libnetcdf.
     149             :         return NCDF_FORMAT_HDF4;
     150             : #else
     151           0 :         return NCDF_FORMAT_NONE;
     152             : #endif
     153             :     }
     154             : 
     155             :     // The HDF5 signature of netCDF 4 files can be at offsets 512, 1024, 2048,
     156             :     // etc.
     157       12708 :     const char *pszExtension = CPLGetExtension(poOpenInfo->pszFilename);
     158       25320 :     if (poOpenInfo->fpL != nullptr &&
     159       12612 :         (!bCheckExt || EQUAL(pszExtension, "nc") ||
     160       12610 :          EQUAL(pszExtension, "cdf") || EQUAL(pszExtension, "nc4") ||
     161       12610 :          poOpenInfo->IsSingleAllowedDriver("netCDF")))
     162             :     {
     163           4 :         vsi_l_offset nOffset = HDF5_SIG_OFFSET;
     164           8 :         for (int i = 0; i < 64; i++)
     165             :         {
     166             :             GByte abyBuf[HDF5_SIG_LEN];
     167          16 :             if (VSIFSeekL(poOpenInfo->fpL, nOffset, SEEK_SET) != 0 ||
     168           8 :                 VSIFReadL(abyBuf, 1, HDF5_SIG_LEN, poOpenInfo->fpL) !=
     169             :                     HDF5_SIG_LEN)
     170             :             {
     171           2 :                 break;
     172             :             }
     173           6 :             if (memcmp(abyBuf, HDF5_SIG, HDF5_SIG_LEN) == 0)
     174             :             {
     175           2 :                 return NCDF_FORMAT_NC4;
     176             :             }
     177           4 :             nOffset *= 2;
     178             :         }
     179             :     }
     180             : 
     181       12706 :     return NCDF_FORMAT_NONE;
     182             : }
     183             : 
     184             : /************************************************************************/
     185             : /*                              Identify()                              */
     186             : /************************************************************************/
     187             : 
     188       66130 : static int netCDFDatasetIdentify(GDALOpenInfo *poOpenInfo)
     189             : 
     190             : {
     191       66130 :     if (STARTS_WITH_CI(poOpenInfo->pszFilename, "NETCDF:"))
     192             :     {
     193          58 :         return TRUE;
     194             :     }
     195             :     const NetCDFFormatEnum eTmpFormat =
     196       66072 :         netCDFIdentifyFormat(poOpenInfo,
     197             :                              /* bCheckExt = */ true);
     198       66077 :     if (NCDF_FORMAT_NC == eTmpFormat || NCDF_FORMAT_NC2 == eTmpFormat ||
     199       65523 :         NCDF_FORMAT_NC4 == eTmpFormat || NCDF_FORMAT_NC4C == eTmpFormat)
     200         555 :         return TRUE;
     201       65835 :     if (eTmpFormat == NCDF_FORMAT_HDF4 &&
     202         313 :         poOpenInfo->IsSingleAllowedDriver("netCDF"))
     203             :     {
     204           0 :         return TRUE;
     205             :     }
     206             : 
     207       65522 :     return FALSE;
     208             : }
     209             : 
     210             : /************************************************************************/
     211             : /*                    NCDFDriverGetSubdatasetInfo()                     */
     212             : /************************************************************************/
     213             : 
     214             : struct NCDFDriverSubdatasetInfo : public GDALSubdatasetInfo
     215             : {
     216             :   public:
     217          54 :     explicit NCDFDriverSubdatasetInfo(const std::string &fileName)
     218          54 :         : GDALSubdatasetInfo(fileName)
     219             :     {
     220          54 :     }
     221             : 
     222             :     // GDALSubdatasetInfo interface
     223             :   private:
     224          54 :     void parseFileName() override
     225             :     {
     226             : 
     227          54 :         if (!STARTS_WITH_CI(m_fileName.c_str(), "NETCDF:"))
     228             :         {
     229           0 :             return;
     230             :         }
     231             : 
     232         108 :         CPLStringList aosParts{CSLTokenizeString2(m_fileName.c_str(), ":", 0)};
     233          54 :         const int iPartsCount{CSLCount(aosParts)};
     234             : 
     235          54 :         if (iPartsCount >= 3)
     236             :         {
     237             : 
     238          52 :             m_driverPrefixComponent = aosParts[0];
     239             : 
     240          52 :             int subdatasetIndex{2};
     241             : 
     242         104 :             std::string part1{aosParts[1]};
     243          52 :             if (!part1.empty() && part1[0] == '"')
     244             :             {
     245          42 :                 part1 = part1.substr(1);
     246             :             }
     247             : 
     248             :             const bool hasDriveLetter{
     249          52 :                 (strlen(aosParts[2]) > 1 &&
     250          58 :                  (aosParts[2][0] == '\\' || aosParts[2][0] == '/')) &&
     251         110 :                 part1.length() == 1 &&
     252           7 :                 std::isalpha(static_cast<unsigned char>(part1.at(0)))};
     253             : 
     254         104 :             const bool hasProtocol{part1 == "/vsicurl/http" ||
     255         103 :                                    part1 == "/vsicurl/https" ||
     256         102 :                                    part1 == "/vsicurl_streaming/http" ||
     257         102 :                                    part1 == "/vsicurl_streaming/https" ||
     258         155 :                                    part1 == "http" || part1 == "https"};
     259             : 
     260          52 :             m_pathComponent = aosParts[1];
     261          52 :             if (hasDriveLetter || hasProtocol)
     262             :             {
     263           9 :                 m_pathComponent.append(":");
     264           9 :                 m_pathComponent.append(aosParts[2]);
     265           9 :                 subdatasetIndex++;
     266             :             }
     267             : 
     268             :             // Check for bogus paths
     269          52 :             if (subdatasetIndex < iPartsCount)
     270             :             {
     271          50 :                 m_subdatasetComponent = aosParts[subdatasetIndex];
     272             : 
     273             :                 // Append any remaining part
     274          51 :                 for (int i = subdatasetIndex + 1; i < iPartsCount; ++i)
     275             :                 {
     276           1 :                     m_subdatasetComponent.append(":");
     277           1 :                     m_subdatasetComponent.append(aosParts[i]);
     278             :                 }
     279             :             }
     280             : 
     281             :             // Remove quotes from subdataset component
     282         102 :             if (!m_subdatasetComponent.empty() &&
     283          50 :                 m_subdatasetComponent[0] == '"')
     284             :             {
     285           1 :                 m_subdatasetComponent = m_subdatasetComponent.substr(1);
     286             :             }
     287         102 :             if (!m_subdatasetComponent.empty() &&
     288          50 :                 m_subdatasetComponent.rfind('"') ==
     289          50 :                     m_subdatasetComponent.length() - 1)
     290             :             {
     291           2 :                 m_subdatasetComponent.pop_back();
     292             :             }
     293             :         }
     294             :     }
     295             : };
     296             : 
     297        2679 : static GDALSubdatasetInfo *NCDFDriverGetSubdatasetInfo(const char *pszFileName)
     298             : {
     299        2679 :     if (STARTS_WITH_CI(pszFileName, "NETCDF:"))
     300             :     {
     301             :         std::unique_ptr<GDALSubdatasetInfo> info =
     302          54 :             std::make_unique<NCDFDriverSubdatasetInfo>(pszFileName);
     303             :         // Subdataset component can be empty, path cannot.
     304          54 :         if (!info->GetPathComponent().empty())
     305             :         {
     306          52 :             return info.release();
     307             :         }
     308             :     }
     309        2627 :     return nullptr;
     310             : }
     311             : 
     312             : /************************************************************************/
     313             : /*                   netCDFDriverSetCommonMetadata()                    */
     314             : /************************************************************************/
     315             : 
     316        1307 : void netCDFDriverSetCommonMetadata(GDALDriver *poDriver)
     317             : {
     318             :     // Set the driver details.
     319        1307 :     poDriver->SetDescription(DRIVER_NAME);
     320        1307 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     321        1307 :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
     322        1307 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
     323        1307 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
     324        1307 :     poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
     325        1307 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Network Common Data Format");
     326        1307 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/netcdf.html");
     327        1307 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "nc");
     328             : 
     329        1307 :     poDriver->SetMetadataItem(
     330             :         GDAL_DMD_OPENOPTIONLIST,
     331             :         "<OpenOptionList>"
     332             :         "   <Option name='HONOUR_VALID_RANGE' type='boolean' scope='raster' "
     333             :         "description='Whether to set to nodata pixel values outside of the "
     334             :         "validity range' default='YES'/>"
     335             :         "   <Option name='IGNORE_XY_AXIS_NAME_CHECKS' type='boolean' "
     336             :         "scope='raster' "
     337             :         "description='Whether X/Y dimensions should be always considered as "
     338             :         "geospatial axis, even if the lack conventional attributes confirming "
     339             :         "it.'"
     340             :         " default='NO'/>"
     341             :         "   <Option name='VARIABLES_AS_BANDS' type='boolean' scope='raster' "
     342             :         "description='Whether 2D variables that share the same indexing "
     343             :         "dimensions "
     344             :         "should be exposed as several bands of a same dataset instead of "
     345             :         "several "
     346             :         "subdatasets.' default='NO'/>"
     347             :         "   <Option name='ASSUME_LONGLAT' type='boolean' scope='raster' "
     348             :         "description='Whether when all else has failed for determining a CRS, "
     349             :         "a "
     350             :         "meaningful geotransform has been found, and is within the  "
     351             :         "bounds -180,360 -90,90, assume OGC:CRS84.' default='NO'/>"
     352             :         "   <Option name='PRESERVE_AXIS_UNIT_IN_CRS' type='boolean' "
     353             :         "scope='raster' description='Whether unusual linear axis unit (km) "
     354             :         "should be kept as such, instead of being normalized to metre' "
     355             :         "default='NO'/>"
     356        1307 :         "</OpenOptionList>");
     357        1307 :     poDriver->SetMetadataItem(
     358             :         GDAL_DMD_CREATIONDATATYPES,
     359             :         "Byte Int8 UInt16 Int16 UInt32 Int32 Int64 UInt64 "
     360             :         "Float32 Float64 "
     361        1307 :         "CInt16 CInt32 CFloat32 CFloat64");
     362        1307 :     poDriver->SetMetadataItem(
     363             :         GDAL_DMD_CREATIONOPTIONLIST,
     364             :         "<CreationOptionList>"
     365             :         "   <Option name='FORMAT' type='string-select' default='NC'>"
     366             :         "     <Value>NC</Value>"
     367             : #if NETCDF_CORE_HAS_NC2
     368             :         "     <Value>NC2</Value>"
     369             : #endif
     370             :         "     <Value>NC4</Value>"
     371             :         "     <Value>NC4C</Value>"
     372             :         "   </Option>"
     373             :         "   <Option name='COMPRESS' type='string-select' scope='raster' "
     374             :         "default='NONE'>"
     375             :         "     <Value>NONE</Value>"
     376             :         "     <Value>DEFLATE</Value>"
     377             :         "   </Option>"
     378             :         "   <Option name='ZLEVEL' type='int' scope='raster' "
     379             :         "description='DEFLATE compression level 1-9' default='1'/>"
     380             :         "   <Option name='WRITE_BOTTOMUP' type='boolean' scope='raster' "
     381             :         "default='YES'>"
     382             :         "   </Option>"
     383             :         "   <Option name='WRITE_GDAL_TAGS' type='boolean' default='YES'>"
     384             :         "   </Option>"
     385             :         "   <Option name='WRITE_LONLAT' type='string-select' scope='raster'>"
     386             :         "     <Value>YES</Value>"
     387             :         "     <Value>NO</Value>"
     388             :         "     <Value>IF_NEEDED</Value>"
     389             :         "   </Option>"
     390             :         "   <Option name='TYPE_LONLAT' type='string-select' scope='raster'>"
     391             :         "     <Value>float</Value>"
     392             :         "     <Value>double</Value>"
     393             :         "   </Option>"
     394             :         "   <Option name='PIXELTYPE' type='string-select' scope='raster' "
     395             :         "description='(deprecated, use Int8 datatype) only used in Create()'>"
     396             :         "       <Value>DEFAULT</Value>"
     397             :         "       <Value>SIGNEDBYTE</Value>"
     398             :         "   </Option>"
     399             :         "   <Option name='CHUNKING' type='boolean' scope='raster' "
     400             :         "default='YES' description='define chunking when creating netcdf4 "
     401             :         "file'/>"
     402             :         "   <Option name='MULTIPLE_LAYERS' type='string-select' scope='vector' "
     403             :         "description='Behaviour regarding multiple vector layer creation' "
     404             :         "default='NO'>"
     405             :         "       <Value>NO</Value>"
     406             :         "       <Value>SEPARATE_FILES</Value>"
     407             :         "       <Value>SEPARATE_GROUPS</Value>"
     408             :         "   </Option>"
     409             :         "   <Option name='GEOMETRY_ENCODING' type='string' scope='vector' "
     410             :         "default='CF_1.8' description='Specifies the type of geometry encoding "
     411             :         "when creating a netCDF dataset'>"
     412             :         "       <Value>WKT</Value>"
     413             :         "       <Value>CF_1.8</Value>"
     414             :         "   </Option>"
     415             :         "   <Option name='CONFIG_FILE' type='string' scope='vector' "
     416             :         "description='Path to a XML configuration file (or content inlined)'/>"
     417             :         "   <Option name='WRITE_GDAL_VERSION' type='boolean' default='YES'/>"
     418             :         "   <Option name='WRITE_GDAL_HISTORY' type='boolean' default='YES'/>"
     419             :         "   <Option name='BAND_NAMES' type='string' scope='raster' />"
     420        1307 :         "</CreationOptionList>");
     421        1307 :     poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
     422             : 
     423        1307 :     poDriver->SetMetadataItem(
     424             :         GDAL_DS_LAYER_CREATIONOPTIONLIST,
     425             :         "<LayerCreationOptionList>"
     426             :         "   <Option name='RECORD_DIM_NAME' type='string' description='Name of "
     427             :         "the unlimited dimension' default='record'/>"
     428             :         "   <Option name='STRING_DEFAULT_WIDTH' type='int' description='"
     429             :         "For non-NC4 format, "
     430             :         "default width of strings. Default is 10 in autogrow mode, 80 "
     431             :         "otherwise.'/>"
     432             :         "   <Option name='WKT_DEFAULT_WIDTH' type='int' description='"
     433             :         "For non-NC4 format, "
     434             :         "default width of WKT strings. Default is 1000 in autogrow mode, 10000 "
     435             :         "otherwise.'/>"
     436             :         "   <Option name='AUTOGROW_STRINGS' type='boolean' "
     437             :         "description='Whether to auto-grow non-bounded string fields of "
     438             :         "bidimensional char variable' default='YES'/>"
     439             :         "   <Option name='USE_STRING_IN_NC4' type='boolean' "
     440             :         "description='Whether to use NetCDF string type for strings in NC4 "
     441             :         "format. If NO, bidimensional char variable are used' default='YES'/>"
     442             : #if 0
     443             : "   <Option name='NCDUMP_COMPAT' type='boolean' description='When USE_STRING_IN_NC4=YEs, whether to use empty string instead of null string to avoid crashes with ncdump' default='NO'/>"
     444             : #endif
     445             :         "   <Option name='FEATURE_TYPE' type='string-select' description='CF "
     446             :         "FeatureType' default='AUTO'>"
     447             :         "       <Value>AUTO</Value>"
     448             :         "       <Value>POINT</Value>"
     449             :         "       <Value>PROFILE</Value>"
     450             :         "   </Option>"
     451             :         "   <Option name='BUFFER_SIZE' type='int' default='' "
     452             :         "description='Specifies the soft limit of buffer translation in bytes. "
     453             :         "Minimum size is 4096. Does not apply to datasets with CF version less "
     454             :         "than 1.8.'/>"
     455             :         "   <Option name='GROUPLESS_WRITE_BACK' type='boolean' default='NO' "
     456             :         "description='Enables or disables array building write back for "
     457             :         "CF-1.8.'/>"
     458             :         "   <Option name='PROFILE_DIM_NAME' type='string' description='Name of "
     459             :         "the profile dimension and variable' default='profile'/>"
     460             :         "   <Option name='PROFILE_DIM_INIT_SIZE' type='string' "
     461             :         "description='Initial size of profile dimension (default 100), or "
     462             :         "UNLIMITED for NC4 files'/>"
     463             :         "   <Option name='PROFILE_VARIABLES' type='string' description='Comma "
     464             :         "separated list of field names that must be indexed by the profile "
     465             :         "dimension'/>"
     466        1307 :         "</LayerCreationOptionList>");
     467             : 
     468             :     // Make driver config and capabilities available.
     469             : #if NETCDF_CORE_HAS_NC2
     470        1307 :     poDriver->SetMetadataItem("NETCDF_HAS_NC2", "YES");
     471             : #endif
     472        1307 :     poDriver->SetMetadataItem("NETCDF_HAS_NC4", "YES");
     473             : #ifdef NETCDF_HAS_HDF4
     474             :     poDriver->SetMetadataItem("NETCDF_HAS_HDF4", "YES");
     475             : #endif
     476             : 
     477        1307 :     poDriver->SetMetadataItem("NETCDF_HAS_NETCDF_MEM", "YES");
     478             : 
     479             : #ifdef ENABLE_NCDUMP
     480        1307 :     poDriver->SetMetadataItem("ENABLE_NCDUMP", "YES");
     481             : #endif
     482             : 
     483        1307 :     poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
     484             : 
     485        1307 :     poDriver->SetMetadataItem(
     486             :         GDAL_DMD_MULTIDIM_DATASET_CREATIONOPTIONLIST,
     487             :         "<MultiDimDatasetCreationOptionList>"
     488             :         "   <Option name='FORMAT' type='string-select' default='NC4'>"
     489             :         "     <Value>NC</Value>"
     490             : #if NETCDF_CORE_HAS_NC2
     491             :         "     <Value>NC2</Value>"
     492             : #endif
     493             :         "     <Value>NC4</Value>"
     494             :         "     <Value>NC4C</Value>"
     495             :         "   </Option>"
     496             :         "   <Option name='CONVENTIONS' type='string' default='CF-1.6' "
     497             :         "description='Value of the Conventions attribute'/>"
     498        1307 :         "</MultiDimDatasetCreationOptionList>");
     499             : 
     500        1307 :     poDriver->SetMetadataItem(
     501             :         GDAL_DMD_MULTIDIM_DIMENSION_CREATIONOPTIONLIST,
     502             :         "<MultiDimDimensionCreationOptionList>"
     503             :         "   <Option name='UNLIMITED' type='boolean' description='Whether the "
     504             :         "dimension should be unlimited' default='false'/>"
     505        1307 :         "</MultiDimDimensionCreationOptionList>");
     506             : 
     507        1307 :     poDriver->SetMetadataItem(
     508             :         GDAL_DMD_MULTIDIM_ARRAY_CREATIONOPTIONLIST,
     509             :         "<MultiDimArrayCreationOptionList>"
     510             :         "   <Option name='BLOCKSIZE' type='int' description='Block size in "
     511             :         "pixels'/>"
     512             :         "   <Option name='COMPRESS' type='string-select' default='NONE'>"
     513             :         "     <Value>NONE</Value>"
     514             :         "     <Value>DEFLATE</Value>"
     515             :         "   </Option>"
     516             :         "   <Option name='ZLEVEL' type='int' description='DEFLATE compression "
     517             :         "level 1-9' default='1'/>"
     518             :         "   <Option name='NC_TYPE' type='string-select' default='netCDF data "
     519             :         "type'>"
     520             :         "     <Value>AUTO</Value>"
     521             :         "     <Value>NC_BYTE</Value>"
     522             :         "     <Value>NC_INT64</Value>"
     523             :         "     <Value>NC_UINT64</Value>"
     524             :         "   </Option>"
     525        1307 :         "</MultiDimArrayCreationOptionList>");
     526             : 
     527        1307 :     poDriver->SetMetadataItem(
     528             :         GDAL_DMD_MULTIDIM_ARRAY_OPENOPTIONLIST,
     529             :         "<MultiDimArrayOpenOptionList>"
     530             :         "   <Option name='USE_DEFAULT_FILL_AS_NODATA' type='boolean' "
     531             :         "description='Whether the default fill value should be used as nodata "
     532             :         "when there is no _FillValue or missing_value attribute' default='NO'/>"
     533             :         "   <Option name='RAW_DATA_CHUNK_CACHE_SIZE' type='integer' "
     534             :         "description='The total size of the libnetcdf raw data chunk cache, "
     535             :         "in bytes. Only for netCDF4/HDF5 files'/>"
     536             :         "   <Option name='CHUNK_SLOTS' type='integer' "
     537             :         "description='The number of chunk slots in the libnetcdf raw data "
     538             :         "chunk cache. "
     539             :         "Only for netCDF4/HDF5 files'/>"
     540             :         "   <Option name='PREEMPTION' type='float' min='0' max='1' "
     541             :         "description='Indicates how much chunks from libnetcdf chunk cache "
     542             :         "that have been fully read are favored for preemption. "
     543             :         "Only for netCDF4/HDF5 files'/>"
     544        1307 :         "</MultiDimArrayOpenOptionList>");
     545             : 
     546        1307 :     poDriver->SetMetadataItem(GDAL_DMD_MULTIDIM_ATTRIBUTE_CREATIONOPTIONLIST,
     547             :                               "<MultiDimAttributeCreationOptionList>"
     548             :                               "   <Option name='NC_TYPE' type='string-select' "
     549             :                               "default='netCDF data type'>"
     550             :                               "     <Value>AUTO</Value>"
     551             :                               "     <Value>NC_BYTE</Value>"
     552             :                               "     <Value>NC_CHAR</Value>"
     553             :                               "     <Value>NC_INT64</Value>"
     554             :                               "     <Value>NC_UINT64</Value>"
     555             :                               "   </Option>"
     556        1307 :                               "</MultiDimAttributeCreationOptionList>");
     557             : 
     558        1307 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES,
     559        1307 :                               "Integer Integer64 Real String Date DateTime");
     560        1307 :     poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS,
     561        1307 :                               "Comment AlternativeName");
     562             : 
     563        1307 :     poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
     564             : 
     565        1307 :     poDriver->pfnIdentify = netCDFDatasetIdentify;
     566        1307 :     poDriver->pfnGetSubdatasetInfoFunc = NCDFDriverGetSubdatasetInfo;
     567        1307 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     568        1307 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
     569        1307 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
     570        1307 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_MULTIDIMENSIONAL, "YES");
     571        1307 : }
     572             : 
     573             : /************************************************************************/
     574             : /*                    DeclareDeferredNetCDFPlugin()                     */
     575             : /************************************************************************/
     576             : 
     577             : #ifdef PLUGIN_FILENAME
     578        1595 : void DeclareDeferredNetCDFPlugin()
     579             : {
     580        1595 :     if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
     581             :     {
     582         302 :         return;
     583             :     }
     584        1293 :     auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     585             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     586             :     poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     587             :                               PLUGIN_INSTALLATION_MESSAGE);
     588             : #endif
     589        1293 :     netCDFDriverSetCommonMetadata(poDriver);
     590        1293 :     GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     591             : }
     592             : #endif

Generated by: LCOV version 1.14