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

Generated by: LCOV version 1.14