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

Generated by: LCOV version 1.14