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