LCOV - code coverage report
Current view: top level - frmts/netcdf - netcdflayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1297 1419 91.4 %
Date: 2026-10-23 13:59:38 Functions: 28 28 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  netCDF read/write Driver
       4             :  * Purpose:  GDAL bindings over netCDF library.
       5             :  * Author:   Even Rouault <even.rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2016, Even Rouault <even.rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "netcdfdataset.h"
      14             : #include "netcdfsgwriterutil.h"
      15             : #include "netcdfsg.h"
      16             : #include "netcdflayersg.h"
      17             : #include "cpl_time.h"
      18             : 
      19             : /************************************************************************/
      20             : /*                            netCDFLayer()                             */
      21             : /************************************************************************/
      22             : 
      23         223 : netCDFLayer::netCDFLayer(netCDFDataset *poDS, int nLayerCDFId,
      24             :                          const char *pszName, OGRwkbGeometryType eGeomType,
      25         223 :                          OGRSpatialReference *poSRS)
      26             :     : m_poDS(poDS), m_nLayerCDFId(nLayerCDFId),
      27         223 :       m_poFeatureDefn(new OGRFeatureDefn(pszName)), m_osRecordDimName("record"),
      28             :       m_nRecordDimID(-1), m_nDefaultWidth(10), m_bAutoGrowStrings(true),
      29             :       m_nDefaultMaxWidthDimId(-1), m_nXVarID(-1), m_nYVarID(-1), m_nZVarID(-1),
      30             :       m_nXVarNCDFType(NC_NAT), m_nYVarNCDFType(NC_NAT), m_nZVarNCDFType(NC_NAT),
      31             :       m_osWKTVarName("ogc_wkt"), m_nWKTMaxWidth(10000), m_nWKTMaxWidthDimId(-1),
      32             :       m_nWKTVarID(-1), m_nWKTNCDFType(NC_NAT), m_bLegacyCreateMode(true),
      33             :       m_nCurFeatureId(1), m_bWriteGDALTags(true), m_bUseStringInNC4(true),
      34             :       m_bNCDumpCompat(true), m_nProfileDimID(-1), m_nProfileVarID(-1),
      35             :       m_bProfileVarUnlimited(false), m_nParentIndexVarID(-1),
      36         223 :       layerVID_alloc(poDS->cdfid == m_nLayerCDFId
      37             :                          ? nullptr
      38          69 :                          : new nccfdriver::netCDFVID(poDS, m_nLayerCDFId)),
      39         223 :       layerVID(layerVID_alloc.get() == nullptr ? poDS->vcdf : *layerVID_alloc),
      40             :       m_SGeometryFeatInd(0), m_poLayerConfig(nullptr),
      41         446 :       m_layerSGDefn(poDS->cdfid, nccfdriver::OGRtoRaw(eGeomType), poDS->vcdf,
      42         738 :                     poDS->GeometryScribe)
      43             : {
      44         223 :     m_uXVarNoData.nVal64 = 0;
      45         223 :     m_uYVarNoData.nVal64 = 0;
      46         223 :     m_uZVarNoData.nVal64 = 0;
      47         223 :     m_poFeatureDefn->SetGeomType(eGeomType);
      48         223 :     if (eGeomType != wkbNone)
      49         187 :         m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
      50         223 :     m_poFeatureDefn->Reference();
      51         223 :     SetDescription(pszName);
      52         223 : }
      53             : 
      54             : /************************************************************************/
      55             : /*                            ~netCDFLayer()                            */
      56             : /************************************************************************/
      57             : 
      58         288 : netCDFLayer::~netCDFLayer()
      59             : {
      60         223 :     m_poFeatureDefn->Release();
      61         288 : }
      62             : 
      63             : /************************************************************************/
      64             : /*                   netCDFWriteAttributesFromConf()                    */
      65             : /************************************************************************/
      66             : 
      67           8 : void netCDFLayer::netCDFWriteAttributesFromConf(
      68             :     int cdfid, int varid,
      69             :     const std::vector<netCDFWriterConfigAttribute> &aoAttributes) const
      70             : {
      71          15 :     for (const auto &oAtt : aoAttributes)
      72             :     {
      73             :         try
      74             :         {
      75           7 :             int status = NC_NOERR;
      76           7 :             if (oAtt.m_osValue.empty())
      77             :             {
      78           1 :                 int attid = -1;
      79           1 :                 status = nc_inq_attid(cdfid, varid, oAtt.m_osName, &attid);
      80           1 :                 if (status == NC_NOERR)
      81           1 :                     status = nc_del_att(cdfid, varid, oAtt.m_osName);
      82             :                 else
      83           0 :                     status = NC_NOERR;
      84             :             }
      85           6 :             else if (EQUAL(oAtt.m_osType, "string"))
      86             :             {
      87           4 :                 layerVID.nc_put_vatt_text(varid, oAtt.m_osName, oAtt.m_osValue);
      88             :             }
      89             : 
      90           2 :             else if (EQUAL(oAtt.m_osType, "integer"))
      91             :             {
      92           1 :                 int nVal = atoi(oAtt.m_osValue);
      93           1 :                 layerVID.nc_put_vatt_int(varid, oAtt.m_osName, &nVal);
      94             :             }
      95             : 
      96           1 :             else if (EQUAL(oAtt.m_osType, "double"))
      97             :             {
      98           1 :                 double dfVal = CPLAtof(oAtt.m_osValue);
      99           1 :                 layerVID.nc_put_vatt_double(varid, oAtt.m_osName, &dfVal);
     100             :             }
     101             : 
     102           7 :             NCDF_ERR(status);
     103             :         }
     104             : 
     105           0 :         catch (nccfdriver::SG_Exception &e)
     106             :         {
     107           0 :             CPLError(CE_Failure, CPLE_FileIO, "%s", e.get_err_msg());
     108             :         }
     109             :     }
     110           8 : }
     111             : 
     112             : /************************************************************************/
     113             : /*                               Create()                               */
     114             : /************************************************************************/
     115             : 
     116          58 : bool netCDFLayer::Create(CSLConstList papszOptions,
     117             :                          const netCDFWriterConfigLayer *poLayerConfig)
     118             : {
     119          58 :     m_poDS->SetDefineMode(true);
     120             : 
     121          58 :     if (m_poDS->bSGSupport)
     122             :     {
     123          41 :         m_bLegacyCreateMode = false;
     124             :     }
     125             : 
     126             :     else
     127             :     {
     128          17 :         m_bLegacyCreateMode = true;
     129             :     }
     130             : 
     131          58 :     long long newbufsize = 0;
     132             :     const char *memorySizeLimitation =
     133          58 :         CSLFetchNameValueDef(papszOptions, "BUFFER_SIZE", nullptr);
     134          58 :     if (memorySizeLimitation && memorySizeLimitation[0] != '\0')
     135             :     {
     136           4 :         newbufsize = strtoll(memorySizeLimitation, nullptr, 10);
     137             :     }
     138             : 
     139             :     const char *singleDatumMode =
     140          58 :         CSLFetchNameValueDef(papszOptions, "GROUPLESS_WRITE_BACK", "NO");
     141             : 
     142          58 :     if (CPLTestBool(singleDatumMode))
     143             :     {
     144           1 :         m_poDS->GeometryScribe.setSingleDatumMode(true);
     145           1 :         m_poDS->FieldScribe.setSingleDatumMode(true);
     146             :     }
     147             : 
     148          58 :     if (m_bLegacyCreateMode)
     149             :     {
     150             :         m_osRecordDimName = CSLFetchNameValueDef(
     151          17 :             papszOptions, "RECORD_DIM_NAME", m_osRecordDimName.c_str());
     152             :     }
     153             : 
     154          58 :     m_bAutoGrowStrings =
     155          58 :         CPL_TO_BOOL(CSLFetchBoolean(papszOptions, "AUTOGROW_STRINGS", TRUE));
     156          58 :     m_nDefaultWidth = atoi(
     157             :         CSLFetchNameValueDef(papszOptions, "STRING_DEFAULT_WIDTH",
     158          58 :                              CPLSPrintf("%d", m_bAutoGrowStrings ? 10 : 80)));
     159          58 :     m_bWriteGDALTags =
     160          58 :         m_poDS->aosCreationOptions.FetchBool("WRITE_GDAL_TAGS", true);
     161          58 :     m_bUseStringInNC4 =
     162          58 :         CPL_TO_BOOL(CSLFetchBoolean(papszOptions, "USE_STRING_IN_NC4", TRUE));
     163          58 :     m_bNCDumpCompat =
     164          58 :         CPL_TO_BOOL(CSLFetchBoolean(papszOptions, "NCDUMP_COMPAT", TRUE));
     165             : 
     166         116 :     std::vector<std::pair<CPLString, int>> aoAutoVariables;
     167             : 
     168             :     const char *pszFeatureType =
     169          58 :         CSLFetchNameValue(papszOptions, "FEATURE_TYPE");
     170          58 :     if (pszFeatureType != nullptr)
     171             :     {
     172           4 :         if (EQUAL(pszFeatureType, "POINT"))
     173             :         {
     174           0 :             if (wkbFlatten(m_poFeatureDefn->GetGeomType()) != wkbPoint)
     175             :             {
     176           0 :                 CPLError(CE_Warning, CPLE_NotSupported,
     177             :                          "FEATURE_TYPE=POINT only supported for Point layer "
     178             :                          "geometry type.");
     179             :             }
     180             :         }
     181             : 
     182           4 :         else if (EQUAL(pszFeatureType, "PROFILE"))
     183             :         {
     184           4 :             if (wkbFlatten(m_poFeatureDefn->GetGeomType()) != wkbPoint)
     185             :             {
     186           0 :                 CPLError(CE_Warning, CPLE_NotSupported,
     187             :                          "FEATURE_TYPE=PROFILE only supported for Point layer "
     188             :                          "geometry type.");
     189             :             }
     190             :             else
     191             :             {
     192             :                 // Cf
     193             :                 // http://cfconventions.org/cf-conventions/v1.6.0/cf-conventions.html#_indexed_ragged_array_representation_of_profiles
     194             : 
     195             :                 m_osProfileDimName = CSLFetchNameValueDef(
     196           4 :                     papszOptions, "PROFILE_DIM_NAME", "profile");
     197             :                 m_osProfileVariables =
     198           4 :                     CSLFetchNameValueDef(papszOptions, "PROFILE_VARIABLES", "");
     199             : 
     200           4 :                 const char *pszProfileInitSize = CSLFetchNameValueDef(
     201             :                     papszOptions, "PROFILE_DIM_INIT_SIZE",
     202           4 :                     (m_poDS->eFormat == NCDF_FORMAT_NC4) ? "UNLIMITED" : "100");
     203           4 :                 m_bProfileVarUnlimited = EQUAL(pszProfileInitSize, "UNLIMITED");
     204           4 :                 size_t nProfileInitSize =
     205           4 :                     m_bProfileVarUnlimited
     206           4 :                         ? NC_UNLIMITED
     207           3 :                         : static_cast<size_t>(atoi(pszProfileInitSize));
     208           4 :                 int status = nc_def_dim(m_nLayerCDFId, m_osProfileDimName,
     209             :                                         nProfileInitSize, &m_nProfileDimID);
     210           4 :                 NCDF_ERR(status);
     211           4 :                 if (status != NC_NOERR)
     212           0 :                     return false;
     213             : 
     214           4 :                 status = nc_def_var(m_nLayerCDFId, m_osProfileDimName, NC_INT,
     215           4 :                                     1, &m_nProfileDimID, &m_nProfileVarID);
     216           4 :                 NCDF_ERR(status);
     217           4 :                 if (status != NC_NOERR)
     218           0 :                     return false;
     219             : 
     220           4 :                 aoAutoVariables.push_back(
     221           8 :                     std::pair(m_osProfileDimName, m_nProfileVarID));
     222             : 
     223             :                 status =
     224           4 :                     nc_put_att_text(m_nLayerCDFId, m_nProfileVarID, "cf_role",
     225             :                                     strlen("profile_id"), "profile_id");
     226           4 :                 NCDF_ERR(status);
     227             :             }
     228             :         }
     229           0 :         else if (!EQUAL(pszFeatureType, "AUTO"))
     230             :         {
     231           0 :             CPLError(CE_Warning, CPLE_NotSupported,
     232             :                      "FEATURE_TYPE=%s not supported.", pszFeatureType);
     233             :         }
     234             :     }
     235             : 
     236          58 :     const OGRSpatialReference *poSRS = nullptr;
     237          58 :     if (m_poFeatureDefn->GetGeomFieldCount())
     238          56 :         poSRS = m_poFeatureDefn->GetGeomFieldDefn(0)->GetSpatialRef();
     239             : 
     240             :     int status;
     241          58 :     if (m_bLegacyCreateMode)
     242             :     {
     243             : 
     244          17 :         if (m_bWriteGDALTags)
     245             :         {
     246          15 :             status = nc_put_att_text(m_nLayerCDFId, NC_GLOBAL, "ogr_layer_name",
     247          15 :                                      strlen(m_poFeatureDefn->GetName()),
     248          15 :                                      m_poFeatureDefn->GetName());
     249          15 :             NCDF_ERR(status);
     250             :         }
     251             : 
     252          17 :         status = nc_def_dim(m_nLayerCDFId, m_osRecordDimName, NC_UNLIMITED,
     253             :                             &m_nRecordDimID);
     254          17 :         NCDF_ERR(status);
     255          17 :         if (status != NC_NOERR)
     256           0 :             return false;
     257             : 
     258          17 :         if (!m_osProfileDimName.empty())
     259             :         {
     260           8 :             status = nc_def_var(m_nLayerCDFId, "parentIndex", NC_INT, 1,
     261           4 :                                 &m_nRecordDimID, &m_nParentIndexVarID);
     262           4 :             NCDF_ERR(status);
     263           4 :             if (status != NC_NOERR)
     264           0 :                 return false;
     265             : 
     266           4 :             aoAutoVariables.push_back(
     267           4 :                 std::pair("parentIndex", m_nParentIndexVarID));
     268             : 
     269             :             status =
     270           4 :                 nc_put_att_text(m_nLayerCDFId, m_nParentIndexVarID, CF_LNG_NAME,
     271             :                                 strlen("index of profile"), "index of profile");
     272           4 :             NCDF_ERR(status);
     273             : 
     274           4 :             status = nc_put_att_text(
     275             :                 m_nLayerCDFId, m_nParentIndexVarID, "instance_dimension",
     276             :                 m_osProfileDimName.size(), m_osProfileDimName.c_str());
     277           4 :             NCDF_ERR(status);
     278             :         }
     279             : 
     280          17 :         if (wkbFlatten(m_poFeatureDefn->GetGeomType()) == wkbPoint)
     281             :         {
     282             :             const int nPointDim =
     283           8 :                 !m_osProfileDimName.empty() ? m_nProfileDimID : m_nRecordDimID;
     284             :             const bool bIsGeographic =
     285           8 :                 (poSRS == nullptr || poSRS->IsGeographic());
     286             : 
     287           8 :             const char *pszXVarName =
     288           8 :                 bIsGeographic ? CF_LONGITUDE_VAR_NAME : CF_PROJ_X_VAR_NAME;
     289             : 
     290           8 :             status = nc_def_var(m_nLayerCDFId, pszXVarName, NC_DOUBLE, 1,
     291             :                                 &nPointDim, &m_nXVarID);
     292             : 
     293           8 :             NCDF_ERR(status);
     294           8 :             if (status != NC_NOERR)
     295             :             {
     296           0 :                 return false;
     297             :             }
     298             : 
     299           8 :             const char *pszYVarName =
     300           8 :                 bIsGeographic ? CF_LATITUDE_VAR_NAME : CF_PROJ_Y_VAR_NAME;
     301             : 
     302           8 :             status = nc_def_var(m_nLayerCDFId, pszYVarName, NC_DOUBLE, 1,
     303             :                                 &nPointDim, &m_nYVarID);
     304           8 :             NCDF_ERR(status);
     305           8 :             if (status != NC_NOERR)
     306             :             {
     307           0 :                 return false;
     308             :             }
     309             : 
     310           8 :             aoAutoVariables.push_back(std::pair(pszXVarName, m_nXVarID));
     311           8 :             aoAutoVariables.push_back(std::pair(pszYVarName, m_nYVarID));
     312             : 
     313           8 :             m_nXVarNCDFType = NC_DOUBLE;
     314           8 :             m_nYVarNCDFType = NC_DOUBLE;
     315           8 :             m_uXVarNoData.dfVal = NC_FILL_DOUBLE;
     316           8 :             m_uYVarNoData.dfVal = NC_FILL_DOUBLE;
     317             : 
     318           8 :             m_osCoordinatesValue = pszXVarName;
     319           8 :             m_osCoordinatesValue += " ";
     320           8 :             m_osCoordinatesValue += pszYVarName;
     321             : 
     322           8 :             if (poSRS == nullptr || poSRS->IsGeographic())
     323             :             {
     324             :                 // Deal with potentional issues of multiple groups
     325           5 :                 NCDFWriteLonLatVarsAttributes(layerVID, m_nXVarID, m_nYVarID);
     326             :             }
     327             : 
     328           3 :             else if (poSRS->IsProjected())
     329             :             {
     330             :                 // Deal with potentional issues of multiple groups
     331           3 :                 NCDFWriteXYVarsAttributes(layerVID, m_nXVarID, m_nYVarID,
     332             :                                           poSRS);
     333             :             }
     334             : 
     335           8 :             if (m_poFeatureDefn->GetGeomType() == wkbPoint25D)
     336             :             {
     337           8 :                 const char *pszZVarName = "z";
     338             : 
     339          16 :                 status = nc_def_var(m_nLayerCDFId, pszZVarName, NC_DOUBLE, 1,
     340           8 :                                     &m_nRecordDimID, &m_nZVarID);
     341           8 :                 NCDF_ERR(status);
     342           8 :                 if (status != NC_NOERR)
     343             :                 {
     344           0 :                     return false;
     345             :                 }
     346             : 
     347           8 :                 aoAutoVariables.push_back(std::pair(pszZVarName, m_nZVarID));
     348             : 
     349           8 :                 m_nZVarNCDFType = NC_DOUBLE;
     350           8 :                 m_uZVarNoData.dfVal = NC_FILL_DOUBLE;
     351             : 
     352             :                 status =
     353           8 :                     nc_put_att_text(m_nLayerCDFId, m_nZVarID, CF_LNG_NAME,
     354             :                                     strlen("z coordinate"), "z coordinate");
     355           8 :                 NCDF_ERR(status);
     356             : 
     357           8 :                 status = nc_put_att_text(m_nLayerCDFId, m_nZVarID, CF_STD_NAME,
     358             :                                          strlen("height"), "height");
     359           8 :                 NCDF_ERR(status);
     360             : 
     361           8 :                 status = nc_put_att_text(m_nLayerCDFId, m_nZVarID, CF_AXIS,
     362             :                                          strlen("Z"), "Z");
     363           8 :                 NCDF_ERR(status);
     364             : 
     365           8 :                 status = nc_put_att_text(m_nLayerCDFId, m_nZVarID, CF_UNITS,
     366             :                                          strlen("m"), "m");
     367           8 :                 NCDF_ERR(status);
     368             : 
     369           8 :                 m_osCoordinatesValue += " ";
     370           8 :                 m_osCoordinatesValue += pszZVarName;
     371             :             }
     372             : 
     373             :             const char *pszFeatureTypeVal =
     374           8 :                 !m_osProfileDimName.empty() ? "profile" : "point";
     375             : 
     376             :             status =
     377           8 :                 nc_put_att_text(m_nLayerCDFId, NC_GLOBAL, "featureType",
     378             :                                 strlen(pszFeatureTypeVal), pszFeatureTypeVal);
     379             : 
     380           8 :             NCDF_ERR(status);
     381             :         }
     382           9 :         else if (m_poFeatureDefn->GetGeomType() != wkbNone)
     383             :         {
     384           7 :             if (m_poDS->eFormat == NCDF_FORMAT_NC4 && m_bUseStringInNC4)
     385             :             {
     386           2 :                 m_nWKTNCDFType = NC_STRING;
     387           2 :                 status =
     388           2 :                     nc_def_var(m_nLayerCDFId, m_osWKTVarName.c_str(), NC_STRING,
     389           2 :                                1, &m_nRecordDimID, &m_nWKTVarID);
     390             :             }
     391             :             else
     392             :             {
     393           5 :                 m_nWKTNCDFType = NC_CHAR;
     394           5 :                 m_nWKTMaxWidth = atoi(CSLFetchNameValueDef(
     395             :                     papszOptions, "WKT_DEFAULT_WIDTH",
     396           5 :                     CPLSPrintf("%d", m_bAutoGrowStrings ? 1000 : 10000)));
     397           5 :                 status = nc_def_dim(
     398             :                     m_nLayerCDFId,
     399             :                     CPLSPrintf("%s_max_width", m_osWKTVarName.c_str()),
     400           5 :                     m_nWKTMaxWidth, &m_nWKTMaxWidthDimId);
     401           5 :                 NCDF_ERR(status);
     402           5 :                 if (status != NC_NOERR)
     403             :                 {
     404           0 :                     return false;
     405             :                 }
     406             : 
     407           5 :                 int anDims[2] = {m_nRecordDimID, m_nWKTMaxWidthDimId};
     408           5 :                 status = nc_def_var(m_nLayerCDFId, m_osWKTVarName.c_str(),
     409             :                                     NC_CHAR, 2, anDims, &m_nWKTVarID);
     410             :             }
     411           7 :             NCDF_ERR(status);
     412           7 :             if (status != NC_NOERR)
     413             :             {
     414           0 :                 return false;
     415             :             }
     416             : 
     417           7 :             aoAutoVariables.push_back(std::pair(m_osWKTVarName, m_nWKTVarID));
     418             : 
     419           7 :             status = nc_put_att_text(m_nLayerCDFId, m_nWKTVarID, CF_LNG_NAME,
     420             :                                      strlen("Geometry as ISO WKT"),
     421             :                                      "Geometry as ISO WKT");
     422           7 :             NCDF_ERR(status);
     423             : 
     424             :             // nc_put_att_text(m_nLayerCDFId, m_nWKTVarID, CF_UNITS,
     425             :             //                 strlen("none"), "none");
     426             : 
     427           7 :             if (m_bWriteGDALTags)
     428             :             {
     429           7 :                 status = nc_put_att_text(
     430             :                     m_nLayerCDFId, NC_GLOBAL, "ogr_geometry_field",
     431             :                     m_osWKTVarName.size(), m_osWKTVarName.c_str());
     432           7 :                 NCDF_ERR(status);
     433             : 
     434             :                 CPLString osGeometryType =
     435          14 :                     OGRToOGCGeomType(m_poFeatureDefn->GetGeomType());
     436           7 :                 if (wkbHasZ(m_poFeatureDefn->GetGeomType()))
     437           0 :                     osGeometryType += " Z";
     438           7 :                 status = nc_put_att_text(
     439             :                     m_nLayerCDFId, NC_GLOBAL, "ogr_layer_type",
     440             :                     osGeometryType.size(), osGeometryType.c_str());
     441           7 :                 NCDF_ERR(status);
     442             :             }
     443             :         }
     444             :     }
     445             : 
     446          58 :     if (poSRS != nullptr)
     447             :     {
     448          43 :         char *pszCFProjection = nullptr;
     449          43 :         m_sgCRSname = m_bLegacyCreateMode
     450         129 :                           ? ""
     451         124 :                           : std::string(this->GetName()) + std::string("_crs");
     452             : 
     453             :         int nSRSVarId =
     454          86 :             NCDFWriteSRSVariable(m_nLayerCDFId, poSRS, &pszCFProjection,
     455          43 :                                  m_bWriteGDALTags, m_sgCRSname);
     456          43 :         if (nSRSVarId < 0)
     457           0 :             return false;
     458          43 :         if (pszCFProjection != nullptr)
     459             :         {
     460          43 :             aoAutoVariables.push_back(std::pair(pszCFProjection, nSRSVarId));
     461             : 
     462          43 :             m_osGridMapping = pszCFProjection;
     463          43 :             CPLFree(pszCFProjection);
     464             :         }
     465             : 
     466          43 :         if (m_nWKTVarID >= 0 && !m_osGridMapping.empty())
     467             :         {
     468           2 :             status = nc_put_att_text(m_nLayerCDFId, m_nWKTVarID, CF_GRD_MAPPING,
     469             :                                      m_osGridMapping.size(),
     470             :                                      m_osGridMapping.c_str());
     471           2 :             NCDF_ERR(status);
     472             :         }
     473             :     }
     474             : 
     475          58 :     if (m_poDS->oWriterConfig.m_bIsValid)
     476             :     {
     477           3 :         m_poLayerConfig = poLayerConfig;
     478             : 
     479           3 :         netCDFWriteAttributesFromConf(m_nLayerCDFId, NC_GLOBAL,
     480           3 :                                       m_poDS->oWriterConfig.m_aoAttributes);
     481           3 :         if (poLayerConfig != nullptr)
     482             :         {
     483           1 :             netCDFWriteAttributesFromConf(m_nLayerCDFId, NC_GLOBAL,
     484           1 :                                           poLayerConfig->m_aoAttributes);
     485             :         }
     486             : 
     487          11 :         for (const auto &[osVar, nVarId] : aoAutoVariables)
     488             :         {
     489           8 :             const netCDFWriterConfigField *poConfig = nullptr;
     490          16 :             CPLString osLookup = "__" + osVar;
     491           8 :             std::map<CPLString, netCDFWriterConfigField>::const_iterator oIter;
     492          13 :             if (m_poLayerConfig != nullptr &&
     493           5 :                 (oIter = m_poLayerConfig->m_oFields.find(osLookup)) !=
     494          13 :                     m_poLayerConfig->m_oFields.end())
     495             :             {
     496           1 :                 poConfig = &(oIter->second);
     497             :             }
     498           7 :             else if ((oIter = m_poDS->oWriterConfig.m_oFields.find(osLookup)) !=
     499          14 :                      m_poDS->oWriterConfig.m_oFields.end())
     500             :             {
     501           1 :                 poConfig = &(oIter->second);
     502             :             }
     503             : 
     504           8 :             if (poConfig != nullptr)
     505             :             {
     506           2 :                 netCDFWriteAttributesFromConf(m_nLayerCDFId, nVarId,
     507           2 :                                               poConfig->m_aoAttributes);
     508             :             }
     509             :         }
     510             :     }
     511             : 
     512             :     try
     513             :     {
     514          58 :         if (!m_bLegacyCreateMode)
     515             :         {
     516             :             // Write a geometry container
     517             :             OGRwkbGeometryType geometryContainerType =
     518          41 :                 m_poFeatureDefn->GetGeomType();
     519          82 :             std::vector<std::string> coordNames;
     520             :             std::string strXVarName =
     521         123 :                 std::string(this->GetName()).append("_coordX");
     522             :             std::string strYVarName =
     523         123 :                 std::string(this->GetName()).append("_coordY");
     524          41 :             coordNames.push_back(std::move(strXVarName));
     525          41 :             coordNames.push_back(std::move(strYVarName));
     526             : 
     527          41 :             if (nccfdriver::OGRHasZandSupported(geometryContainerType))
     528             :             {
     529             :                 std::string strZVarName =
     530          45 :                     std::string(this->GetName()).append("_coordZ");
     531          15 :                 coordNames.push_back(std::move(strZVarName));
     532             :             }
     533             : 
     534          41 :             if (m_layerSGDefn.getWritableType() == nccfdriver::NONE)
     535             :             {
     536           0 :                 throw nccfdriver::SG_Exception_BadFeature();
     537             :             }
     538             : 
     539         123 :             int writableSGContVarID = nccfdriver::write_Geometry_Container(
     540          82 :                 m_poDS->cdfid, this->GetName(), m_layerSGDefn.getWritableType(),
     541             :                 coordNames);
     542          41 :             m_layerSGDefn.initializeNewContainer(writableSGContVarID);
     543             : 
     544          41 :             if (newbufsize >= 4096)
     545             :             {
     546           4 :                 m_poDS->bufManager.adjustLimit(newbufsize);
     547             :             }
     548             : 
     549             :             // Set record dim ID; POINT it's the node coordinate dim ID and
     550             :             // everything else it's node count:
     551          41 :             if (m_layerSGDefn.getWritableType() == nccfdriver::POINT)
     552             :             {
     553           9 :                 m_nRecordDimID = m_layerSGDefn.get_node_coord_dimID();
     554          18 :                 m_osRecordDimName = std::string(this->GetName()) +
     555          36 :                                     std::string("_") +
     556          27 :                                     std::string(CF_SG_NODE_COORDINATES);
     557             :             }
     558             :             else
     559             :             {
     560          32 :                 m_nRecordDimID = m_layerSGDefn.get_node_count_dimID();
     561          64 :                 m_osRecordDimName = std::string(this->GetName()) +
     562         128 :                                     std::string("_") +
     563          96 :                                     std::string(CF_SG_NODE_COUNT);
     564             :             }
     565             : 
     566             :             // Write the grid mapping, if it exists:
     567          41 :             if (poSRS != nullptr)
     568             :             {
     569          38 :                 status = nc_put_att_text(
     570             :                     m_nLayerCDFId, m_layerSGDefn.get_containerRealID(),
     571             :                     CF_GRD_MAPPING, strlen(m_sgCRSname.c_str()),
     572             :                     m_sgCRSname.c_str());
     573             : 
     574          38 :                 if (status != NC_NOERR)
     575             :                 {
     576             :                     throw nccfdriver::SGWriter_Exception_NCWriteFailure(
     577           0 :                         m_layerSGDefn.get_containerName().c_str(),
     578           0 :                         CF_GRD_MAPPING, "attribute");
     579             :                 }
     580             : 
     581             :                 const std::vector<int> &ncv =
     582          38 :                     m_layerSGDefn.get_nodeCoordVarIDs();
     583          38 :                 int xVar = ncv[0];
     584          38 :                 int yVar = ncv[1];
     585             : 
     586          38 :                 if (poSRS->IsGeographic())
     587             :                 {
     588          37 :                     NCDFWriteLonLatVarsAttributes(layerVID, xVar, yVar);
     589             :                 }
     590             : 
     591           1 :                 else if (poSRS->IsProjected())
     592             :                 {
     593           1 :                     NCDFWriteXYVarsAttributes(layerVID, xVar, yVar, poSRS);
     594             :                 }
     595             :             }
     596             :         }
     597             :     }
     598           0 :     catch (nccfdriver::SG_Exception &sge)
     599             :     {
     600           0 :         CPLError(
     601             :             CE_Failure, CPLE_AppDefined,
     602             :             "An error occurred while writing metadata to the netCDF file.\n%s",
     603             :             sge.get_err_msg());
     604           0 :         return false;
     605             :     }
     606             : 
     607          58 :     m_poDS->SetDefineMode(false);
     608          58 :     return true;
     609             : }
     610             : 
     611             : /************************************************************************/
     612             : /*                           SetRecordDimID()                           */
     613             : /************************************************************************/
     614             : 
     615         100 : void netCDFLayer::SetRecordDimID(int nRecordDimID)
     616             : {
     617         100 :     m_nRecordDimID = nRecordDimID;
     618             :     char szTemp[NC_MAX_NAME + 1];
     619         100 :     szTemp[0] = 0;
     620         100 :     int status = nc_inq_dimname(m_nLayerCDFId, m_nRecordDimID, szTemp);
     621         100 :     NCDF_ERR(status);
     622         100 :     m_osRecordDimName = szTemp;
     623         100 : }
     624             : 
     625             : /************************************************************************/
     626             : /*                            GetFillValue()                            */
     627             : /************************************************************************/
     628             : 
     629         320 : CPLErr netCDFLayer::GetFillValue(int nVarId, char **ppszValue) const
     630             : {
     631         320 :     if (NCDFGetAttr(m_nLayerCDFId, nVarId, NCDF_FillValue, ppszValue) ==
     632             :         CE_None)
     633          67 :         return CE_None;
     634         253 :     return NCDFGetAttr(m_nLayerCDFId, nVarId, "missing_value", ppszValue);
     635             : }
     636             : 
     637         379 : CPLErr netCDFLayer::GetFillValue(int nVarId, double *pdfValue) const
     638             : {
     639         379 :     if (NCDFGetAttr(m_nLayerCDFId, nVarId, NCDF_FillValue, pdfValue) == CE_None)
     640          40 :         return CE_None;
     641         339 :     return NCDFGetAttr(m_nLayerCDFId, nVarId, "missing_value", pdfValue);
     642             : }
     643             : 
     644             : /************************************************************************/
     645             : /*                       GetNoDataValueForFloat()                       */
     646             : /************************************************************************/
     647             : 
     648           6 : void netCDFLayer::GetNoDataValueForFloat(int nVarId, NCDFNoDataUnion *puNoData)
     649             : {
     650             :     double dfValue;
     651           6 :     if (GetFillValue(nVarId, &dfValue) == CE_None)
     652           2 :         puNoData->fVal = static_cast<float>(dfValue);
     653             :     else
     654           4 :         puNoData->fVal = NC_FILL_FLOAT;
     655           6 : }
     656             : 
     657             : /************************************************************************/
     658             : /*                      GetNoDataValueForDouble()                       */
     659             : /************************************************************************/
     660             : 
     661         161 : void netCDFLayer::GetNoDataValueForDouble(int nVarId, NCDFNoDataUnion *puNoData)
     662             : {
     663             :     double dfValue;
     664         161 :     if (GetFillValue(nVarId, &dfValue) == CE_None)
     665           0 :         puNoData->dfVal = dfValue;
     666             :     else
     667         161 :         puNoData->dfVal = NC_FILL_DOUBLE;
     668         161 : }
     669             : 
     670             : /************************************************************************/
     671             : /*                           GetNoDataValue()                           */
     672             : /************************************************************************/
     673             : 
     674         167 : void netCDFLayer::GetNoDataValue(int nVarId, nc_type nVarType,
     675             :                                  NCDFNoDataUnion *puNoData)
     676             : {
     677         167 :     if (nVarType == NC_DOUBLE)
     678         161 :         GetNoDataValueForDouble(nVarId, puNoData);
     679           6 :     else if (nVarType == NC_FLOAT)
     680           6 :         GetNoDataValueForFloat(nVarId, puNoData);
     681         167 : }
     682             : 
     683             : /************************************************************************/
     684             : /*                             SetXYZVars()                             */
     685             : /************************************************************************/
     686             : 
     687          56 : void netCDFLayer::SetXYZVars(int nXVarId, int nYVarId, int nZVarId)
     688             : {
     689          56 :     m_nXVarID = nXVarId;
     690          56 :     m_nYVarID = nYVarId;
     691          56 :     m_nZVarID = nZVarId;
     692             : 
     693          56 :     nc_inq_vartype(m_nLayerCDFId, m_nXVarID, &m_nXVarNCDFType);
     694          56 :     nc_inq_vartype(m_nLayerCDFId, m_nYVarID, &m_nYVarNCDFType);
     695          56 :     if ((m_nXVarNCDFType != NC_FLOAT && m_nXVarNCDFType != NC_DOUBLE) ||
     696          56 :         (m_nYVarNCDFType != NC_FLOAT && m_nYVarNCDFType != NC_DOUBLE))
     697             :     {
     698           0 :         CPLError(CE_Warning, CPLE_NotSupported,
     699             :                  "X or Y variable of type X=%d,Y=%d not handled",
     700             :                  m_nXVarNCDFType, m_nYVarNCDFType);
     701           0 :         m_nXVarID = -1;
     702           0 :         m_nYVarID = -1;
     703             :     }
     704          56 :     if (m_nZVarID >= 0)
     705             :     {
     706          55 :         nc_inq_vartype(m_nLayerCDFId, m_nZVarID, &m_nZVarNCDFType);
     707          55 :         if (m_nZVarNCDFType != NC_FLOAT && m_nZVarNCDFType != NC_DOUBLE)
     708             :         {
     709           0 :             CPLError(CE_Warning, CPLE_NotSupported,
     710             :                      "Z variable of type %d not handled", m_nZVarNCDFType);
     711           0 :             m_nZVarID = -1;
     712             :         }
     713             :     }
     714             : 
     715          56 :     if (m_nXVarID >= 0 && m_nYVarID >= 0)
     716             :     {
     717             :         char szVarName[NC_MAX_NAME + 1];
     718          56 :         szVarName[0] = '\0';
     719          56 :         CPL_IGNORE_RET_VAL(nc_inq_varname(m_nLayerCDFId, m_nXVarID, szVarName));
     720          56 :         m_osCoordinatesValue = szVarName;
     721             : 
     722          56 :         szVarName[0] = '\0';
     723          56 :         CPL_IGNORE_RET_VAL(nc_inq_varname(m_nLayerCDFId, m_nYVarID, szVarName));
     724          56 :         m_osCoordinatesValue += " ";
     725          56 :         m_osCoordinatesValue += szVarName;
     726             : 
     727          56 :         if (m_nZVarID >= 0)
     728             :         {
     729          55 :             szVarName[0] = '\0';
     730          55 :             CPL_IGNORE_RET_VAL(
     731          55 :                 nc_inq_varname(m_nLayerCDFId, m_nZVarID, szVarName));
     732          55 :             m_osCoordinatesValue += " ";
     733          55 :             m_osCoordinatesValue += szVarName;
     734             :         }
     735             :     }
     736             : 
     737          56 :     if (m_nXVarID >= 0)
     738          56 :         GetNoDataValue(m_nXVarID, m_nXVarNCDFType, &m_uXVarNoData);
     739          56 :     if (m_nYVarID >= 0)
     740          56 :         GetNoDataValue(m_nYVarID, m_nYVarNCDFType, &m_uYVarNoData);
     741          56 :     if (m_nZVarID >= 0)
     742          55 :         GetNoDataValue(m_nZVarID, m_nZVarNCDFType, &m_uZVarNoData);
     743          56 : }
     744             : 
     745             : /************************************************************************/
     746             : /*                        SetWKTGeometryField()                         */
     747             : /************************************************************************/
     748             : 
     749          10 : void netCDFLayer::SetWKTGeometryField(const char *pszWKTVarName)
     750             : {
     751          10 :     m_nWKTVarID = -1;
     752          10 :     nc_inq_varid(m_nLayerCDFId, pszWKTVarName, &m_nWKTVarID);
     753          10 :     if (m_nWKTVarID < 0)
     754           0 :         return;
     755             :     int nd;
     756          10 :     nc_inq_varndims(m_nLayerCDFId, m_nWKTVarID, &nd);
     757          10 :     nc_inq_vartype(m_nLayerCDFId, m_nWKTVarID, &m_nWKTNCDFType);
     758          10 :     if (nd == 1 && m_nWKTNCDFType == NC_STRING)
     759             :     {
     760             :         int nDimID;
     761           4 :         if (nc_inq_vardimid(m_nLayerCDFId, m_nWKTVarID, &nDimID) != NC_NOERR ||
     762           2 :             nDimID != m_nRecordDimID)
     763             :         {
     764           0 :             m_nWKTVarID = -1;
     765           0 :             return;
     766           2 :         }
     767             :     }
     768           8 :     else if (nd == 2 && m_nWKTNCDFType == NC_CHAR)
     769             :     {
     770           8 :         int anDimIds[2] = {-1, -1};
     771           8 :         size_t nLen = 0;
     772           8 :         if (nc_inq_vardimid(m_nLayerCDFId, m_nWKTVarID, anDimIds) != NC_NOERR ||
     773          16 :             anDimIds[0] != m_nRecordDimID ||
     774           8 :             nc_inq_dimlen(m_nLayerCDFId, anDimIds[1], &nLen) != NC_NOERR)
     775             :         {
     776           0 :             m_nWKTVarID = -1;
     777           0 :             return;
     778             :         }
     779           8 :         m_nWKTMaxWidth = static_cast<int>(nLen);
     780           8 :         m_nWKTMaxWidthDimId = anDimIds[1];
     781             :     }
     782             :     else
     783             :     {
     784           0 :         m_nWKTVarID = -1;
     785           0 :         return;
     786             :     }
     787             : 
     788          10 :     m_osWKTVarName = pszWKTVarName;
     789             : }
     790             : 
     791             : /************************************************************************/
     792             : /*                           SetGridMapping()                           */
     793             : /************************************************************************/
     794             : 
     795          21 : void netCDFLayer::SetGridMapping(const char *pszGridMapping)
     796             : {
     797          21 :     m_osGridMapping = pszGridMapping;
     798          21 : }
     799             : 
     800             : /************************************************************************/
     801             : /*                             SetProfile()                             */
     802             : /************************************************************************/
     803             : 
     804         100 : void netCDFLayer::SetProfile(int nProfileDimID, int nParentIndexVarID)
     805             : {
     806         100 :     m_nProfileDimID = nProfileDimID;
     807         100 :     m_nParentIndexVarID = nParentIndexVarID;
     808         100 :     if (m_nProfileDimID >= 0)
     809             :     {
     810             :         char szTemp[NC_MAX_NAME + 1];
     811          35 :         szTemp[0] = 0;
     812          35 :         int status = nc_inq_dimname(m_nLayerCDFId, m_nProfileDimID, szTemp);
     813          35 :         NCDF_ERR(status);
     814          35 :         m_osProfileDimName = szTemp;
     815             : 
     816          35 :         nc_inq_varid(m_nLayerCDFId, m_osProfileDimName, &m_nProfileVarID);
     817          35 :         m_bProfileVarUnlimited = NCDFIsUnlimitedDim(
     818          35 :             m_poDS->eFormat == NCDF_FORMAT_NC4, m_nLayerCDFId, m_nProfileVarID);
     819             :     }
     820         100 : }
     821             : 
     822             : /************************************************************************/
     823             : /*                            ResetReading()                            */
     824             : /************************************************************************/
     825             : 
     826         134 : void netCDFLayer::ResetReading()
     827             : {
     828         134 :     if (!m_bLegacyCreateMode)
     829             :     {
     830           6 :         m_SGeometryFeatInd = 0;
     831             :     }
     832             :     else
     833             :     {
     834         128 :         m_nCurFeatureId = 1;
     835             :     }
     836         134 : }
     837             : 
     838             : /************************************************************************/
     839             : /*                          Get1DVarAsDouble()                          */
     840             : /************************************************************************/
     841             : 
     842         620 : double netCDFLayer::Get1DVarAsDouble(int nVarId, nc_type nVarType,
     843             :                                      size_t nIndex,
     844             :                                      const NCDFNoDataUnion &noDataVal,
     845             :                                      bool *pbIsNoData) const
     846             : {
     847         620 :     double dfVal = 0;
     848         620 :     if (nVarType == NC_DOUBLE)
     849             :     {
     850         609 :         nc_get_var1_double(m_nLayerCDFId, nVarId, &nIndex, &dfVal);
     851         609 :         if (pbIsNoData)
     852         609 :             *pbIsNoData = dfVal == noDataVal.dfVal;
     853             :     }
     854          11 :     else if (nVarType == NC_FLOAT)
     855             :     {
     856          11 :         float fVal = 0.f;
     857          11 :         nc_get_var1_float(m_nLayerCDFId, nVarId, &nIndex, &fVal);
     858          11 :         if (pbIsNoData)
     859          11 :             *pbIsNoData = fVal == noDataVal.fVal;
     860          11 :         dfVal = fVal;
     861             :     }
     862           0 :     else if (pbIsNoData)
     863           0 :         *pbIsNoData = true;
     864         620 :     return dfVal;
     865             : }
     866             : 
     867             : /************************************************************************/
     868             : /*                         GetNextRawFeature()                          */
     869             : /************************************************************************/
     870             : 
     871         773 : OGRFeature *netCDFLayer::GetNextRawFeature()
     872             : {
     873             : 
     874         773 :     if (m_simpleGeometryReader.get() != nullptr)
     875             :     {
     876         497 :         if (m_SGeometryFeatInd >= m_simpleGeometryReader->get_geometry_count())
     877             :         {
     878           5 :             return nullptr;
     879             :         }
     880             : 
     881         492 :         OGRFeature *ft = nullptr;
     882             : 
     883             :         try
     884             :         {
     885         492 :             ft = buildSGeometryFeature(m_SGeometryFeatInd);
     886         492 :             m_SGeometryFeatInd++;
     887             :         }
     888           0 :         catch (nccfdriver::SG_Exception &sge)
     889             :         {
     890           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     891             :                      "An error occurred while retrieving a feature.\n%s",
     892             :                      sge.get_err_msg());
     893             :         }
     894             : 
     895         492 :         return ft;
     896             :     }
     897             : 
     898         276 :     m_poDS->SetDefineMode(false);
     899             : 
     900             :     // In update mode, nc_get_varXXX() doesn't return error if we are
     901             :     // beyond the end of dimension
     902         276 :     size_t nDimLen = 0;
     903         276 :     nc_inq_dimlen(m_nLayerCDFId, m_nRecordDimID, &nDimLen);
     904         276 :     if (m_nCurFeatureId > static_cast<GIntBig>(nDimLen))
     905          56 :         return nullptr;
     906             : 
     907         220 :     OGRFeature *poFeature = new OGRFeature(m_poFeatureDefn);
     908             : 
     909         220 :     if (m_nParentIndexVarID >= 0)
     910             :     {
     911          52 :         int nProfileIdx = 0;
     912          52 :         size_t nIdx = static_cast<size_t>(m_nCurFeatureId - 1);
     913          52 :         int status = nc_get_var1_int(m_nLayerCDFId, m_nParentIndexVarID, &nIdx,
     914             :                                      &nProfileIdx);
     915          52 :         if (status == NC_NOERR && nProfileIdx >= 0)
     916             :         {
     917          52 :             nIdx = static_cast<size_t>(nProfileIdx);
     918          52 :             FillFeatureFromVar(poFeature, m_nProfileDimID, nIdx);
     919             :         }
     920             :     }
     921             : 
     922         220 :     if (!FillFeatureFromVar(poFeature, m_nRecordDimID,
     923         220 :                             static_cast<size_t>(m_nCurFeatureId - 1)))
     924             :     {
     925           0 :         m_nCurFeatureId++;
     926           0 :         delete poFeature;
     927           0 :         return nullptr;
     928             :     }
     929             : 
     930         220 :     poFeature->SetFID(m_nCurFeatureId);
     931         220 :     m_nCurFeatureId++;
     932             : 
     933         220 :     return poFeature;
     934             : }
     935             : 
     936             : /************************************************************************/
     937             : /*                         FillFeatureFromVar()                         */
     938             : /************************************************************************/
     939             : 
     940         786 : bool netCDFLayer::FillFeatureFromVar(OGRFeature *poFeature, int nMainDimId,
     941             :                                      size_t nIndex)
     942             : {
     943             :     size_t anIndex[2];
     944         786 :     anIndex[0] = nIndex;
     945         786 :     anIndex[1] = 0;
     946             : 
     947        6227 :     for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++)
     948             :     {
     949        5441 :         if (m_aoFieldDesc[i].nMainDimId != nMainDimId && m_bLegacyCreateMode)
     950         264 :             continue;
     951             : 
     952        5177 :         switch (m_aoFieldDesc[i].nType)
     953             :         {
     954        1451 :             case NC_CHAR:
     955             :             {
     956        1451 :                 if (m_aoFieldDesc[i].nDimCount == 1)
     957             :                 {
     958         126 :                     char szVal[2] = {0, 0};
     959         126 :                     int status = nc_get_var1_text(
     960         126 :                         m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, szVal);
     961         126 :                     if (status != NC_NOERR)
     962             :                     {
     963           0 :                         NCDF_ERR(status);
     964           0 :                         continue;
     965             :                     }
     966         126 :                     poFeature->SetField(i, szVal);
     967             :                 }
     968             :                 else
     969             :                 {
     970             :                     size_t anCount[2];
     971        1325 :                     anCount[0] = 1;
     972        1325 :                     anCount[1] = 0;
     973        1325 :                     nc_inq_dimlen(m_nLayerCDFId, m_aoFieldDesc[i].nSecDimId,
     974             :                                   &(anCount[1]));
     975        1325 :                     char *pszVal = (char *)CPLCalloc(1, anCount[1] + 1);
     976             :                     int status =
     977        1325 :                         nc_get_vara_text(m_nLayerCDFId, m_aoFieldDesc[i].nVarId,
     978             :                                          anIndex, anCount, pszVal);
     979        1325 :                     if (status != NC_NOERR)
     980             :                     {
     981           0 :                         NCDF_ERR(status);
     982           0 :                         CPLFree(pszVal);
     983           0 :                         continue;
     984             :                     }
     985        1325 :                     poFeature->SetField(i, pszVal);
     986        1325 :                     CPLFree(pszVal);
     987             :                 }
     988        1451 :                 break;
     989             :             }
     990             : 
     991          49 :             case NC_STRING:
     992             :             {
     993          49 :                 char *pszVal = nullptr;
     994          49 :                 int status = nc_get_var1_string(
     995          49 :                     m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &pszVal);
     996          49 :                 if (status != NC_NOERR)
     997             :                 {
     998           0 :                     NCDF_ERR(status);
     999           0 :                     continue;
    1000             :                 }
    1001          49 :                 if (pszVal != nullptr)
    1002             :                 {
    1003          49 :                     poFeature->SetField(i, pszVal);
    1004          49 :                     nc_free_string(1, &pszVal);
    1005             :                 }
    1006          49 :                 break;
    1007             :             }
    1008             : 
    1009         431 :             case NC_BYTE:
    1010             :             {
    1011         431 :                 signed char chVal = 0;
    1012         431 :                 int status = nc_get_var1_schar(
    1013         431 :                     m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &chVal);
    1014         431 :                 if (status != NC_NOERR)
    1015             :                 {
    1016           0 :                     NCDF_ERR(status);
    1017         248 :                     continue;
    1018             :                 }
    1019         431 :                 if (chVal == m_aoFieldDesc[i].uNoData.chVal)
    1020         248 :                     continue;
    1021         183 :                 poFeature->SetField(i, static_cast<int>(chVal));
    1022         183 :                 break;
    1023             :             }
    1024             : 
    1025          32 :             case NC_UBYTE:
    1026             :             {
    1027          32 :                 unsigned char uchVal = 0;
    1028          32 :                 int status = nc_get_var1_uchar(
    1029          32 :                     m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &uchVal);
    1030          32 :                 if (status != NC_NOERR)
    1031             :                 {
    1032           0 :                     NCDF_ERR(status);
    1033          16 :                     continue;
    1034             :                 }
    1035          32 :                 if (uchVal == m_aoFieldDesc[i].uNoData.uchVal)
    1036          16 :                     continue;
    1037          16 :                 poFeature->SetField(i, static_cast<int>(uchVal));
    1038          16 :                 break;
    1039             :             }
    1040             : 
    1041         302 :             case NC_SHORT:
    1042             :             {
    1043         302 :                 short sVal = 0;
    1044         302 :                 int status = nc_get_var1_short(
    1045         302 :                     m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &sVal);
    1046             : 
    1047         302 :                 if (status != NC_NOERR)
    1048             :                 {
    1049           0 :                     NCDF_ERR(status);
    1050         172 :                     continue;
    1051             :                 }
    1052         302 :                 if (sVal == m_aoFieldDesc[i].uNoData.sVal)
    1053         172 :                     continue;
    1054         130 :                 poFeature->SetField(i, static_cast<int>(sVal));
    1055         130 :                 break;
    1056             :             }
    1057             : 
    1058          32 :             case NC_USHORT:
    1059             :             {
    1060          32 :                 unsigned short usVal = 0;
    1061          32 :                 int status = nc_get_var1_ushort(
    1062          32 :                     m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &usVal);
    1063          32 :                 if (status != NC_NOERR)
    1064             :                 {
    1065           0 :                     NCDF_ERR(status);
    1066          16 :                     continue;
    1067             :                 }
    1068          32 :                 if (usVal == m_aoFieldDesc[i].uNoData.usVal)
    1069          16 :                     continue;
    1070          16 :                 poFeature->SetField(i, static_cast<int>(usVal));
    1071          16 :                 break;
    1072             :             }
    1073             : 
    1074         714 :             case NC_INT:
    1075             :             {
    1076         714 :                 int nVal = 0;
    1077         714 :                 int status = nc_get_var1_int(
    1078         714 :                     m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &nVal);
    1079         714 :                 if (status != NC_NOERR)
    1080             :                 {
    1081           0 :                     NCDF_ERR(status);
    1082         218 :                     continue;
    1083             :                 }
    1084         714 :                 if (nVal == m_aoFieldDesc[i].uNoData.nVal)
    1085         218 :                     continue;
    1086         983 :                 if (m_poFeatureDefn->GetFieldDefn(i)->GetType() == OFTDate ||
    1087         487 :                     m_poFeatureDefn->GetFieldDefn(i)->GetType() == OFTDateTime)
    1088             :                 {
    1089             :                     struct tm brokendowntime;
    1090           9 :                     GIntBig nVal64 = static_cast<GIntBig>(nVal);
    1091           9 :                     if (m_aoFieldDesc[i].bIsDays)
    1092           9 :                         nVal64 *= 86400;
    1093           9 :                     CPLUnixTimeToYMDHMS(nVal64, &brokendowntime);
    1094           9 :                     poFeature->SetField(
    1095           9 :                         i, brokendowntime.tm_year + 1900,
    1096           9 :                         brokendowntime.tm_mon + 1, brokendowntime.tm_mday,
    1097             :                         brokendowntime.tm_hour, brokendowntime.tm_min,
    1098           9 :                         static_cast<float>(brokendowntime.tm_sec), 0);
    1099             :                 }
    1100             :                 else
    1101             :                 {
    1102         487 :                     poFeature->SetField(i, nVal);
    1103             :                 }
    1104         496 :                 break;
    1105             :             }
    1106             : 
    1107          32 :             case NC_UINT:
    1108             :             {
    1109          32 :                 unsigned int unVal = 0;
    1110             :                 // nc_get_var1_uint() doesn't work on old netCDF version when
    1111             :                 // the returned value is > INT_MAX
    1112             :                 // https://bugtracking.unidata.ucar.edu/browse/NCF-226
    1113             :                 // nc_get_vara_uint() has not this bug
    1114          32 :                 size_t nCount = 1;
    1115             :                 int status =
    1116          32 :                     nc_get_vara_uint(m_nLayerCDFId, m_aoFieldDesc[i].nVarId,
    1117             :                                      anIndex, &nCount, &unVal);
    1118          32 :                 if (status != NC_NOERR)
    1119             :                 {
    1120           0 :                     NCDF_ERR(status);
    1121          16 :                     continue;
    1122             :                 }
    1123          32 :                 if (unVal == m_aoFieldDesc[i].uNoData.unVal)
    1124          16 :                     continue;
    1125          16 :                 poFeature->SetField(i, static_cast<GIntBig>(unVal));
    1126          16 :                 break;
    1127             :             }
    1128          66 :             case NC_INT64:
    1129             :             {
    1130          66 :                 GIntBig nVal = 0;
    1131          66 :                 int status = nc_get_var1_longlong(
    1132          66 :                     m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &nVal);
    1133          66 :                 if (status != NC_NOERR)
    1134             :                 {
    1135           0 :                     NCDF_ERR(status);
    1136          44 :                     continue;
    1137             :                 }
    1138          66 :                 if (nVal == m_aoFieldDesc[i].uNoData.nVal64)
    1139          44 :                     continue;
    1140          22 :                 poFeature->SetField(i, nVal);
    1141          22 :                 break;
    1142             :             }
    1143             : 
    1144          32 :             case NC_UINT64:
    1145             :             {
    1146          32 :                 GUIntBig nVal = 0;
    1147          32 :                 int status = nc_get_var1_ulonglong(
    1148          32 :                     m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &nVal);
    1149          32 :                 if (status != NC_NOERR)
    1150             :                 {
    1151           0 :                     NCDF_ERR(status);
    1152          24 :                     continue;
    1153             :                 }
    1154          32 :                 if (nVal == m_aoFieldDesc[i].uNoData.unVal64)
    1155          24 :                     continue;
    1156           8 :                 poFeature->SetField(i, static_cast<double>(nVal));
    1157           8 :                 break;
    1158             :             }
    1159             : 
    1160         302 :             case NC_FLOAT:
    1161             :             {
    1162         302 :                 float fVal = 0.f;
    1163         302 :                 int status = nc_get_var1_float(
    1164         302 :                     m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &fVal);
    1165         302 :                 if (status != NC_NOERR)
    1166             :                 {
    1167           0 :                     NCDF_ERR(status);
    1168         172 :                     continue;
    1169             :                 }
    1170         302 :                 if (fVal == m_aoFieldDesc[i].uNoData.fVal)
    1171         172 :                     continue;
    1172         130 :                 poFeature->SetField(i, static_cast<double>(fVal));
    1173         130 :                 break;
    1174             :             }
    1175             : 
    1176        1734 :             case NC_DOUBLE:
    1177             :             {
    1178        1734 :                 double dfVal = 0.0;
    1179        1734 :                 int status = nc_get_var1_double(
    1180        1734 :                     m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &dfVal);
    1181        1734 :                 if (status != NC_NOERR)
    1182             :                 {
    1183           0 :                     NCDF_ERR(status);
    1184         666 :                     continue;
    1185             :                 }
    1186        1734 :                 if (dfVal == m_aoFieldDesc[i].uNoData.dfVal)
    1187         666 :                     continue;
    1188        2081 :                 if (m_poFeatureDefn->GetFieldDefn(i)->GetType() == OFTDate ||
    1189        1013 :                     m_poFeatureDefn->GetFieldDefn(i)->GetType() == OFTDateTime)
    1190             :                 {
    1191         183 :                     if (m_aoFieldDesc[i].bIsDays)
    1192           0 :                         dfVal *= 86400.0;
    1193             :                     struct tm brokendowntime;
    1194         183 :                     GIntBig nVal = static_cast<GIntBig>(floor(dfVal));
    1195         183 :                     CPLUnixTimeToYMDHMS(nVal, &brokendowntime);
    1196         183 :                     poFeature->SetField(
    1197         183 :                         i, brokendowntime.tm_year + 1900,
    1198         183 :                         brokendowntime.tm_mon + 1, brokendowntime.tm_mday,
    1199             :                         brokendowntime.tm_hour, brokendowntime.tm_min,
    1200         183 :                         static_cast<float>(brokendowntime.tm_sec +
    1201         183 :                                            (dfVal - nVal)),
    1202             :                         0);
    1203             :                 }
    1204             :                 else
    1205             :                 {
    1206         885 :                     poFeature->SetField(i, dfVal);
    1207             :                 }
    1208        1068 :                 break;
    1209             :             }
    1210             : 
    1211           0 :             default:
    1212           0 :                 break;
    1213             :         }
    1214             :     }
    1215             : 
    1216             :     // For CF-1.8 simple geometry specifically
    1217             :     // Only need fields to be set here
    1218         786 :     if (!m_bLegacyCreateMode)
    1219         492 :         return true;  // todo: remove this, refactor to allow for CF-1.6 CF-1.8
    1220             :                       // mixed datasets (multi group)
    1221             : 
    1222         701 :     if (m_nXVarID >= 0 && m_nYVarID >= 0 &&
    1223         407 :         (m_osProfileDimName.empty() || nMainDimId == m_nProfileDimID))
    1224             :     {
    1225         229 :         bool bXIsNoData = false;
    1226         458 :         const double dfX = Get1DVarAsDouble(
    1227         229 :             m_nXVarID, m_nXVarNCDFType, anIndex[0], m_uXVarNoData, &bXIsNoData);
    1228         229 :         bool bYIsNoData = false;
    1229         458 :         const double dfY = Get1DVarAsDouble(
    1230         229 :             m_nYVarID, m_nYVarNCDFType, anIndex[0], m_uYVarNoData, &bYIsNoData);
    1231             : 
    1232         229 :         if (!bXIsNoData && !bYIsNoData)
    1233             :         {
    1234         185 :             OGRPoint *poPoint = nullptr;
    1235         185 :             if (m_nZVarID >= 0 && m_osProfileDimName.empty())
    1236             :             {
    1237         110 :                 bool bZIsNoData = false;
    1238             :                 const double dfZ =
    1239         220 :                     Get1DVarAsDouble(m_nZVarID, m_nZVarNCDFType, anIndex[0],
    1240         110 :                                      m_uZVarNoData, &bZIsNoData);
    1241         110 :                 if (bZIsNoData)
    1242          39 :                     poPoint = new OGRPoint(dfX, dfY);
    1243             :                 else
    1244          71 :                     poPoint = new OGRPoint(dfX, dfY, dfZ);
    1245             :             }
    1246             :             else
    1247          75 :                 poPoint = new OGRPoint(dfX, dfY);
    1248         185 :             poPoint->assignSpatialReference(GetSpatialRef());
    1249         185 :             poFeature->SetGeometryDirectly(poPoint);
    1250             :         }
    1251             :     }
    1252          52 :     else if (m_nXVarID >= 0 && m_nYVarID >= 0 && m_nZVarID >= 0 &&
    1253         117 :              !m_osProfileDimName.empty() && nMainDimId == m_nRecordDimID)
    1254             :     {
    1255          52 :         OGRGeometry *poGeom = poFeature->GetGeometryRef();
    1256         104 :         if (poGeom != nullptr &&
    1257          52 :             wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1258             :         {
    1259          52 :             bool bZIsNoData = false;
    1260             :             const double dfZ =
    1261         104 :                 Get1DVarAsDouble(m_nZVarID, m_nZVarNCDFType, anIndex[0],
    1262          52 :                                  m_uZVarNoData, &bZIsNoData);
    1263          52 :             if (!bZIsNoData)
    1264          52 :                 poGeom->toPoint()->setZ(dfZ);
    1265             :         }
    1266             :     }
    1267          13 :     else if (m_nWKTVarID >= 0)
    1268             :     {
    1269          10 :         char *pszWKT = nullptr;
    1270          10 :         if (m_nWKTNCDFType == NC_CHAR)
    1271             :         {
    1272             :             size_t anCount[2];
    1273           7 :             anCount[0] = 1;
    1274           7 :             anCount[1] = m_nWKTMaxWidth;
    1275           7 :             pszWKT = (char *)CPLCalloc(1, anCount[1] + 1);
    1276           7 :             int status = nc_get_vara_text(m_nLayerCDFId, m_nWKTVarID, anIndex,
    1277             :                                           anCount, pszWKT);
    1278           7 :             if (status == NC_EINVALCOORDS || status == NC_EEDGE)
    1279             :             {
    1280           0 :                 CPLFree(pszWKT);
    1281           0 :                 return false;
    1282             :             }
    1283           7 :             if (status != NC_NOERR)
    1284             :             {
    1285           0 :                 NCDF_ERR(status);
    1286           0 :                 CPLFree(pszWKT);
    1287           0 :                 pszWKT = nullptr;
    1288             :             }
    1289             :         }
    1290           3 :         else if (m_nWKTNCDFType == NC_STRING)
    1291             :         {
    1292           3 :             char *pszVal = nullptr;
    1293           3 :             int status = nc_get_var1_string(m_nLayerCDFId, m_nWKTVarID, anIndex,
    1294             :                                             &pszVal);
    1295           3 :             if (status == NC_EINVALCOORDS || status == NC_EEDGE)
    1296             :             {
    1297           0 :                 return false;
    1298             :             }
    1299           3 :             if (status != NC_NOERR)
    1300             :             {
    1301           0 :                 NCDF_ERR(status);
    1302             :             }
    1303           3 :             else if (pszVal != nullptr)
    1304             :             {
    1305           3 :                 pszWKT = CPLStrdup(pszVal);
    1306           3 :                 nc_free_string(1, &pszVal);
    1307             :             }
    1308             :         }
    1309          10 :         if (pszWKT != nullptr)
    1310             :         {
    1311          20 :             auto [poGeom, _] = OGRGeometryFactory::createFromWkt(pszWKT);
    1312          10 :             if (poGeom != nullptr)
    1313             :             {
    1314           6 :                 poGeom->assignSpatialReference(GetSpatialRef());
    1315           6 :                 poFeature->SetGeometry(std::move(poGeom));
    1316             :             }
    1317          10 :             CPLFree(pszWKT);
    1318             :         }
    1319             :     }
    1320             : 
    1321         294 :     return true;
    1322             : }
    1323             : 
    1324             : /************************************************************************/
    1325             : /*                           GetNextFeature()                           */
    1326             : /************************************************************************/
    1327             : 
    1328         773 : OGRFeature *netCDFLayer::GetNextFeature()
    1329             : {
    1330             :     while (true)
    1331             :     {
    1332         773 :         OGRFeature *poFeature = GetNextRawFeature();
    1333         773 :         if (poFeature == nullptr)
    1334          61 :             return nullptr;
    1335             : 
    1336        1457 :         if ((m_poFilterGeom == nullptr ||
    1337        1405 :              FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) &&
    1338         693 :             (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
    1339         669 :             return poFeature;
    1340             : 
    1341          43 :         delete poFeature;
    1342          43 :     }
    1343             : }
    1344             : 
    1345             : /************************************************************************/
    1346             : /*                            GetLayerDefn()                            */
    1347             : /************************************************************************/
    1348             : 
    1349        3351 : const OGRFeatureDefn *netCDFLayer::GetLayerDefn() const
    1350             : {
    1351        3351 :     return m_poFeatureDefn;
    1352             : }
    1353             : 
    1354             : /************************************************************************/
    1355             : /*                           ICreateFeature()                           */
    1356             : /************************************************************************/
    1357             : 
    1358         501 : OGRErr netCDFLayer::ICreateFeature(OGRFeature *poFeature)
    1359             : {
    1360         501 :     m_poDS->SetDefineMode(false);
    1361             : 
    1362         501 :     size_t nFeatureIdx = 0;
    1363         501 :     nc_inq_dimlen(m_nLayerCDFId, m_nRecordDimID, &nFeatureIdx);
    1364             : 
    1365         501 :     if (!m_bLegacyCreateMode)
    1366             :     {
    1367             :         // Detects: append mode
    1368         442 :         if (m_layerSGDefn.get_containerRealID() == nccfdriver::INVALID_VAR_ID)
    1369             :         {
    1370           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    1371             :                      "Append mode is not supported for CF-1.8 datasets.");
    1372           0 :             return OGRERR_UNSUPPORTED_OPERATION;
    1373             :         }
    1374             :     }
    1375             : 
    1376         501 :     if (m_nProfileDimID >= 0)
    1377             :     {
    1378          20 :         size_t nProfileCount = 0;
    1379          20 :         nc_inq_dimlen(m_nLayerCDFId, m_nProfileDimID, &nProfileCount);
    1380             : 
    1381          20 :         OGRFeature *poProfileToLookup = poFeature->Clone();
    1382          20 :         poProfileToLookup->SetFID(-1);
    1383          96 :         for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++)
    1384             :         {
    1385         152 :             if (!(poProfileToLookup->IsFieldSetAndNotNull(i)) ||
    1386          76 :                 m_aoFieldDesc[i].nMainDimId != m_nProfileDimID)
    1387             :             {
    1388          52 :                 poProfileToLookup->UnsetField(i);
    1389          52 :                 continue;
    1390             :             }
    1391             :         }
    1392          20 :         OGRGeometry *poGeom = poProfileToLookup->GetGeometryRef();
    1393          40 :         if (poGeom != nullptr &&
    1394          20 :             wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1395             :         {
    1396          20 :             poGeom->toPoint()->setZ(0);
    1397             :         }
    1398             : 
    1399          20 :         size_t nProfileIdx = 0;
    1400          20 :         bool bFoundProfile = false;
    1401          30 :         for (; nProfileIdx < nProfileCount; nProfileIdx++)
    1402             :         {
    1403          26 :             int nId = NC_FILL_INT;
    1404          26 :             int status = nc_get_var1_int(m_nLayerCDFId, m_nProfileVarID,
    1405             :                                          &nProfileIdx, &nId);
    1406          26 :             NCDF_ERR(status);
    1407          26 :             if (nId == NC_FILL_INT)
    1408          16 :                 break;
    1409             : 
    1410          22 :             OGRFeature *poIterFeature = new OGRFeature(m_poFeatureDefn);
    1411          22 :             if (FillFeatureFromVar(poIterFeature, m_nProfileDimID, nProfileIdx))
    1412             :             {
    1413          22 :                 poGeom = poIterFeature->GetGeometryRef();
    1414          44 :                 if (poGeom != nullptr &&
    1415          22 :                     wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1416             :                 {
    1417          22 :                     poGeom->toPoint()->setZ(0);
    1418             :                 }
    1419          22 :                 if (poIterFeature->Equal(poProfileToLookup))
    1420             :                 {
    1421          12 :                     bFoundProfile = true;
    1422          12 :                     delete poIterFeature;
    1423          12 :                     break;
    1424             :                 }
    1425             :             }
    1426          10 :             delete poIterFeature;
    1427             :         }
    1428             : 
    1429          20 :         if (!bFoundProfile)
    1430             :         {
    1431           8 :             if (!m_bProfileVarUnlimited && nProfileIdx == nProfileCount)
    1432             :             {
    1433           2 :                 size_t nNewSize = 1 + nProfileCount + nProfileCount / 3;
    1434           2 :                 m_poDS->GrowDim(m_nLayerCDFId, m_nProfileDimID, nNewSize);
    1435             :             }
    1436             : 
    1437           8 :             if (!FillVarFromFeature(poProfileToLookup, m_nProfileDimID,
    1438             :                                     nProfileIdx))
    1439             :             {
    1440           0 :                 delete poProfileToLookup;
    1441           0 :                 return OGRERR_FAILURE;
    1442             :             }
    1443             :         }
    1444             : 
    1445          20 :         int nProfileIdIdx = m_poFeatureDefn->GetFieldIndex(m_osProfileDimName);
    1446          36 :         if (nProfileIdIdx < 0 ||
    1447          16 :             m_poFeatureDefn->GetFieldDefn(nProfileIdIdx)->GetType() !=
    1448             :                 OFTInteger)
    1449             :         {
    1450           4 :             int nVal = static_cast<int>(nProfileIdx);
    1451           4 :             int status = nc_put_var1_int(m_nLayerCDFId, m_nProfileVarID,
    1452             :                                          &nProfileIdx, &nVal);
    1453           4 :             NCDF_ERR(status);
    1454             :         }
    1455             : 
    1456          20 :         int nVal = static_cast<int>(nProfileIdx);
    1457          20 :         int status = nc_put_var1_int(m_nLayerCDFId, m_nParentIndexVarID,
    1458             :                                      &nFeatureIdx, &nVal);
    1459          20 :         NCDF_ERR(status);
    1460             : 
    1461          20 :         delete poProfileToLookup;
    1462             :     }
    1463             : 
    1464         501 :     if (!FillVarFromFeature(poFeature, m_nRecordDimID, nFeatureIdx))
    1465           1 :         return OGRERR_FAILURE;
    1466             : 
    1467         500 :     poFeature->SetFID(nFeatureIdx + 1);
    1468             : 
    1469         500 :     return OGRERR_NONE;
    1470             : }
    1471             : 
    1472             : /************************************************************************/
    1473             : /*                         FillVarFromFeature()                         */
    1474             : /************************************************************************/
    1475             : 
    1476         509 : bool netCDFLayer::FillVarFromFeature(OGRFeature *poFeature, int nMainDimId,
    1477             :                                      size_t nIndex)
    1478             : {
    1479             :     size_t anIndex[2];
    1480         509 :     anIndex[0] = nIndex;
    1481         509 :     anIndex[1] = 0;
    1482             : 
    1483        2675 :     for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++)
    1484             :     {
    1485        2166 :         if (m_aoFieldDesc[i].nMainDimId != nMainDimId)
    1486          46 :             continue;
    1487             : 
    1488        2120 :         if (!(poFeature->IsFieldSetAndNotNull(i)) && m_bLegacyCreateMode)
    1489             :         {
    1490         127 :             if (m_bNCDumpCompat && m_aoFieldDesc[i].nType == NC_STRING)
    1491             :             {
    1492           1 :                 const char *pszVal = "";
    1493           1 :                 int status = nc_put_var1_string(
    1494           1 :                     m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &pszVal);
    1495           1 :                 NCDF_ERR(status);
    1496             :             }
    1497         127 :             continue;
    1498             :         }
    1499             : 
    1500        1993 :         int status = NC_NOERR;
    1501        1993 :         switch (m_aoFieldDesc[i].nType)
    1502             :         {
    1503         947 :             case NC_CHAR:
    1504             :             {
    1505         947 :                 const char *pszVal = poFeature->GetFieldAsString(i);
    1506         947 :                 if (m_aoFieldDesc[i].nDimCount == 1)
    1507             :                 {
    1508           7 :                     if (strlen(pszVal) > 1 &&
    1509           0 :                         !m_aoFieldDesc[i].bHasWarnedAboutTruncation)
    1510             :                     {
    1511           0 :                         CPLError(
    1512             :                             CE_Warning, CPLE_AppDefined,
    1513             :                             "Content of field %s exceeded the 1 character "
    1514             :                             "limit and will be truncated",
    1515           0 :                             m_poFeatureDefn->GetFieldDefn(i)->GetNameRef());
    1516           0 :                         m_aoFieldDesc[i].bHasWarnedAboutTruncation = true;
    1517             :                     }
    1518           7 :                     if (m_poDS->HasInfiniteRecordDim())
    1519             :                     {
    1520           7 :                         status = nc_put_var1_text(m_nLayerCDFId,
    1521           7 :                                                   m_aoFieldDesc[i].nVarId,
    1522             :                                                   anIndex, pszVal);
    1523             :                     }
    1524             :                     else
    1525             :                     {
    1526           0 :                         m_poDS->FieldScribe.enqueue_transaction(
    1527           0 :                             nccfdriver::MTPtr(
    1528             :                                 new nccfdriver::OGR_SGFS_NC_Char_Transaction(
    1529           0 :                                     m_aoFieldDesc[i].nVarId, pszVal)));
    1530             :                     }
    1531             :                 }
    1532             :                 else
    1533             :                 {
    1534             :                     size_t anCount[2];
    1535         940 :                     anCount[0] = 1;
    1536         940 :                     anCount[1] = strlen(pszVal);
    1537         940 :                     size_t nWidth = 0;
    1538             : 
    1539         940 :                     if (m_bLegacyCreateMode)
    1540             :                     {
    1541          64 :                         nc_inq_dimlen(m_nLayerCDFId, m_aoFieldDesc[i].nSecDimId,
    1542             :                                       &nWidth);
    1543             :                     }
    1544             :                     else
    1545             :                     {
    1546         876 :                         nWidth =
    1547         876 :                             layerVID.virtualDIDToDim(m_aoFieldDesc[i].nSecDimId)
    1548         876 :                                 .getLen();
    1549             :                     }
    1550             : 
    1551         940 :                     if (anCount[1] > nWidth)
    1552             :                     {
    1553             :                         // Always grow the dim if not writing to WKT- it's
    1554             :                         // rather inexpensive in CF-1.8
    1555             : 
    1556          43 :                         if ((m_bAutoGrowStrings &&
    1557          43 :                              m_poFeatureDefn->GetFieldDefn(i)->GetWidth() ==
    1558          88 :                                  0) ||
    1559           1 :                             !m_bLegacyCreateMode)
    1560             :                         {
    1561          43 :                             size_t nNewSize = anCount[1] + anCount[1] / 3;
    1562             : 
    1563          43 :                             CPLDebug(
    1564             :                                 "GDAL_netCDF", "Growing %s from %u to %u",
    1565          43 :                                 m_poFeatureDefn->GetFieldDefn(i)->GetNameRef(),
    1566             :                                 static_cast<unsigned>(nWidth),
    1567             :                                 static_cast<unsigned>(nNewSize));
    1568             : 
    1569          43 :                             if (m_bLegacyCreateMode)
    1570             :                             {
    1571           8 :                                 m_poDS->GrowDim(m_nLayerCDFId,
    1572           8 :                                                 m_aoFieldDesc[i].nSecDimId,
    1573             :                                                 nNewSize);
    1574             :                             }
    1575             :                             else
    1576             :                             {
    1577          35 :                                 layerVID.nc_resize_vdim(
    1578          35 :                                     m_aoFieldDesc[i].nSecDimId, nNewSize);
    1579             :                             }
    1580             : 
    1581          43 :                             pszVal = poFeature->GetFieldAsString(i);
    1582             :                         }
    1583             :                         else
    1584             :                         {
    1585           1 :                             anCount[1] = nWidth;
    1586           1 :                             if (!m_aoFieldDesc[i].bHasWarnedAboutTruncation)
    1587             :                             {
    1588           1 :                                 CPLError(CE_Warning, CPLE_AppDefined,
    1589             :                                          "Content of field %s exceeded the %u "
    1590             :                                          "character "
    1591             :                                          "limit and will be truncated",
    1592           1 :                                          m_poFeatureDefn->GetFieldDefn(i)
    1593             :                                              ->GetNameRef(),
    1594             :                                          static_cast<unsigned int>(nWidth));
    1595           1 :                                 m_aoFieldDesc[i].bHasWarnedAboutTruncation =
    1596             :                                     true;
    1597             :                             }
    1598             :                         }
    1599             :                     }
    1600             : 
    1601         940 :                     if (m_poDS->HasInfiniteRecordDim())
    1602             :                     {
    1603          64 :                         status = nc_put_vara_text(m_nLayerCDFId,
    1604          64 :                                                   m_aoFieldDesc[i].nVarId,
    1605             :                                                   anIndex, anCount, pszVal);
    1606             :                     }
    1607             :                     else
    1608             :                     {
    1609         876 :                         m_poDS->FieldScribe.enqueue_transaction(
    1610        1752 :                             nccfdriver::MTPtr(
    1611             :                                 new nccfdriver::OGR_SGFS_NC_CharA_Transaction(
    1612         876 :                                     m_aoFieldDesc[i].nVarId, pszVal)));
    1613             :                     }
    1614             :                 }
    1615         947 :                 break;
    1616             :             }
    1617             : 
    1618          34 :             case NC_STRING:
    1619             :             {
    1620          34 :                 const char *pszVal = poFeature->GetFieldAsString(i);
    1621             : 
    1622          34 :                 if (m_poDS->HasInfiniteRecordDim())
    1623             :                 {
    1624          20 :                     status = nc_put_var1_string(m_nLayerCDFId,
    1625          20 :                                                 m_aoFieldDesc[i].nVarId,
    1626             :                                                 anIndex, &pszVal);
    1627             :                 }
    1628             : 
    1629             :                 else
    1630             :                 {
    1631          14 :                     m_poDS->FieldScribe.enqueue_transaction(nccfdriver::MTPtr(
    1632             :                         new nccfdriver::OGR_SGFS_NC_String_Transaction(
    1633          14 :                             m_aoFieldDesc[i].nVarId, pszVal)));
    1634             :                 }
    1635             : 
    1636          34 :                 break;
    1637             :             }
    1638             : 
    1639          16 :             case NC_BYTE:
    1640             :             {
    1641          16 :                 int nVal = poFeature->GetFieldAsInteger(i);
    1642          16 :                 signed char chVal = static_cast<signed char>(nVal);
    1643             : 
    1644          16 :                 if (m_poDS->HasInfiniteRecordDim())
    1645             :                 {
    1646          16 :                     status = nc_put_var1_schar(m_nLayerCDFId,
    1647          16 :                                                m_aoFieldDesc[i].nVarId, anIndex,
    1648             :                                                &chVal);
    1649             :                 }
    1650             : 
    1651             :                 else
    1652             :                 {
    1653           0 :                     m_poDS->FieldScribe.enqueue_transaction(nccfdriver::MTPtr(
    1654             :                         new nccfdriver::OGR_SGFS_NC_Byte_Transaction(
    1655           0 :                             m_aoFieldDesc[i].nVarId, chVal)));
    1656             :                 }
    1657          16 :                 break;
    1658             :             }
    1659             : 
    1660           4 :             case NC_UBYTE:
    1661             :             {
    1662           4 :                 int nVal = poFeature->GetFieldAsInteger(i);
    1663           4 :                 unsigned char uchVal = static_cast<unsigned char>(nVal);
    1664             : 
    1665           4 :                 if (m_poDS->HasInfiniteRecordDim())
    1666             :                 {
    1667           4 :                     status = nc_put_var1_uchar(m_nLayerCDFId,
    1668           4 :                                                m_aoFieldDesc[i].nVarId, anIndex,
    1669             :                                                &uchVal);
    1670             :                 }
    1671             : 
    1672             :                 else
    1673             :                 {
    1674           0 :                     m_poDS->FieldScribe.enqueue_transaction(nccfdriver::MTPtr(
    1675             :                         new nccfdriver::OGR_SGFS_NC_UByte_Transaction(
    1676           0 :                             m_aoFieldDesc[i].nVarId, uchVal)));
    1677             :                 }
    1678           4 :                 break;
    1679             :             }
    1680             : 
    1681          15 :             case NC_SHORT:
    1682             :             {
    1683          15 :                 int nVal = poFeature->GetFieldAsInteger(i);
    1684          15 :                 short sVal = static_cast<short>(nVal);
    1685             : 
    1686          15 :                 if (m_poDS->HasInfiniteRecordDim())
    1687             :                 {
    1688          14 :                     status = nc_put_var1_short(
    1689          14 :                         m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &sVal);
    1690             :                 }
    1691             :                 else
    1692             :                 {
    1693           1 :                     m_poDS->FieldScribe.enqueue_transaction(nccfdriver::MTPtr(
    1694             :                         new nccfdriver::OGR_SGFS_NC_Short_Transaction(
    1695           1 :                             m_aoFieldDesc[i].nVarId, sVal)));
    1696             :                 }
    1697          15 :                 break;
    1698             :             }
    1699             : 
    1700           4 :             case NC_USHORT:
    1701             :             {
    1702           4 :                 int nVal = poFeature->GetFieldAsInteger(i);
    1703           4 :                 unsigned short usVal = static_cast<unsigned short>(nVal);
    1704             : 
    1705           4 :                 if (m_poDS->HasInfiniteRecordDim())
    1706             :                 {
    1707           4 :                     status = nc_put_var1_ushort(m_nLayerCDFId,
    1708           4 :                                                 m_aoFieldDesc[i].nVarId,
    1709             :                                                 anIndex, &usVal);
    1710             :                 }
    1711             :                 else
    1712             :                 {
    1713           0 :                     m_poDS->FieldScribe.enqueue_transaction(nccfdriver::MTPtr(
    1714             :                         new nccfdriver::OGR_SGFS_NC_UShort_Transaction(
    1715           0 :                             m_aoFieldDesc[i].nVarId, usVal)));
    1716             :                 }
    1717             : 
    1718           4 :                 break;
    1719             :             }
    1720             : 
    1721         270 :             case NC_INT:
    1722             :             {
    1723             :                 int nVal;
    1724         270 :                 if (m_poFeatureDefn->GetFieldDefn(i)->GetType() == OFTDate)
    1725             :                 {
    1726             :                     int nYear;
    1727             :                     int nMonth;
    1728             :                     int nDay;
    1729             :                     int nHour;
    1730             :                     int nMinute;
    1731             :                     float fSecond;
    1732             :                     int nTZ;
    1733           5 :                     poFeature->GetFieldAsDateTime(i, &nYear, &nMonth, &nDay,
    1734             :                                                   &nHour, &nMinute, &fSecond,
    1735             :                                                   &nTZ);
    1736             :                     struct tm brokendowntime;
    1737           5 :                     brokendowntime.tm_year = nYear - 1900;
    1738           5 :                     brokendowntime.tm_mon = nMonth - 1;
    1739           5 :                     brokendowntime.tm_mday = nDay;
    1740           5 :                     brokendowntime.tm_hour = 0;
    1741           5 :                     brokendowntime.tm_min = 0;
    1742           5 :                     brokendowntime.tm_sec = 0;
    1743           5 :                     GIntBig nVal64 = CPLYMDHMSToUnixTime(&brokendowntime);
    1744           5 :                     if (m_aoFieldDesc[i].bIsDays)
    1745           5 :                         nVal64 /= 86400;
    1746           5 :                     nVal = static_cast<int>(nVal64);
    1747             :                 }
    1748             :                 else
    1749             :                 {
    1750         265 :                     nVal = poFeature->GetFieldAsInteger(i);
    1751             :                 }
    1752             : 
    1753         270 :                 if (m_poDS->HasInfiniteRecordDim())
    1754             :                 {
    1755          62 :                     status = nc_put_var1_int(
    1756          62 :                         m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &nVal);
    1757             :                 }
    1758             :                 else
    1759             :                 {
    1760         208 :                     m_poDS->FieldScribe.enqueue_transaction(nccfdriver::MTPtr(
    1761             :                         new nccfdriver::OGR_SGFS_NC_Int_Transaction(
    1762         208 :                             m_aoFieldDesc[i].nVarId, nVal)));
    1763             :                 }
    1764             : 
    1765         270 :                 break;
    1766             :             }
    1767             : 
    1768           4 :             case NC_UINT:
    1769             :             {
    1770           4 :                 GIntBig nVal = poFeature->GetFieldAsInteger64(i);
    1771           4 :                 unsigned int unVal = static_cast<unsigned int>(nVal);
    1772             : 
    1773           4 :                 if (m_poDS->HasInfiniteRecordDim())
    1774             :                 {
    1775             :                     status =
    1776           4 :                         nc_put_var1_uint(m_nLayerCDFId, m_aoFieldDesc[i].nVarId,
    1777             :                                          anIndex, &unVal);
    1778             :                 }
    1779             :                 else
    1780             :                 {
    1781           0 :                     m_poDS->FieldScribe.enqueue_transaction(nccfdriver::MTPtr(
    1782             :                         new nccfdriver::OGR_SGFS_NC_UInt_Transaction(
    1783           0 :                             m_aoFieldDesc[i].nVarId, unVal)));
    1784             :                 }
    1785             : 
    1786           4 :                 break;
    1787             :             }
    1788             : 
    1789          18 :             case NC_INT64:
    1790             :             {
    1791          18 :                 GIntBig nVal = poFeature->GetFieldAsInteger64(i);
    1792          18 :                 if (m_poDS->HasInfiniteRecordDim())
    1793             :                 {
    1794          18 :                     status = nc_put_var1_longlong(
    1795          18 :                         m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &nVal);
    1796             :                 }
    1797             :                 else
    1798             :                 {
    1799           0 :                     m_poDS->FieldScribe.enqueue_transaction(nccfdriver::MTPtr(
    1800             :                         new nccfdriver::OGR_SGFS_NC_Int64_Transaction(
    1801           0 :                             m_aoFieldDesc[i].nVarId, nVal)));
    1802             :                 }
    1803          18 :                 break;
    1804             :             }
    1805             : 
    1806           2 :             case NC_UINT64:
    1807             :             {
    1808           2 :                 double dfVal = poFeature->GetFieldAsDouble(i);
    1809           2 :                 GUIntBig nVal = static_cast<GUIntBig>(dfVal);
    1810             : 
    1811           2 :                 if (m_poDS->HasInfiniteRecordDim())
    1812             :                 {
    1813           2 :                     status = nc_put_var1_ulonglong(
    1814           2 :                         m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &nVal);
    1815             :                 }
    1816             :                 else
    1817             :                 {
    1818           0 :                     m_poDS->FieldScribe.enqueue_transaction(nccfdriver::MTPtr(
    1819             :                         new nccfdriver::OGR_SGFS_NC_UInt64_Transaction(
    1820           0 :                             m_aoFieldDesc[i].nVarId, nVal)));
    1821             :                 }
    1822             : 
    1823           2 :                 break;
    1824             :             }
    1825             : 
    1826          15 :             case NC_FLOAT:
    1827             :             {
    1828          15 :                 double dfVal = poFeature->GetFieldAsDouble(i);
    1829          15 :                 float fVal = static_cast<float>(dfVal);
    1830             : 
    1831          15 :                 if (m_poDS->HasInfiniteRecordDim())
    1832             :                 {
    1833          14 :                     status = nc_put_var1_float(
    1834          14 :                         m_nLayerCDFId, m_aoFieldDesc[i].nVarId, anIndex, &fVal);
    1835             :                 }
    1836             :                 else
    1837             :                 {
    1838           1 :                     m_poDS->FieldScribe.enqueue_transaction(nccfdriver::MTPtr(
    1839             :                         new nccfdriver::OGR_SGFS_NC_Float_Transaction(
    1840           1 :                             m_aoFieldDesc[i].nVarId, fVal)));
    1841             :                 }
    1842             : 
    1843          15 :                 break;
    1844             :             }
    1845             : 
    1846         664 :             case NC_DOUBLE:
    1847             :             {
    1848             :                 double dfVal;
    1849        1326 :                 if (m_poFeatureDefn->GetFieldDefn(i)->GetType() == OFTDate ||
    1850         662 :                     m_poFeatureDefn->GetFieldDefn(i)->GetType() == OFTDateTime)
    1851             :                 {
    1852             :                     int nYear;
    1853             :                     int nMonth;
    1854             :                     int nDay;
    1855             :                     int nHour;
    1856             :                     int nMinute;
    1857             :                     float fSecond;
    1858             :                     int nTZ;
    1859          16 :                     poFeature->GetFieldAsDateTime(i, &nYear, &nMonth, &nDay,
    1860             :                                                   &nHour, &nMinute, &fSecond,
    1861             :                                                   &nTZ);
    1862             :                     struct tm brokendowntime;
    1863          16 :                     brokendowntime.tm_year = nYear - 1900;
    1864          16 :                     brokendowntime.tm_mon = nMonth - 1;
    1865          16 :                     brokendowntime.tm_mday = nDay;
    1866          16 :                     brokendowntime.tm_hour = nHour;
    1867          16 :                     brokendowntime.tm_min = nMinute;
    1868          16 :                     brokendowntime.tm_sec = static_cast<int>(fSecond);
    1869          16 :                     GIntBig nVal = CPLYMDHMSToUnixTime(&brokendowntime);
    1870          16 :                     dfVal = static_cast<double>(nVal) + fmod(fSecond, 1.0f);
    1871          16 :                     if (m_aoFieldDesc[i].bIsDays)
    1872           0 :                         dfVal /= 86400.0;
    1873             :                 }
    1874             :                 else
    1875             :                 {
    1876         648 :                     dfVal = poFeature->GetFieldAsDouble(i);
    1877             :                 }
    1878             : 
    1879         664 :                 if (m_poDS->HasInfiniteRecordDim())
    1880             :                 {
    1881          75 :                     status = nc_put_var1_double(m_nLayerCDFId,
    1882          75 :                                                 m_aoFieldDesc[i].nVarId,
    1883             :                                                 anIndex, &dfVal);
    1884             :                 }
    1885             :                 else
    1886             :                 {
    1887         589 :                     m_poDS->FieldScribe.enqueue_transaction(nccfdriver::MTPtr(
    1888             :                         new nccfdriver::OGR_SGFS_NC_Double_Transaction(
    1889         589 :                             m_aoFieldDesc[i].nVarId, dfVal)));
    1890             :                 }
    1891             : 
    1892         664 :                 break;
    1893             :             }
    1894             : 
    1895           0 :             default:
    1896           0 :                 break;
    1897             :         }
    1898             : 
    1899        1993 :         NCDF_ERR(status);
    1900        1993 :         if (status != NC_NOERR)
    1901             :         {
    1902           0 :             return false;
    1903             :         }
    1904             :     }
    1905             : 
    1906         509 :     OGRGeometry *poGeom = poFeature->GetGeometryRef();
    1907         583 :     if (wkbFlatten(m_poFeatureDefn->GetGeomType()) == wkbPoint &&
    1908          71 :         poGeom != nullptr &&
    1909         654 :         wkbFlatten(poGeom->getGeometryType()) == wkbPoint &&
    1910          71 :         m_bLegacyCreateMode)
    1911             :     {
    1912          38 :         if (m_osProfileDimName.empty() || nMainDimId == m_nProfileDimID)
    1913             :         {
    1914          18 :             auto poPoint = poGeom->toPoint();
    1915          18 :             double dfX = poPoint->getX();
    1916          18 :             double dfY = poPoint->getY();
    1917             : 
    1918             :             int status;
    1919             : 
    1920          18 :             if (m_nXVarNCDFType == NC_DOUBLE)
    1921             :                 status =
    1922          18 :                     nc_put_var1_double(m_nLayerCDFId, m_nXVarID, anIndex, &dfX);
    1923             :             else
    1924             :             {
    1925           0 :                 float fX = static_cast<float>(dfX);
    1926             :                 status =
    1927           0 :                     nc_put_var1_float(m_nLayerCDFId, m_nXVarID, anIndex, &fX);
    1928             :             }
    1929          18 :             NCDF_ERR(status);
    1930          18 :             if (status != NC_NOERR)
    1931             :             {
    1932           0 :                 return false;
    1933             :             }
    1934             : 
    1935          18 :             if (m_nYVarNCDFType == NC_DOUBLE)
    1936             :                 status =
    1937          18 :                     nc_put_var1_double(m_nLayerCDFId, m_nYVarID, anIndex, &dfY);
    1938             :             else
    1939             :             {
    1940           0 :                 float fY = static_cast<float>(dfY);
    1941             :                 status =
    1942           0 :                     nc_put_var1_float(m_nLayerCDFId, m_nYVarID, anIndex, &fY);
    1943             :             }
    1944          18 :             NCDF_ERR(status);
    1945          18 :             if (status != NC_NOERR)
    1946             :             {
    1947           0 :                 return false;
    1948             :             }
    1949             :         }
    1950             : 
    1951         104 :         if (m_poFeatureDefn->GetGeomType() == wkbPoint25D &&
    1952          66 :             (m_osProfileDimName.empty() || nMainDimId == m_nRecordDimID))
    1953             :         {
    1954             :             int status;
    1955          30 :             double dfZ = poGeom->toPoint()->getZ();
    1956          30 :             if (m_nZVarNCDFType == NC_DOUBLE)
    1957             :                 status =
    1958          30 :                     nc_put_var1_double(m_nLayerCDFId, m_nZVarID, anIndex, &dfZ);
    1959             :             else
    1960             :             {
    1961           0 :                 float fZ = static_cast<float>(dfZ);
    1962             :                 status =
    1963           0 :                     nc_put_var1_float(m_nLayerCDFId, m_nZVarID, anIndex, &fZ);
    1964             :             }
    1965          30 :             NCDF_ERR(status);
    1966          30 :             if (status != NC_NOERR)
    1967             :             {
    1968           0 :                 return false;
    1969             :             }
    1970             :         }
    1971             :     }
    1972         940 :     else if (m_poFeatureDefn->GetGeomType() != wkbNone && m_nWKTVarID >= 0 &&
    1973         940 :              poGeom != nullptr && m_bLegacyCreateMode)
    1974             :     {
    1975          21 :         OGRWktOptions opts;
    1976          21 :         opts.variant = wkbVariantIso;
    1977             : 
    1978          21 :         std::string osWKT = poGeom->exportToWkt(opts);
    1979          21 :         int status = NC_NOERR;
    1980          21 :         if (m_nWKTNCDFType == NC_STRING)
    1981             :         {
    1982          10 :             const char *pszWKTConst = osWKT.c_str();
    1983          10 :             status = nc_put_var1_string(m_nLayerCDFId, m_nWKTVarID, anIndex,
    1984             :                                         &pszWKTConst);
    1985             :         }
    1986             :         else
    1987             :         {
    1988             :             size_t anCount[2];
    1989          11 :             anCount[0] = 1;
    1990          11 :             anCount[1] = osWKT.size();
    1991          11 :             if (anCount[1] > static_cast<unsigned int>(m_nWKTMaxWidth))
    1992             :             {
    1993           4 :                 if (m_bAutoGrowStrings)
    1994             :                 {
    1995           3 :                     size_t nNewSize = anCount[1] + anCount[1] / 3;
    1996             : 
    1997           3 :                     CPLDebug("GDAL_netCDF", "Growing %s from %u to %u",
    1998             :                              m_osWKTVarName.c_str(),
    1999           3 :                              static_cast<unsigned>(m_nWKTMaxWidth),
    2000             :                              static_cast<unsigned>(nNewSize));
    2001           3 :                     m_poDS->GrowDim(m_nLayerCDFId, m_nWKTMaxWidthDimId,
    2002             :                                     nNewSize);
    2003             : 
    2004           3 :                     m_nWKTMaxWidth = static_cast<int>(nNewSize);
    2005             : 
    2006           3 :                     status = nc_put_vara_text(m_nLayerCDFId, m_nWKTVarID,
    2007             :                                               anIndex, anCount, osWKT.c_str());
    2008             :                 }
    2009             :                 else
    2010             :                 {
    2011           1 :                     CPLError(CE_Failure, CPLE_AppDefined,
    2012             :                              "Cannot write geometry as WKT. Would require %d "
    2013             :                              "characters but field width is %d",
    2014           1 :                              static_cast<int>(anCount[1]), m_nWKTMaxWidth);
    2015           1 :                     status =
    2016             :                         NC_EEDGE;  // error that would be returned had we called nc_put_var_text
    2017             :                 }
    2018             :             }
    2019             :             else
    2020             :             {
    2021           7 :                 status = nc_put_vara_text(m_nLayerCDFId, m_nWKTVarID, anIndex,
    2022             :                                           anCount, osWKT.c_str());
    2023             :             }
    2024             :         }
    2025          21 :         NCDF_ERR(status);
    2026          21 :         if (status != NC_NOERR)
    2027             :         {
    2028           1 :             return false;
    2029             :         }
    2030             :     }
    2031         898 :     else if (m_poFeatureDefn->GetGeomType() != wkbNone && m_nWKTVarID >= 0 &&
    2032           3 :              poGeom == nullptr && m_nWKTNCDFType == NC_STRING &&
    2033         898 :              m_bNCDumpCompat && m_bLegacyCreateMode)
    2034             :     {
    2035           1 :         const char *pszWKTConst = "";
    2036           1 :         int status = nc_put_var1_string(m_nLayerCDFId, m_nWKTVarID, anIndex,
    2037             :                                         &pszWKTConst);
    2038           1 :         NCDF_ERR(status);
    2039             :     }
    2040             : 
    2041             :     try
    2042             :     {
    2043             :         // CF 1.8 simple geometry, only
    2044         508 :         if (!m_bLegacyCreateMode && poGeom != nullptr)
    2045             :         {
    2046         884 :             nccfdriver::SGeometry_Feature featWithMetaData(*poFeature);
    2047             : 
    2048             :             // Check if ready to dump buffer to LOG
    2049         442 :             if (m_poDS->bufManager.isOverQuota())
    2050             :             {
    2051         180 :                 m_poDS->SGLogPendingTransaction();
    2052             :             }
    2053             : 
    2054             :             // Finally, "write" the feature
    2055         442 :             m_layerSGDefn.writeSGeometryFeature(featWithMetaData);
    2056             :         }
    2057             :     }
    2058             : 
    2059           0 :     catch (nccfdriver::SG_Exception &sge)
    2060             :     {
    2061           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2062             :                  "An error occurred while attempting to write a feature to the "
    2063             :                  "target netCDF file.\n%s",
    2064             :                  sge.get_err_msg());
    2065           0 :         return false;
    2066             :     }
    2067             : 
    2068         508 :     return true;
    2069             : }
    2070             : 
    2071             : /************************************************************************/
    2072             : /*                              AddField()                              */
    2073             : /************************************************************************/
    2074             : 
    2075         743 : bool netCDFLayer::AddField(int nVarID)
    2076             : {
    2077         743 :     if (nVarID == m_nWKTVarID)
    2078          10 :         return false;
    2079             : 
    2080             :     char szName[NC_MAX_NAME + 1];
    2081         733 :     szName[0] = '\0';
    2082         733 :     CPL_IGNORE_RET_VAL(nc_inq_varname(m_nLayerCDFId, nVarID, szName));
    2083             : 
    2084         733 :     nc_type vartype = NC_NAT;
    2085         733 :     nc_inq_vartype(m_nLayerCDFId, nVarID, &vartype);
    2086             : 
    2087         733 :     OGRFieldType eType = OFTString;
    2088         733 :     OGRFieldSubType eSubType = OFSTNone;
    2089         733 :     int nWidth = 0;
    2090             : 
    2091             :     NCDFNoDataUnion nodata;
    2092         733 :     memset(&nodata, 0, sizeof(nodata));
    2093         733 :     int nDimCount = 1;
    2094         733 :     nc_inq_varndims(m_nLayerCDFId, nVarID, &nDimCount);
    2095         733 :     int anDimIds[2] = {-1, -1};
    2096         733 :     if ((vartype == NC_CHAR && nDimCount <= 2) ||
    2097         552 :         (vartype != NC_CHAR && nDimCount == 1))
    2098             :     {
    2099         733 :         nc_inq_vardimid(m_nLayerCDFId, nVarID, anDimIds);
    2100             :     }
    2101             :     else
    2102             :     {
    2103           0 :         return false;
    2104             :     }
    2105             : 
    2106         733 :     switch (vartype)
    2107             :     {
    2108          47 :         case NC_BYTE:
    2109             :         {
    2110          47 :             eType = OFTInteger;
    2111          47 :             char *pszValue = nullptr;
    2112          47 :             if (GetFillValue(nVarID, &pszValue) == CE_None)
    2113          11 :                 nodata.chVal = static_cast<signed char>(atoi(pszValue));
    2114             :             else
    2115          36 :                 nodata.chVal = NC_FILL_BYTE;
    2116          47 :             CPLFree(pszValue);
    2117          47 :             break;
    2118             :         }
    2119             : 
    2120          12 :         case NC_UBYTE:
    2121             :         {
    2122          12 :             eType = OFTInteger;
    2123          12 :             char *pszValue = nullptr;
    2124          12 :             if (GetFillValue(nVarID, &pszValue) == CE_None)
    2125           6 :                 nodata.uchVal = static_cast<unsigned char>(atoi(pszValue));
    2126             :             else
    2127           6 :                 nodata.uchVal = NC_FILL_UBYTE;
    2128          12 :             CPLFree(pszValue);
    2129          12 :             break;
    2130             :         }
    2131             : 
    2132         181 :         case NC_CHAR:
    2133             :         {
    2134         181 :             eType = OFTString;
    2135         181 :             if (nDimCount == 1)
    2136             :             {
    2137           9 :                 nWidth = 1;
    2138             :             }
    2139         172 :             else if (nDimCount == 2)
    2140             :             {
    2141         172 :                 size_t nDimLen = 0;
    2142         172 :                 nc_inq_dimlen(m_nLayerCDFId, anDimIds[1], &nDimLen);
    2143         172 :                 nWidth = static_cast<int>(nDimLen);
    2144             :             }
    2145         181 :             break;
    2146             :         }
    2147             : 
    2148          20 :         case NC_STRING:
    2149             :         {
    2150          20 :             eType = OFTString;
    2151          20 :             break;
    2152             :         }
    2153             : 
    2154          38 :         case NC_SHORT:
    2155             :         {
    2156          38 :             eType = OFTInteger;
    2157          38 :             eSubType = OFSTInt16;
    2158          38 :             char *pszValue = nullptr;
    2159          38 :             if (GetFillValue(nVarID, &pszValue) == CE_None)
    2160          11 :                 nodata.sVal = static_cast<short>(atoi(pszValue));
    2161             :             else
    2162          27 :                 nodata.sVal = NC_FILL_SHORT;
    2163          38 :             CPLFree(pszValue);
    2164          38 :             break;
    2165             :         }
    2166             : 
    2167          12 :         case NC_USHORT:
    2168             :         {
    2169          12 :             eType = OFTInteger;
    2170          12 :             char *pszValue = nullptr;
    2171          12 :             if (GetFillValue(nVarID, &pszValue) == CE_None)
    2172           6 :                 nodata.usVal = static_cast<unsigned short>(atoi(pszValue));
    2173             :             else
    2174           6 :                 nodata.usVal = NC_FILL_USHORT;
    2175          12 :             CPLFree(pszValue);
    2176          12 :             break;
    2177             :         }
    2178             : 
    2179         161 :         case NC_INT:
    2180             :         {
    2181         161 :             eType = OFTInteger;
    2182         161 :             char *pszValue = nullptr;
    2183         161 :             if (GetFillValue(nVarID, &pszValue) == CE_None)
    2184          15 :                 nodata.nVal = atoi(pszValue);
    2185             :             else
    2186         146 :                 nodata.nVal = NC_FILL_INT;
    2187         161 :             CPLFree(pszValue);
    2188         161 :             break;
    2189             :         }
    2190             : 
    2191          12 :         case NC_UINT:
    2192             :         {
    2193          12 :             eType = OFTInteger64;
    2194          12 :             char *pszValue = nullptr;
    2195          12 :             if (GetFillValue(nVarID, &pszValue) == CE_None)
    2196           6 :                 nodata.unVal =
    2197           6 :                     static_cast<unsigned int>(CPLAtoGIntBig(pszValue));
    2198             :             else
    2199           6 :                 nodata.unVal = NC_FILL_UINT;
    2200          12 :             CPLFree(pszValue);
    2201          12 :             break;
    2202             :         }
    2203             : 
    2204          26 :         case NC_INT64:
    2205             :         {
    2206          26 :             eType = OFTInteger64;
    2207          26 :             char *pszValue = nullptr;
    2208          26 :             if (GetFillValue(nVarID, &pszValue) == CE_None)
    2209           6 :                 nodata.nVal64 = CPLAtoGIntBig(pszValue);
    2210             :             else
    2211          20 :                 nodata.nVal64 = NC_FILL_INT64;
    2212          26 :             CPLFree(pszValue);
    2213          26 :             break;
    2214             :         }
    2215             : 
    2216          12 :         case NC_UINT64:
    2217             :         {
    2218          12 :             eType = OFTReal;
    2219          12 :             char *pszValue = nullptr;
    2220          12 :             if (GetFillValue(nVarID, &pszValue) == CE_None)
    2221             :             {
    2222           6 :                 nodata.unVal64 = 0;
    2223         126 :                 for (int i = 0; pszValue[i] != '\0'; i++)
    2224             :                 {
    2225         120 :                     nodata.unVal64 = nodata.unVal64 * 10 + (pszValue[i] - '0');
    2226             :                 }
    2227             :             }
    2228             :             else
    2229           6 :                 nodata.unVal64 = NC_FILL_UINT64;
    2230          12 :             CPLFree(pszValue);
    2231          12 :             break;
    2232             :         }
    2233             : 
    2234          38 :         case NC_FLOAT:
    2235             :         {
    2236          38 :             eType = OFTReal;
    2237          38 :             eSubType = OFSTFloat32;
    2238             :             double dfValue;
    2239          38 :             if (GetFillValue(nVarID, &dfValue) == CE_None)
    2240          11 :                 nodata.fVal = static_cast<float>(dfValue);
    2241             :             else
    2242          27 :                 nodata.fVal = NC_FILL_FLOAT;
    2243          38 :             break;
    2244             :         }
    2245             : 
    2246         174 :         case NC_DOUBLE:
    2247             :         {
    2248         174 :             eType = OFTReal;
    2249             :             double dfValue;
    2250         174 :             if (GetFillValue(nVarID, &dfValue) == CE_None)
    2251          31 :                 nodata.dfVal = dfValue;
    2252             :             else
    2253         143 :                 nodata.dfVal = NC_FILL_DOUBLE;
    2254         174 :             break;
    2255             :         }
    2256             : 
    2257           0 :         default:
    2258             :         {
    2259           0 :             CPLDebug("GDAL_netCDF",
    2260             :                      "Variable %s has type %d, which is unhandled", szName,
    2261             :                      vartype);
    2262           0 :             return false;
    2263             :         }
    2264             :     }
    2265             : 
    2266         733 :     bool bIsDays = false;
    2267             : 
    2268         733 :     char *pszValue = nullptr;
    2269         733 :     if (NCDFGetAttr(m_nLayerCDFId, nVarID, "ogr_field_type", &pszValue) ==
    2270             :         CE_None)
    2271             :     {
    2272         491 :         if ((eType == OFTInteger || eType == OFTReal) &&
    2273         299 :             EQUAL(pszValue, "Date"))
    2274             :         {
    2275          17 :             eType = OFTDate;
    2276             :             // cppcheck-suppress knownConditionTrueFalse
    2277          17 :             bIsDays = (eType == OFTInteger);
    2278             :         }
    2279         474 :         else if ((eType == OFTInteger || eType == OFTReal) &&
    2280         282 :                  EQUAL(pszValue, "DateTime"))
    2281          23 :             eType = OFTDateTime;
    2282         451 :         else if (eType == OFTReal && EQUAL(pszValue, "Integer64"))
    2283          21 :             eType = OFTInteger64;
    2284         430 :         else if (eType == OFTInteger && EQUAL(pszValue, "Integer(Boolean)"))
    2285          34 :             eSubType = OFSTBoolean;
    2286             :     }
    2287         733 :     CPLFree(pszValue);
    2288             : 
    2289         733 :     if (NCDFGetAttr(m_nLayerCDFId, nVarID, "units", &pszValue) == CE_None)
    2290             :     {
    2291         110 :         if ((eType == OFTInteger || eType == OFTReal || eType == OFTDate) &&
    2292          63 :             (EQUAL(pszValue, "seconds since 1970-1-1 0:0:0") ||
    2293          39 :              EQUAL(pszValue, "seconds since 1970-01-01 00:00:00")))
    2294             :         {
    2295          24 :             if (eType != OFTDate)
    2296          13 :                 eType = OFTDateTime;
    2297          24 :             bIsDays = false;
    2298             :         }
    2299          86 :         else if ((eType == OFTInteger || eType == OFTReal ||
    2300          39 :                   eType == OFTDate) &&
    2301          39 :                  (EQUAL(pszValue, "days since 1970-1-1") ||
    2302          32 :                   EQUAL(pszValue, "days since 1970-01-01")))
    2303             :         {
    2304           7 :             eType = OFTDate;
    2305           7 :             bIsDays = true;
    2306             :         }
    2307             :     }
    2308         733 :     CPLFree(pszValue);
    2309             : 
    2310         733 :     if (NCDFGetAttr(m_nLayerCDFId, nVarID, "ogr_field_name", &pszValue) ==
    2311             :         CE_None)
    2312             :     {
    2313         486 :         snprintf(szName, sizeof(szName), "%s", pszValue);
    2314             :     }
    2315         733 :     CPLFree(pszValue);
    2316             : 
    2317         733 :     if (NCDFGetAttr(m_nLayerCDFId, nVarID, "ogr_field_width", &pszValue) ==
    2318             :         CE_None)
    2319             :     {
    2320         192 :         nWidth = atoi(pszValue);
    2321             :     }
    2322         733 :     CPLFree(pszValue);
    2323             : 
    2324         733 :     int nPrecision = 0;
    2325         733 :     if (NCDFGetAttr(m_nLayerCDFId, nVarID, "ogr_field_precision", &pszValue) ==
    2326             :         CE_None)
    2327             :     {
    2328           6 :         nPrecision = atoi(pszValue);
    2329             :     }
    2330         733 :     CPLFree(pszValue);
    2331             : 
    2332         733 :     OGRFieldDefn oFieldDefn(szName, eType);
    2333         733 :     oFieldDefn.SetSubType(eSubType);
    2334         733 :     oFieldDefn.SetWidth(nWidth);
    2335         733 :     oFieldDefn.SetPrecision(nPrecision);
    2336             : 
    2337        1256 :     if (NCDFGetAttr(m_nLayerCDFId, nVarID, CF_LNG_NAME, &pszValue) == CE_None &&
    2338        1256 :         pszValue != std::string("Field ") + szName)
    2339             :     {
    2340          19 :         oFieldDefn.SetComment(pszValue);
    2341             :     }
    2342         733 :     CPLFree(pszValue);
    2343             : 
    2344         761 :     if (NCDFGetAttr(m_nLayerCDFId, nVarID, CF_STD_NAME, &pszValue) == CE_None &&
    2345          28 :         strcmp(pszValue, szName) != 0)
    2346             :     {
    2347           4 :         oFieldDefn.SetAlternativeName(pszValue);
    2348             :     }
    2349         733 :     CPLFree(pszValue);
    2350             : 
    2351             :     FieldDesc fieldDesc;
    2352         733 :     fieldDesc.uNoData = nodata;
    2353         733 :     fieldDesc.nType = vartype;
    2354         733 :     fieldDesc.nVarId = nVarID;
    2355         733 :     fieldDesc.nDimCount = nDimCount;
    2356         733 :     fieldDesc.nMainDimId = anDimIds[0];
    2357         733 :     fieldDesc.nSecDimId = anDimIds[1];
    2358         733 :     fieldDesc.bHasWarnedAboutTruncation = false;
    2359         733 :     fieldDesc.bIsDays = bIsDays;
    2360         733 :     m_aoFieldDesc.push_back(fieldDesc);
    2361             : 
    2362         733 :     m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
    2363             : 
    2364         733 :     return true;
    2365             : }
    2366             : 
    2367             : /************************************************************************/
    2368             : /*                            CreateField()                             */
    2369             : /************************************************************************/
    2370             : 
    2371         177 : OGRErr netCDFLayer::CreateField(const OGRFieldDefn *poFieldDefn,
    2372             :                                 int /* bApproxOK */)
    2373             : {
    2374         177 :     int nSecDimId = -1;
    2375         177 :     int nVarID = -1;
    2376             :     int status;
    2377             : 
    2378         177 :     const netCDFWriterConfigField *poConfig = nullptr;
    2379         177 :     if (m_poDS->oWriterConfig.m_bIsValid)
    2380             :     {
    2381          11 :         std::map<CPLString, netCDFWriterConfigField>::const_iterator oIter;
    2382          15 :         if (m_poLayerConfig != nullptr &&
    2383           4 :             (oIter =
    2384          15 :                  m_poLayerConfig->m_oFields.find(poFieldDefn->GetNameRef())) !=
    2385          15 :                 m_poLayerConfig->m_oFields.end())
    2386             :         {
    2387           1 :             poConfig = &(oIter->second);
    2388             :         }
    2389          10 :         else if ((oIter = m_poDS->oWriterConfig.m_oFields.find(
    2390          20 :                       poFieldDefn->GetNameRef())) !=
    2391          20 :                  m_poDS->oWriterConfig.m_oFields.end())
    2392             :         {
    2393           2 :             poConfig = &(oIter->second);
    2394             :         }
    2395             :     }
    2396             : 
    2397         177 :     if (!m_osProfileDimName.empty() &&
    2398         180 :         EQUAL(poFieldDefn->GetNameRef(), m_osProfileDimName) &&
    2399           3 :         poFieldDefn->GetType() == OFTInteger)
    2400             :     {
    2401             :         FieldDesc fieldDesc;
    2402           3 :         fieldDesc.uNoData.nVal = NC_FILL_INT;
    2403           3 :         fieldDesc.nType = NC_INT;
    2404           3 :         fieldDesc.nVarId = m_nProfileVarID;
    2405           3 :         fieldDesc.nDimCount = 1;
    2406           3 :         fieldDesc.nMainDimId = m_nProfileDimID;
    2407           3 :         fieldDesc.nSecDimId = -1;
    2408           3 :         fieldDesc.bHasWarnedAboutTruncation = false;
    2409           3 :         fieldDesc.bIsDays = false;
    2410           3 :         m_aoFieldDesc.push_back(fieldDesc);
    2411           3 :         m_poFeatureDefn->AddFieldDefn(poFieldDefn);
    2412           3 :         return OGRERR_NONE;
    2413             :     }
    2414             : 
    2415         174 :     m_poDS->SetDefineMode(true);
    2416             : 
    2417             :     // Try to use the field name as variable name, but detects conflict first
    2418             :     CPLString osVarName(poConfig != nullptr
    2419           3 :                             ? poConfig->m_osNetCDFName
    2420         348 :                             : CPLString(poFieldDefn->GetNameRef()));
    2421             : 
    2422         174 :     if (!m_bLegacyCreateMode && m_bWriteGDALTags)
    2423             :     {
    2424             :         // To help avoid naming conflicts, append the layer name as a prefix
    2425          73 :         const char *prefix = this->GetName();
    2426          73 :         const char *fprefix = "_field_";
    2427             : 
    2428          73 :         osVarName = CPLString(prefix) + CPLString(fprefix) + osVarName;
    2429             :     }
    2430             : 
    2431         174 :     bool vCDFHas = false;
    2432         174 :     if (!m_bLegacyCreateMode)
    2433             :     {
    2434          73 :         vCDFHas = layerVID.virtualVarNameDefined(osVarName);
    2435             :     }
    2436             : 
    2437             :     // Also check the real
    2438         174 :     status = nc_inq_varid(m_nLayerCDFId, osVarName, &nVarID);
    2439         174 :     if (status == NC_NOERR || vCDFHas)
    2440             :     {
    2441           3 :         for (int i = 1; i <= 100; i++)
    2442             :         {
    2443           3 :             osVarName = CPLSPrintf("%s%d", poFieldDefn->GetNameRef(), i);
    2444           3 :             status = nc_inq_varid(m_nLayerCDFId, osVarName, &nVarID);
    2445           3 :             if (!m_bLegacyCreateMode)
    2446           0 :                 vCDFHas = layerVID.virtualVarNameDefined(osVarName);
    2447           3 :             if (status != NC_NOERR && !vCDFHas)
    2448           3 :                 break;
    2449             :         }
    2450             : 
    2451           3 :         CPLDebug("netCDF", "Field %s is written in variable %s",
    2452             :                  poFieldDefn->GetNameRef(), osVarName.c_str());
    2453             :     }
    2454             : 
    2455         174 :     const char *pszVarName = osVarName.c_str();
    2456             : 
    2457             :     NCDFNoDataUnion nodata;
    2458         174 :     memset(&nodata, 0, sizeof(nodata));
    2459             : 
    2460         174 :     const OGRFieldType eType = poFieldDefn->GetType();
    2461         174 :     const OGRFieldSubType eSubType = poFieldDefn->GetSubType();
    2462         174 :     nc_type nType = NC_NAT;
    2463         174 :     int nDimCount = 1;
    2464             : 
    2465             :     // Find which is the dimension that this variable should be indexed against
    2466         174 :     int nMainDimId = m_nRecordDimID;
    2467         174 :     if (!m_osProfileVariables.empty())
    2468             :     {
    2469             :         char **papszTokens =
    2470           3 :             CSLTokenizeString2(m_osProfileVariables, ",", CSLT_HONOURSTRINGS);
    2471           3 :         if (CSLFindString(papszTokens, poFieldDefn->GetNameRef()) >= 0)
    2472           1 :             nMainDimId = m_nProfileDimID;
    2473           3 :         CSLDestroy(papszTokens);
    2474             :     }
    2475         176 :     if (poConfig != nullptr && !poConfig->m_osMainDim.empty() &&
    2476           2 :         m_bLegacyCreateMode)
    2477             :     {
    2478           2 :         int ndims = 0;
    2479           2 :         status = nc_inq_ndims(m_nLayerCDFId, &ndims);
    2480           2 :         NCDF_ERR(status);
    2481           2 :         bool bFound = false;
    2482           4 :         for (int idim = 0; idim < ndims; idim++)
    2483             :         {
    2484             :             char szDimName[NC_MAX_NAME + 1];
    2485           3 :             szDimName[0] = 0;
    2486           3 :             status = nc_inq_dimname(m_poDS->cdfid, idim, szDimName);
    2487           3 :             NCDF_ERR(status);
    2488           3 :             if (strcmp(poConfig->m_osMainDim, szDimName) == 0)
    2489             :             {
    2490           1 :                 nMainDimId = idim;
    2491           1 :                 bFound = true;
    2492           1 :                 break;
    2493             :             }
    2494             :         }
    2495           2 :         if (!bFound)
    2496             :         {
    2497           1 :             CPLError(CE_Failure, CPLE_AppDefined,
    2498             :                      "Dimension '%s' does not exist",
    2499             :                      poConfig->m_osMainDim.c_str());
    2500           1 :             return OGRERR_FAILURE;
    2501             :         }
    2502             :     }
    2503             : 
    2504             :     try
    2505             :     {
    2506         173 :         switch (eType)
    2507             :         {
    2508          74 :             case OFTString:
    2509             :             case OFTStringList:
    2510             :             case OFTIntegerList:
    2511             :             case OFTRealList:
    2512             :             {
    2513          74 :                 if (poFieldDefn->GetWidth() == 1)
    2514             :                 {
    2515           2 :                     nType = NC_CHAR;
    2516           2 :                     nVarID =
    2517           2 :                         layerVID.nc_def_vvar(pszVarName, nType, 1, &nMainDimId);
    2518             :                 }
    2519          72 :                 else if (m_poDS->eFormat == NCDF_FORMAT_NC4 &&
    2520          13 :                          m_bUseStringInNC4)
    2521             :                 {
    2522           9 :                     nType = NC_STRING;
    2523           9 :                     nVarID =
    2524           9 :                         layerVID.nc_def_vvar(pszVarName, nType, 1, &nMainDimId);
    2525             :                 }
    2526             :                 else
    2527             :                 {
    2528          63 :                     if (poFieldDefn->GetWidth() == 0 && !m_bAutoGrowStrings)
    2529             :                     {
    2530           1 :                         if (m_nDefaultMaxWidthDimId < 0)
    2531             :                         {
    2532           1 :                             m_nDefaultMaxWidthDimId = layerVID.nc_def_vdim(
    2533           1 :                                 "string_default_max_width", m_nDefaultWidth);
    2534             :                         }
    2535             : 
    2536           1 :                         nSecDimId = m_nDefaultMaxWidthDimId;
    2537             :                     }
    2538             :                     else
    2539             :                     {
    2540          62 :                         size_t nDim = poFieldDefn->GetWidth() == 0
    2541          68 :                                           ? m_nDefaultWidth
    2542           6 :                                           : poFieldDefn->GetWidth();
    2543             : 
    2544             :                         std::string ndimname =
    2545         124 :                             std::string(pszVarName) + std::string("_max_width");
    2546             :                         nSecDimId =
    2547          62 :                             layerVID.nc_def_vdim(ndimname.c_str(), nDim);
    2548             :                     }
    2549             : 
    2550          63 :                     nDimCount = 2;
    2551          63 :                     int anDims[2] = {nMainDimId, nSecDimId};
    2552          63 :                     nType = NC_CHAR;
    2553          63 :                     nVarID = layerVID.nc_def_vvar(pszVarName, nType, 2, anDims);
    2554             :                 }
    2555             : 
    2556          74 :                 break;
    2557             :             }
    2558             : 
    2559          49 :             case OFTInteger:
    2560             :             {
    2561          92 :                 nType = eSubType == OFSTBoolean   ? NC_BYTE
    2562          43 :                         : (eSubType == OFSTInt16) ? NC_SHORT
    2563             :                                                   : NC_INT;
    2564             : 
    2565          49 :                 if (nType == NC_BYTE)
    2566           6 :                     nodata.chVal = NC_FILL_BYTE;
    2567          43 :                 else if (nType == NC_SHORT)
    2568           7 :                     nodata.sVal = NC_FILL_SHORT;
    2569          36 :                 else if (nType == NC_INT)
    2570          36 :                     nodata.nVal = NC_FILL_INT;
    2571             : 
    2572          49 :                 nVarID =
    2573          49 :                     layerVID.nc_def_vvar(pszVarName, nType, 1, &nMainDimId);
    2574             : 
    2575          49 :                 if (eSubType == OFSTBoolean)
    2576             :                 {
    2577           6 :                     if (m_bLegacyCreateMode)
    2578             :                     {
    2579           6 :                         signed char anRange[2] = {0, 1};
    2580           6 :                         nc_put_att_schar(m_nLayerCDFId, nVarID, "valid_range",
    2581             :                                          NC_BYTE, 2, anRange);
    2582             :                     }
    2583             :                 }
    2584             : 
    2585          49 :                 break;
    2586             :             }
    2587             : 
    2588          11 :             case OFTInteger64:
    2589             :             {
    2590          11 :                 nType = NC_DOUBLE;
    2591          11 :                 nodata.dfVal = NC_FILL_DOUBLE;
    2592          11 :                 if (m_poDS->eFormat == NCDF_FORMAT_NC4)
    2593             :                 {
    2594           5 :                     nType = NC_INT64;
    2595           5 :                     nodata.nVal64 = NC_FILL_INT64;
    2596             :                 }
    2597             : 
    2598          11 :                 nVarID =
    2599          11 :                     layerVID.nc_def_vvar(pszVarName, nType, 1, &nMainDimId);
    2600          11 :                 break;
    2601             :             }
    2602             : 
    2603          30 :             case OFTReal:
    2604             :             {
    2605          30 :                 nType = (eSubType == OFSTFloat32) ? NC_FLOAT : NC_DOUBLE;
    2606          30 :                 if (eSubType == OFSTFloat32)
    2607           7 :                     nodata.fVal = NC_FILL_FLOAT;
    2608             :                 else
    2609          23 :                     nodata.dfVal = NC_FILL_DOUBLE;
    2610             : 
    2611          30 :                 nVarID =
    2612          30 :                     layerVID.nc_def_vvar(pszVarName, nType, 1, &nMainDimId);
    2613          30 :                 break;
    2614             :             }
    2615             : 
    2616           3 :             case OFTDate:
    2617             :             {
    2618           3 :                 nType = NC_INT;
    2619             : 
    2620           3 :                 nVarID =
    2621           3 :                     layerVID.nc_def_vvar(pszVarName, nType, 1, &nMainDimId);
    2622           3 :                 nodata.nVal = NC_FILL_INT;
    2623             : 
    2624           3 :                 layerVID.nc_put_vatt_text(nVarID, CF_UNITS,
    2625             :                                           "days since 1970-1-1");
    2626           3 :                 break;
    2627             :             }
    2628             : 
    2629           6 :             case OFTDateTime:
    2630             :             {
    2631           6 :                 nType = NC_DOUBLE;
    2632           6 :                 nVarID =
    2633           6 :                     layerVID.nc_def_vvar(pszVarName, nType, 1, &nMainDimId);
    2634             : 
    2635           6 :                 nodata.dfVal = NC_FILL_DOUBLE;
    2636             : 
    2637           6 :                 layerVID.nc_put_vatt_text(nVarID, CF_UNITS,
    2638             :                                           "seconds since 1970-1-1 0:0:0");
    2639           6 :                 break;
    2640             :             }
    2641             : 
    2642           0 :             default:
    2643           0 :                 return OGRERR_FAILURE;
    2644             :         }
    2645             : 
    2646             :         FieldDesc fieldDesc;
    2647         173 :         fieldDesc.uNoData = nodata;
    2648         173 :         fieldDesc.nType = nType;
    2649         173 :         fieldDesc.nVarId = nVarID;
    2650         173 :         fieldDesc.nDimCount = nDimCount;
    2651         173 :         fieldDesc.nMainDimId = nMainDimId;
    2652         173 :         fieldDesc.nSecDimId = nSecDimId;
    2653         173 :         fieldDesc.bHasWarnedAboutTruncation = false;
    2654         173 :         fieldDesc.bIsDays = (eType == OFTDate);
    2655         173 :         m_aoFieldDesc.push_back(fieldDesc);
    2656             : 
    2657             :         // If we have an alternative name that is compatible with the
    2658             :         // standard_name attribute, then put it in it.
    2659             :         // http://cfconventions.org/Data/cf-standard-names/docs/guidelines.html:
    2660             :         // "Standard names consist of lower-letters, digits and underscores,
    2661             :         // and begin with a letter. Upper case is not used."
    2662             :         // Otherwise use it as the long_name, unless we have a comment
    2663         173 :         bool bAlternativeNameCompatibleOfStandardName = false;
    2664         173 :         const char *pszAlternativeName = poFieldDefn->GetAlternativeNameRef();
    2665         173 :         if (pszAlternativeName[0] >= 'a' && pszAlternativeName[0] <= 'z')
    2666             :         {
    2667           2 :             bAlternativeNameCompatibleOfStandardName = true;
    2668          15 :             for (const char *chPtr = pszAlternativeName; *chPtr; ++chPtr)
    2669             :             {
    2670          14 :                 if (!((*chPtr >= 'a' && *chPtr <= 'z') || *chPtr == '_' ||
    2671           1 :                       (*chPtr >= '0' && *chPtr <= '9')))
    2672             :                 {
    2673           1 :                     bAlternativeNameCompatibleOfStandardName = false;
    2674           1 :                     break;
    2675             :                 }
    2676             :             }
    2677             :         }
    2678             : 
    2679         173 :         if (!poFieldDefn->GetComment().empty())
    2680             :         {
    2681           2 :             layerVID.nc_put_vatt_text(nVarID, CF_LNG_NAME,
    2682           2 :                                       poFieldDefn->GetComment().c_str());
    2683             :         }
    2684         171 :         else if (pszAlternativeName[0] &&
    2685           1 :                  !bAlternativeNameCompatibleOfStandardName)
    2686             :         {
    2687           1 :             layerVID.nc_put_vatt_text(nVarID, CF_LNG_NAME, pszAlternativeName);
    2688             :         }
    2689             :         else
    2690             :         {
    2691             :             const char *pszLongName =
    2692         170 :                 CPLSPrintf("Field %s", poFieldDefn->GetNameRef());
    2693             : 
    2694         170 :             layerVID.nc_put_vatt_text(nVarID, CF_LNG_NAME, pszLongName);
    2695             :         }
    2696             : 
    2697         173 :         if (bAlternativeNameCompatibleOfStandardName)
    2698             :         {
    2699           1 :             layerVID.nc_put_vatt_text(nVarID, CF_STD_NAME, pszAlternativeName);
    2700             :         }
    2701             : 
    2702         173 :         if (!m_bLegacyCreateMode)
    2703             :         {
    2704         146 :             std::string ct_name(m_layerSGDefn.get_containerName());
    2705          73 :             layerVID.nc_put_vatt_text(nVarID, CF_SG_GEOMETRY, ct_name.c_str());
    2706             :         }
    2707             : 
    2708         173 :         if (m_bWriteGDALTags)
    2709             :         {
    2710         150 :             layerVID.nc_put_vatt_text(nVarID, "ogr_field_name",
    2711             :                                       poFieldDefn->GetNameRef());
    2712             : 
    2713         150 :             const char *pszType = OGRFieldDefn::GetFieldTypeName(eType);
    2714         150 :             if (eSubType != OFSTNone)
    2715             :             {
    2716             :                 pszType =
    2717          14 :                     CPLSPrintf("%s(%s)", pszType,
    2718             :                                OGRFieldDefn::GetFieldSubTypeName(eSubType));
    2719             :             }
    2720             : 
    2721         150 :             layerVID.nc_put_vatt_text(nVarID, "ogr_field_type", pszType);
    2722             : 
    2723         150 :             const int nWidth = poFieldDefn->GetWidth();
    2724         150 :             if (nWidth || nType == NC_CHAR)
    2725             :             {
    2726          70 :                 layerVID.nc_put_vatt_int(nVarID, "ogr_field_width", &nWidth);
    2727             : 
    2728          70 :                 const int nPrecision = poFieldDefn->GetPrecision();
    2729          70 :                 if (nPrecision)
    2730             :                 {
    2731           3 :                     layerVID.nc_put_vatt_int(nVarID, "ogr_field_precision",
    2732             :                                              &nPrecision);
    2733             :                 }
    2734             :             }
    2735             :         }
    2736             : 
    2737             :         // nc_put_att_text(m_nLayerCDFId, nVarID, CF_UNITS,
    2738             :         //                 strlen("none"), "none");
    2739             : 
    2740         173 :         if (!m_osGridMapping.empty() && nMainDimId == m_nRecordDimID)
    2741             :         {
    2742         138 :             layerVID.nc_put_vatt_text(nVarID, CF_GRD_MAPPING,
    2743             :                                       m_osGridMapping.c_str());
    2744             :         }
    2745             : 
    2746         173 :         if (!m_osCoordinatesValue.empty() && nMainDimId == m_nRecordDimID)
    2747             :         {
    2748          83 :             layerVID.nc_put_vatt_text(nVarID, CF_COORDINATES,
    2749             :                                       m_osCoordinatesValue.c_str());
    2750             :         }
    2751             : 
    2752         173 :         if (poConfig != nullptr)
    2753             :         {
    2754           2 :             netCDFWriteAttributesFromConf(m_nLayerCDFId, nVarID,
    2755           2 :                                           poConfig->m_aoAttributes);
    2756             :         }
    2757             :     }
    2758             : 
    2759           0 :     catch (nccfdriver::SG_Exception &e)
    2760             :     {
    2761           0 :         CPLError(CE_Failure, CPLE_FileIO, "%s", e.get_err_msg());
    2762           0 :         return OGRERR_FAILURE;
    2763             :     }
    2764             : 
    2765         173 :     m_poFeatureDefn->AddFieldDefn(poFieldDefn);
    2766         173 :     return OGRERR_NONE;
    2767             : }
    2768             : 
    2769             : /************************************************************************/
    2770             : /*                          GetFeatureCount()                           */
    2771             : /************************************************************************/
    2772             : 
    2773          52 : GIntBig netCDFLayer::GetFeatureCount(int bForce)
    2774             : {
    2775          52 :     if (m_poFilterGeom == nullptr && m_poAttrQuery == nullptr)
    2776             :     {
    2777          46 :         if (!m_bLegacyCreateMode)
    2778             :         {
    2779          32 :             return m_simpleGeometryReader->get_geometry_count();
    2780             :         }
    2781             : 
    2782             :         size_t nDimLen;
    2783          14 :         nc_inq_dimlen(m_nLayerCDFId, m_nRecordDimID, &nDimLen);
    2784          14 :         return static_cast<GIntBig>(nDimLen);
    2785             :     }
    2786           6 :     return OGRLayer::GetFeatureCount(bForce);
    2787             : }
    2788             : 
    2789             : /************************************************************************/
    2790             : /*                           TestCapability()                           */
    2791             : /************************************************************************/
    2792             : 
    2793         341 : bool netCDFLayer::TestCapability(const char *pszCap) const
    2794             : {
    2795         341 :     if (EQUAL(pszCap, OLCSequentialWrite))
    2796           1 :         return m_poDS->GetAccess() == GA_Update;
    2797         340 :     if (EQUAL(pszCap, OLCCreateField))
    2798           2 :         return m_poDS->GetAccess() == GA_Update;
    2799         338 :     if (EQUAL(pszCap, OLCFastFeatureCount))
    2800           0 :         return m_poFilterGeom == nullptr && m_poAttrQuery == nullptr;
    2801         338 :     if (EQUAL(pszCap, OLCZGeometries))
    2802          54 :         return true;
    2803         284 :     return false;
    2804             : }
    2805             : 
    2806             : /************************************************************************/
    2807             : /*                             GetDataset()                             */
    2808             : /************************************************************************/
    2809             : 
    2810           2 : GDALDataset *netCDFLayer::GetDataset()
    2811             : {
    2812           2 :     return m_poDS;
    2813             : }

Generated by: LCOV version 1.14