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

Generated by: LCOV version 1.14