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

Generated by: LCOV version 1.14