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 72915 : 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 72915 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "NETCDF:"))
45 0 : return NCDF_FORMAT_UNKNOWN;
46 72915 : if (poOpenInfo->nHeaderBytes < 4)
47 57666 : return NCDF_FORMAT_NONE;
48 15249 : const char *pszHeader =
49 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
50 :
51 : #ifdef ENABLE_NCDUMP
52 15249 : 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 15240 : if (STARTS_WITH_CI(pszHeader, "CDF\001"))
73 : {
74 921 : return NCDF_FORMAT_NC;
75 : }
76 :
77 14319 : if (STARTS_WITH_CI(pszHeader, "CDF\002"))
78 : {
79 14 : return NCDF_FORMAT_NC2;
80 : }
81 :
82 14305 : constexpr char HDF5_SIG[] = "\211HDF\r\n\032\n";
83 14305 : 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 14305 : constexpr int HDF5_SIG_OFFSET = 512;
87 14305 : if (STARTS_WITH_CI(pszHeader, HDF5_SIG) ||
88 13527 : (poOpenInfo->nHeaderBytes > HDF5_SIG_OFFSET + HDF5_SIG_LEN &&
89 8677 : 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 778 : 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 757 : if (bCheckExt)
106 : {
107 : // Check by default.
108 740 : const char *pszExtension = poOpenInfo->osExtension.c_str();
109 740 : if (!(EQUAL(pszExtension, "nc") || EQUAL(pszExtension, "cdf") ||
110 398 : EQUAL(pszExtension, "nc2") || EQUAL(pszExtension, "nc4") ||
111 398 : EQUAL(pszExtension, "nc3") || EQUAL(pszExtension, "grd") ||
112 398 : EQUAL(pszExtension, "gmac")))
113 : {
114 296 : if (GDALGetDriverByName("HDF5") != nullptr)
115 : {
116 296 : return NCDF_FORMAT_HDF5;
117 : }
118 : }
119 : }
120 :
121 461 : return NCDF_FORMAT_NC4;
122 : }
123 13527 : 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 13214 : const char *pszExtension = poOpenInfo->osExtension.c_str();
158 26341 : if (poOpenInfo->fpL != nullptr &&
159 13127 : (!bCheckExt || EQUAL(pszExtension, "nc") ||
160 13125 : EQUAL(pszExtension, "cdf") || EQUAL(pszExtension, "nc4") ||
161 13125 : 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 13212 : return NCDF_FORMAT_NONE;
182 : }
183 :
184 : /************************************************************************/
185 : /* Identify() */
186 : /************************************************************************/
187 :
188 72108 : static int netCDFDatasetIdentify(GDALOpenInfo *poOpenInfo)
189 :
190 : {
191 72108 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "NETCDF:"))
192 : {
193 60 : return TRUE;
194 : }
195 : const NetCDFFormatEnum eTmpFormat =
196 72048 : netCDFIdentifyFormat(poOpenInfo,
197 : /* bCheckExt = */ true);
198 72051 : if (NCDF_FORMAT_NC == eTmpFormat || NCDF_FORMAT_NC2 == eTmpFormat ||
199 71479 : NCDF_FORMAT_NC4 == eTmpFormat || NCDF_FORMAT_NC4C == eTmpFormat)
200 577 : return TRUE;
201 71787 : if (eTmpFormat == NCDF_FORMAT_HDF4 &&
202 313 : poOpenInfo->IsSingleAllowedDriver("netCDF"))
203 : {
204 0 : return TRUE;
205 : }
206 :
207 71474 : return FALSE;
208 : }
209 :
210 : /************************************************************************/
211 : /* NCDFDriverGetSubdatasetInfo() */
212 : /************************************************************************/
213 :
214 : struct NCDFDriverSubdatasetInfo : public GDALSubdatasetInfo
215 : {
216 : public:
217 53 : explicit NCDFDriverSubdatasetInfo(const std::string &fileName)
218 53 : : GDALSubdatasetInfo(fileName)
219 : {
220 53 : }
221 :
222 : // GDALSubdatasetInfo interface
223 : private:
224 : void parseFileName() override;
225 : };
226 :
227 53 : void NCDFDriverSubdatasetInfo::parseFileName()
228 : {
229 :
230 53 : if (!STARTS_WITH_CI(m_fileName.c_str(), "NETCDF:"))
231 : {
232 0 : return;
233 : }
234 :
235 106 : CPLStringList aosParts{CSLTokenizeString2(m_fileName.c_str(), ":", 0)};
236 53 : const int iPartsCount{CSLCount(aosParts)};
237 :
238 53 : if (iPartsCount >= 3)
239 : {
240 :
241 51 : m_driverPrefixComponent = aosParts[0];
242 :
243 51 : int subdatasetIndex{2};
244 :
245 102 : std::string part1{aosParts[1]};
246 51 : if (!part1.empty() && part1[0] == '"')
247 : {
248 41 : part1 = part1.substr(1);
249 : }
250 :
251 : const bool hasDriveLetter{
252 51 : (strlen(aosParts[2]) > 1 &&
253 57 : (aosParts[2][0] == '\\' || aosParts[2][0] == '/')) &&
254 108 : part1.length() == 1 &&
255 7 : std::isalpha(static_cast<unsigned char>(part1.at(0)))};
256 :
257 102 : const bool hasProtocol{part1 == "/vsicurl/http" ||
258 101 : part1 == "/vsicurl/https" ||
259 100 : part1 == "/vsicurl_streaming/http" ||
260 100 : part1 == "/vsicurl_streaming/https" ||
261 152 : part1 == "http" || part1 == "https"};
262 :
263 51 : m_pathComponent = aosParts[1];
264 51 : if (hasDriveLetter || hasProtocol)
265 : {
266 9 : m_pathComponent.append(":");
267 9 : m_pathComponent.append(aosParts[2]);
268 9 : subdatasetIndex++;
269 : }
270 :
271 : // Check for bogus paths
272 51 : if (subdatasetIndex < iPartsCount)
273 : {
274 49 : m_subdatasetComponent = aosParts[subdatasetIndex];
275 :
276 : // Append any remaining part
277 50 : for (int i = subdatasetIndex + 1; i < iPartsCount; ++i)
278 : {
279 1 : m_subdatasetComponent.append(":");
280 1 : m_subdatasetComponent.append(aosParts[i]);
281 : }
282 : }
283 :
284 : // Remove quotes from subdataset component
285 51 : if (!m_subdatasetComponent.empty() && m_subdatasetComponent[0] == '"')
286 : {
287 1 : m_subdatasetComponent = m_subdatasetComponent.substr(1);
288 : }
289 100 : if (!m_subdatasetComponent.empty() &&
290 49 : m_subdatasetComponent.rfind('"') ==
291 49 : m_subdatasetComponent.length() - 1)
292 : {
293 2 : m_subdatasetComponent.pop_back();
294 : }
295 : }
296 : }
297 :
298 2749 : static GDALSubdatasetInfo *NCDFDriverGetSubdatasetInfo(const char *pszFileName)
299 : {
300 2749 : if (STARTS_WITH_CI(pszFileName, "NETCDF:"))
301 : {
302 : std::unique_ptr<GDALSubdatasetInfo> info =
303 53 : std::make_unique<NCDFDriverSubdatasetInfo>(pszFileName);
304 : // Subdataset component can be empty, path cannot.
305 53 : if (!info->GetPathComponent().empty())
306 : {
307 51 : return info.release();
308 : }
309 : }
310 2698 : return nullptr;
311 : }
312 :
313 : /************************************************************************/
314 : /* netCDFDriverSetCommonMetadata() */
315 : /************************************************************************/
316 :
317 1647 : void netCDFDriverSetCommonMetadata(GDALDriver *poDriver)
318 : {
319 : // Set the driver details.
320 1647 : poDriver->SetDescription(DRIVER_NAME);
321 1647 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
322 1647 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
323 1647 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
324 1647 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
325 1647 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
326 1647 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Network Common Data Format");
327 1647 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/netcdf.html");
328 1647 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "nc");
329 :
330 1647 : poDriver->SetMetadataItem(
331 : GDAL_DMD_OPENOPTIONLIST,
332 : "<OpenOptionList>"
333 : " <Option name='LIST_ALL_ARRAYS' type='boolean' "
334 : "description='Whether to list all arrays, and not only those whose "
335 : "dimension count is 2 or more' default='NO'/>"
336 : " <Option name='HONOUR_VALID_RANGE' type='boolean' scope='raster' "
337 : "description='Whether to set to nodata pixel values outside of the "
338 : "validity range' default='YES'/>"
339 : " <Option name='IGNORE_XY_AXIS_NAME_CHECKS' type='boolean' "
340 : "scope='raster' "
341 : "description='Whether X/Y dimensions should be always considered as "
342 : "geospatial axis, even if the lack conventional attributes confirming "
343 : "it.'"
344 : " default='NO'/>"
345 : " <Option name='VARIABLES_AS_BANDS' type='boolean' scope='raster' "
346 : "description='Whether 2D variables that share the same indexing "
347 : "dimensions "
348 : "should be exposed as several bands of a same dataset instead of "
349 : "several "
350 : "subdatasets.' default='NO'/>"
351 : " <Option name='ASSUME_LONGLAT' type='boolean' scope='raster' "
352 : "description='Whether when all else has failed for determining a CRS, "
353 : "a "
354 : "meaningful geotransform has been found, and is within the "
355 : "bounds -180,360 -90,90, assume OGC:CRS84.' default='NO'/>"
356 : " <Option name='PRESERVE_AXIS_UNIT_IN_CRS' type='boolean' "
357 : "scope='raster' description='Whether unusual linear axis unit (km) "
358 : "should be kept as such, instead of being normalized to metre' "
359 : "default='NO'/>"
360 1647 : "</OpenOptionList>");
361 1647 : poDriver->SetMetadataItem(
362 : GDAL_DMD_CREATIONDATATYPES,
363 : "Byte Int8 UInt16 Int16 UInt32 Int32 Int64 UInt64 "
364 : "Float32 Float64 "
365 1647 : "CInt16 CInt32 CFloat32 CFloat64");
366 1647 : poDriver->SetMetadataItem(
367 : GDAL_DMD_CREATIONOPTIONLIST,
368 : "<CreationOptionList>"
369 : " <Option name='FORMAT' type='string-select' default='NC'>"
370 : " <Value>NC</Value>"
371 : #if NETCDF_CORE_HAS_NC2
372 : " <Value>NC2</Value>"
373 : #endif
374 : " <Value>NC4</Value>"
375 : " <Value>NC4C</Value>"
376 : " </Option>"
377 : " <Option name='COMPRESS' type='string-select' scope='raster' "
378 : "default='NONE'>"
379 : " <Value>NONE</Value>"
380 : " <Value>DEFLATE</Value>"
381 : " </Option>"
382 : " <Option name='ZLEVEL' type='int' scope='raster' "
383 : "description='DEFLATE compression level 1-9' default='1'/>"
384 : " <Option name='WRITE_BOTTOMUP' type='boolean' scope='raster' "
385 : "default='YES'>"
386 : " </Option>"
387 : " <Option name='WRITE_GDAL_TAGS' type='boolean' default='YES'>"
388 : " </Option>"
389 : " <Option name='WRITE_LONLAT' type='string-select' scope='raster'>"
390 : " <Value>YES</Value>"
391 : " <Value>NO</Value>"
392 : " <Value>IF_NEEDED</Value>"
393 : " </Option>"
394 : " <Option name='TYPE_LONLAT' type='string-select' scope='raster'>"
395 : " <Value>float</Value>"
396 : " <Value>double</Value>"
397 : " </Option>"
398 : " <Option name='PIXELTYPE' type='string-select' scope='raster' "
399 : "description='(deprecated, use Int8 datatype) only used in Create()'>"
400 : " <Value>DEFAULT</Value>"
401 : " <Value>SIGNEDBYTE</Value>"
402 : " </Option>"
403 : " <Option name='CHUNKING' type='boolean' scope='raster' "
404 : "default='YES' description='define chunking when creating netcdf4 "
405 : "file'/>"
406 : " <Option name='MULTIPLE_LAYERS' type='string-select' scope='vector' "
407 : "description='Behaviour regarding multiple vector layer creation' "
408 : "default='NO'>"
409 : " <Value>NO</Value>"
410 : " <Value>SEPARATE_FILES</Value>"
411 : " <Value>SEPARATE_GROUPS</Value>"
412 : " </Option>"
413 : " <Option name='GEOMETRY_ENCODING' type='string' scope='vector' "
414 : "default='CF_1.8' description='Specifies the type of geometry encoding "
415 : "when creating a netCDF dataset'>"
416 : " <Value>WKT</Value>"
417 : " <Value>CF_1.8</Value>"
418 : " </Option>"
419 : " <Option name='CONFIG_FILE' type='string' scope='vector' "
420 : "description='Path to a XML configuration file (or content inlined)'/>"
421 : " <Option name='WRITE_GDAL_VERSION' type='boolean' default='YES'/>"
422 : " <Option name='WRITE_GDAL_HISTORY' type='boolean' default='YES'/>"
423 : " <Option name='BAND_NAMES' type='string' scope='raster' />"
424 1647 : "</CreationOptionList>");
425 1647 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
426 :
427 1647 : poDriver->SetMetadataItem(
428 : GDAL_DS_LAYER_CREATIONOPTIONLIST,
429 : "<LayerCreationOptionList>"
430 : " <Option name='RECORD_DIM_NAME' type='string' description='Name of "
431 : "the unlimited dimension' default='record'/>"
432 : " <Option name='STRING_DEFAULT_WIDTH' type='int' description='"
433 : "For non-NC4 format, "
434 : "default width of strings. Default is 10 in autogrow mode, 80 "
435 : "otherwise.'/>"
436 : " <Option name='WKT_DEFAULT_WIDTH' type='int' description='"
437 : "For non-NC4 format, "
438 : "default width of WKT strings. Default is 1000 in autogrow mode, 10000 "
439 : "otherwise.'/>"
440 : " <Option name='AUTOGROW_STRINGS' type='boolean' "
441 : "description='Whether to auto-grow non-bounded string fields of "
442 : "bidimensional char variable' default='YES'/>"
443 : " <Option name='USE_STRING_IN_NC4' type='boolean' "
444 : "description='Whether to use NetCDF string type for strings in NC4 "
445 : "format. If NO, bidimensional char variable are used' default='YES'/>"
446 : #if 0
447 : " <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'/>"
448 : #endif
449 : " <Option name='FEATURE_TYPE' type='string-select' description='CF "
450 : "FeatureType' default='AUTO'>"
451 : " <Value>AUTO</Value>"
452 : " <Value>POINT</Value>"
453 : " <Value>PROFILE</Value>"
454 : " </Option>"
455 : " <Option name='BUFFER_SIZE' type='int' default='' "
456 : "description='Specifies the soft limit of buffer translation in bytes. "
457 : "Minimum size is 4096. Does not apply to datasets with CF version less "
458 : "than 1.8.'/>"
459 : " <Option name='GROUPLESS_WRITE_BACK' type='boolean' default='NO' "
460 : "description='Enables or disables array building write back for "
461 : "CF-1.8.'/>"
462 : " <Option name='PROFILE_DIM_NAME' type='string' description='Name of "
463 : "the profile dimension and variable' default='profile'/>"
464 : " <Option name='PROFILE_DIM_INIT_SIZE' type='string' "
465 : "description='Initial size of profile dimension (default 100), or "
466 : "UNLIMITED for NC4 files'/>"
467 : " <Option name='PROFILE_VARIABLES' type='string' description='Comma "
468 : "separated list of field names that must be indexed by the profile "
469 : "dimension'/>"
470 1647 : "</LayerCreationOptionList>");
471 :
472 : // Make driver config and capabilities available.
473 : #if NETCDF_CORE_HAS_NC2
474 1647 : poDriver->SetMetadataItem("NETCDF_HAS_NC2", "YES");
475 : #endif
476 1647 : poDriver->SetMetadataItem("NETCDF_HAS_NC4", "YES");
477 : #ifdef NETCDF_HAS_HDF4
478 : poDriver->SetMetadataItem("NETCDF_HAS_HDF4", "YES");
479 : #endif
480 :
481 1647 : poDriver->SetMetadataItem("NETCDF_HAS_NETCDF_MEM", "YES");
482 :
483 : #ifdef ENABLE_NCDUMP
484 1647 : poDriver->SetMetadataItem("ENABLE_NCDUMP", "YES");
485 : #endif
486 :
487 1647 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
488 :
489 1647 : poDriver->SetMetadataItem(
490 : GDAL_DMD_MULTIDIM_DATASET_CREATIONOPTIONLIST,
491 : "<MultiDimDatasetCreationOptionList>"
492 : " <Option name='FORMAT' type='string-select' default='NC4'>"
493 : " <Value>NC</Value>"
494 : #if NETCDF_CORE_HAS_NC2
495 : " <Value>NC2</Value>"
496 : #endif
497 : " <Value>NC4</Value>"
498 : " <Value>NC4C</Value>"
499 : " </Option>"
500 : " <Option name='CONVENTIONS' type='string' default='CF-1.6' "
501 : "description='Value of the Conventions attribute'/>"
502 1647 : "</MultiDimDatasetCreationOptionList>");
503 :
504 1647 : poDriver->SetMetadataItem(
505 : GDAL_DMD_MULTIDIM_DIMENSION_CREATIONOPTIONLIST,
506 : "<MultiDimDimensionCreationOptionList>"
507 : " <Option name='UNLIMITED' type='boolean' description='Whether the "
508 : "dimension should be unlimited' default='false'/>"
509 1647 : "</MultiDimDimensionCreationOptionList>");
510 :
511 1647 : poDriver->SetMetadataItem(
512 : GDAL_DMD_MULTIDIM_ARRAY_CREATIONOPTIONLIST,
513 : "<MultiDimArrayCreationOptionList>"
514 : " <Option name='BLOCKSIZE' type='int' description='Block size in "
515 : "pixels'/>"
516 : " <Option name='COMPRESS' type='string-select' default='NONE'>"
517 : " <Value>NONE</Value>"
518 : " <Value>DEFLATE</Value>"
519 : " </Option>"
520 : " <Option name='ZLEVEL' type='int' description='DEFLATE compression "
521 : "level 1-9' default='1'/>"
522 : " <Option name='NC_TYPE' type='string-select' default='netCDF data "
523 : "type'>"
524 : " <Value>AUTO</Value>"
525 : " <Value>NC_BYTE</Value>"
526 : " <Value>NC_INT64</Value>"
527 : " <Value>NC_UINT64</Value>"
528 : " </Option>"
529 1647 : "</MultiDimArrayCreationOptionList>");
530 :
531 1647 : poDriver->SetMetadataItem(
532 : GDAL_DMD_MULTIDIM_ARRAY_OPENOPTIONLIST,
533 : "<MultiDimArrayOpenOptionList>"
534 : " <Option name='USE_DEFAULT_FILL_AS_NODATA' type='boolean' "
535 : "description='Whether the default fill value should be used as nodata "
536 : "when there is no _FillValue or missing_value attribute' default='NO'/>"
537 : " <Option name='RAW_DATA_CHUNK_CACHE_SIZE' type='integer' "
538 : "description='The total size of the libnetcdf raw data chunk cache, "
539 : "in bytes. Only for netCDF4/HDF5 files'/>"
540 : " <Option name='CHUNK_SLOTS' type='integer' "
541 : "description='The number of chunk slots in the libnetcdf raw data "
542 : "chunk cache. "
543 : "Only for netCDF4/HDF5 files'/>"
544 : " <Option name='PREEMPTION' type='float' min='0' max='1' "
545 : "description='Indicates how much chunks from libnetcdf chunk cache "
546 : "that have been fully read are favored for preemption. "
547 : "Only for netCDF4/HDF5 files'/>"
548 1647 : "</MultiDimArrayOpenOptionList>");
549 :
550 1647 : poDriver->SetMetadataItem(GDAL_DMD_MULTIDIM_ATTRIBUTE_CREATIONOPTIONLIST,
551 : "<MultiDimAttributeCreationOptionList>"
552 : " <Option name='NC_TYPE' type='string-select' "
553 : "default='netCDF data type'>"
554 : " <Value>AUTO</Value>"
555 : " <Value>NC_BYTE</Value>"
556 : " <Value>NC_CHAR</Value>"
557 : " <Value>NC_INT64</Value>"
558 : " <Value>NC_UINT64</Value>"
559 : " </Option>"
560 1647 : "</MultiDimAttributeCreationOptionList>");
561 :
562 1647 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES,
563 1647 : "Integer Integer64 Real String Date DateTime");
564 1647 : poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS,
565 1647 : "Comment AlternativeName");
566 :
567 1647 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
568 :
569 1647 : poDriver->pfnIdentify = netCDFDatasetIdentify;
570 1647 : poDriver->pfnGetSubdatasetInfoFunc = NCDFDriverGetSubdatasetInfo;
571 1647 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
572 1647 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
573 1647 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
574 1647 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_MULTIDIMENSIONAL, "YES");
575 :
576 1647 : poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES");
577 1647 : poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS,
578 : "GeoTransform SRS " // if not already set...
579 1647 : "DatasetMetadata BandMetadata RasterValues");
580 1647 : }
581 :
582 : /************************************************************************/
583 : /* DeclareDeferredNetCDFPlugin() */
584 : /************************************************************************/
585 :
586 : #ifdef PLUGIN_FILENAME
587 1911 : void DeclareDeferredNetCDFPlugin()
588 : {
589 1911 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
590 : {
591 282 : return;
592 : }
593 1629 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
594 : #ifdef PLUGIN_INSTALLATION_MESSAGE
595 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
596 : PLUGIN_INSTALLATION_MESSAGE);
597 : #endif
598 1629 : netCDFDriverSetCommonMetadata(poDriver);
599 1629 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
600 : }
601 : #endif
|