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