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

Generated by: LCOV version 1.14