Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: HDF5 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 "hdf5drivercore.h"
14 :
15 : #include "gdal_frmts.h"
16 : #include "gdalplugindriverproxy.h"
17 : #include "gdalsubdatasetinfo.h"
18 :
19 : #include <algorithm>
20 : #include <cctype>
21 :
22 : /************************************************************************/
23 : /* HDF5DatasetIdentify() */
24 : /************************************************************************/
25 :
26 61639 : int HDF5DatasetIdentify(GDALOpenInfo *poOpenInfo)
27 :
28 : {
29 61639 : if ((poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) &&
30 736 : STARTS_WITH(poOpenInfo->pszFilename, "HDF5:"))
31 : {
32 16 : return TRUE;
33 : }
34 :
35 : // Is it an HDF5 file?
36 61623 : constexpr char achSignature[] = "\211HDF\r\n\032\n";
37 :
38 61623 : if (!poOpenInfo->pabyHeader)
39 56767 : return FALSE;
40 :
41 9712 : const CPLString osExt(poOpenInfo->osExtension);
42 :
43 802 : const auto IsRecognizedByNetCDFDriver = [&osExt, poOpenInfo]()
44 : {
45 401 : if ((EQUAL(osExt, "NC") || EQUAL(osExt, "CDF") || EQUAL(osExt, "NC4") ||
46 406 : EQUAL(osExt, "gmac")) &&
47 5 : GDALGetDriverByName("netCDF") != nullptr)
48 : {
49 5 : const char *const apszAllowedDriver[] = {"netCDF", nullptr};
50 5 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
51 10 : return std::unique_ptr<GDALDataset>(GDALDataset::Open(
52 5 : poOpenInfo->pszFilename,
53 : GDAL_OF_RASTER | GDAL_OF_MULTIDIM_RASTER |
54 : GDAL_OF_VECTOR,
55 5 : apszAllowedDriver, nullptr, nullptr)) != nullptr;
56 : }
57 198 : return false;
58 4856 : };
59 :
60 4856 : if (memcmp(poOpenInfo->pabyHeader, achSignature, 8) == 0 ||
61 4650 : (poOpenInfo->nHeaderBytes > 512 + 8 &&
62 3333 : memcmp(poOpenInfo->pabyHeader + 512, achSignature, 8) == 0))
63 : {
64 206 : if (poOpenInfo->IsSingleAllowedDriver("HDF5"))
65 : {
66 4 : return TRUE;
67 : }
68 :
69 : // The tests to avoid opening KEA and BAG drivers are not
70 : // necessary when drivers are built in the core lib, as they
71 : // are registered after HDF5, but in the case of plugins, we
72 : // cannot do assumptions about the registration order.
73 :
74 : // Avoid opening kea files if the kea driver is available.
75 202 : if (EQUAL(osExt, "KEA") && GDALGetDriverByName("KEA") != nullptr)
76 : {
77 0 : return FALSE;
78 : }
79 :
80 : // Avoid opening BAG files if the bag driver is available.
81 202 : if (EQUAL(osExt, "BAG") && GDALGetDriverByName("BAG") != nullptr)
82 : {
83 1 : return FALSE;
84 : }
85 :
86 : // Avoid opening NC files if the netCDF driver is available and
87 : // they are recognized by it.
88 201 : if (IsRecognizedByNetCDFDriver())
89 : {
90 3 : return FALSE;
91 : }
92 :
93 198 : return TRUE;
94 : }
95 :
96 4650 : if (memcmp(poOpenInfo->pabyHeader, "<HDF_UserBlock>", 15) == 0)
97 : {
98 0 : return TRUE;
99 : }
100 :
101 : // The HDF5 signature can be at offsets 512, 1024, 2048, etc.
102 9246 : if (poOpenInfo->fpL != nullptr &&
103 4596 : (EQUAL(osExt, "h5") || EQUAL(osExt, "hdf5") || EQUAL(osExt, "nc") ||
104 4582 : EQUAL(osExt, "cdf") || EQUAL(osExt, "nc4") ||
105 4582 : poOpenInfo->IsSingleAllowedDriver("HDF5")))
106 : {
107 16 : vsi_l_offset nOffset = 512;
108 40 : for (int i = 0; i < 64; i++)
109 : {
110 : GByte abyBuf[8];
111 80 : if (VSIFSeekL(poOpenInfo->fpL, nOffset, SEEK_SET) != 0 ||
112 40 : VSIFReadL(abyBuf, 1, 8, poOpenInfo->fpL) != 8)
113 : {
114 10 : break;
115 : }
116 30 : if (memcmp(abyBuf, achSignature, 8) == 0)
117 : {
118 6 : if (poOpenInfo->IsSingleAllowedDriver("HDF5"))
119 : {
120 6 : return TRUE;
121 : }
122 : // Avoid opening NC files if the netCDF driver is available and
123 : // they are recognized by it.
124 2 : if (IsRecognizedByNetCDFDriver())
125 : {
126 0 : return FALSE;
127 : }
128 :
129 2 : return TRUE;
130 : }
131 24 : nOffset *= 2;
132 : }
133 : }
134 :
135 4644 : return FALSE;
136 : }
137 :
138 : /************************************************************************/
139 : /* HDF5ImageDatasetIdentify() */
140 : /************************************************************************/
141 :
142 60776 : int HDF5ImageDatasetIdentify(GDALOpenInfo *poOpenInfo)
143 :
144 : {
145 60776 : if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF5:"))
146 60715 : return FALSE;
147 :
148 61 : return TRUE;
149 : }
150 :
151 : /************************************************************************/
152 : /* HDF5DriverGetSubdatasetInfo() */
153 : /************************************************************************/
154 :
155 : struct HDF5DriverSubdatasetInfo final : public GDALSubdatasetInfo
156 : {
157 : public:
158 40 : explicit HDF5DriverSubdatasetInfo(const std::string &fileName)
159 40 : : GDALSubdatasetInfo(fileName)
160 : {
161 40 : }
162 :
163 : // GDALSubdatasetInfo interface
164 : private:
165 : void parseFileName() override;
166 : };
167 :
168 40 : void HDF5DriverSubdatasetInfo::parseFileName()
169 : {
170 :
171 40 : if (!STARTS_WITH_CI(m_fileName.c_str(), "HDF5:"))
172 : {
173 0 : return;
174 : }
175 :
176 80 : CPLStringList aosParts{CSLTokenizeString2(m_fileName.c_str(), ":", 0)};
177 40 : const int iPartsCount{CSLCount(aosParts)};
178 :
179 40 : if (iPartsCount >= 3)
180 : {
181 :
182 38 : m_driverPrefixComponent = aosParts[0];
183 :
184 76 : std::string part1{aosParts[1]};
185 38 : if (!part1.empty() && part1[0] == '"')
186 : {
187 34 : part1 = part1.substr(1);
188 : }
189 :
190 38 : int subdatasetIndex{2};
191 : const bool hasDriveLetter{
192 38 : part1.length() == 1 &&
193 44 : std::isalpha(static_cast<unsigned char>(part1.at(0))) &&
194 6 : (strlen(aosParts[2]) > 1 &&
195 5 : (aosParts[2][0] == '\\' ||
196 3 : (aosParts[2][0] == '/' && aosParts[2][1] != '/')))};
197 :
198 75 : const bool hasProtocol{part1 == "/vsicurl/http" ||
199 74 : part1 == "/vsicurl/https" ||
200 112 : part1 == "/vsicurl_streaming/http" ||
201 37 : part1 == "/vsicurl_streaming/https"};
202 :
203 38 : m_pathComponent = aosParts[1];
204 :
205 38 : if (hasDriveLetter || hasProtocol)
206 : {
207 5 : m_pathComponent.append(":");
208 5 : m_pathComponent.append(aosParts[2]);
209 5 : subdatasetIndex++;
210 : }
211 :
212 38 : if (iPartsCount > subdatasetIndex)
213 : {
214 38 : m_subdatasetComponent = aosParts[subdatasetIndex];
215 :
216 : // Append any remaining part
217 38 : for (int i = subdatasetIndex + 1; i < iPartsCount; ++i)
218 : {
219 0 : m_subdatasetComponent.append(":");
220 0 : m_subdatasetComponent.append(aosParts[i]);
221 : }
222 : }
223 : }
224 : }
225 :
226 2736 : static GDALSubdatasetInfo *HDF5DriverGetSubdatasetInfo(const char *pszFileName)
227 : {
228 2736 : if (STARTS_WITH_CI(pszFileName, "HDF5:"))
229 : {
230 : std::unique_ptr<GDALSubdatasetInfo> info =
231 40 : std::make_unique<HDF5DriverSubdatasetInfo>(pszFileName);
232 118 : if (!info->GetSubdatasetComponent().empty() &&
233 78 : !info->GetPathComponent().empty())
234 : {
235 38 : return info.release();
236 : }
237 : }
238 2698 : return nullptr;
239 : }
240 :
241 : /************************************************************************/
242 : /* IdentifySxx() */
243 : /************************************************************************/
244 :
245 185288 : static bool IdentifySxx(GDALOpenInfo *poOpenInfo, const char *pszDriverName,
246 : const char *pszConfigOption,
247 : const char *pszMainGroupName)
248 : {
249 185288 : if (STARTS_WITH(poOpenInfo->pszFilename, pszDriverName) &&
250 188 : poOpenInfo->pszFilename[strlen(pszDriverName)] == ':')
251 188 : return TRUE;
252 :
253 : // Is it an HDF5 file?
254 : static const char achSignature[] = "\211HDF\r\n\032\n";
255 :
256 185100 : if (poOpenInfo->pabyHeader == nullptr ||
257 14492 : memcmp(poOpenInfo->pabyHeader, achSignature, 8) != 0)
258 184541 : return FALSE;
259 :
260 559 : if (poOpenInfo->IsSingleAllowedDriver(pszDriverName))
261 : {
262 35 : return TRUE;
263 : }
264 :
265 : // GDAL_Sxxx_IDENTIFY can be set to NO only for tests, to test that
266 : // HDF5Dataset::Open() can redirect to Sxxx if the below logic fails
267 524 : if (CPLTestBool(CPLGetConfigOption(pszConfigOption, "YES")))
268 : {
269 : // The below identification logic may be a bit fragile...
270 : // Works at least on:
271 : // - /vsis3/noaa-s102-pds/ed2.1.0/national_bathymetric_source/boston/dcf2/tiles/102US00_US4MA1GC.h5
272 : // - https://datahub.admiralty.co.uk/portal/sharing/rest/content/items/6fd07bde26124d48820b6dee60695389/data (S-102_Liverpool_Trial_Cells.zip)
273 523 : const int nLenMainGroup = static_cast<int>(strlen(pszMainGroupName));
274 523 : const int nLenGroupF = static_cast<int>(strlen("Group_F"));
275 523 : const int nLenProductSpecification =
276 : static_cast<int>(strlen("productSpecification"));
277 523 : bool bFoundMainGroup = false;
278 523 : bool bFoundGroupF = false;
279 523 : bool bFoundProductSpecification = false;
280 563 : for (int iTry = 0; iTry < 2; ++iTry)
281 : {
282 870267 : for (int i = 0; i <= poOpenInfo->nHeaderBytes - nLenGroupF; ++i)
283 : {
284 869863 : if (i <= poOpenInfo->nHeaderBytes - nLenMainGroup &&
285 866803 : poOpenInfo->pabyHeader[i] == pszMainGroupName[0] &&
286 714 : memcmp(poOpenInfo->pabyHeader + i, pszMainGroupName,
287 : nLenMainGroup) == 0)
288 : {
289 170 : bFoundMainGroup = true;
290 170 : if (bFoundGroupF)
291 0 : return true;
292 : }
293 869863 : if (poOpenInfo->pabyHeader[i] == 'G' &&
294 548 : memcmp(poOpenInfo->pabyHeader + i, "Group_F", nLenGroupF) ==
295 : 0)
296 : {
297 196 : bFoundGroupF = true;
298 196 : if (bFoundMainGroup)
299 159 : return true;
300 : }
301 869704 : if (i <= poOpenInfo->nHeaderBytes - nLenProductSpecification &&
302 864452 : poOpenInfo->pabyHeader[i] == 'p' &&
303 857 : memcmp(poOpenInfo->pabyHeader + i, "productSpecification",
304 : nLenProductSpecification) == 0)
305 : {
306 : // For 102DE00OS08J.H5
307 151 : bFoundProductSpecification = true;
308 : }
309 : }
310 515 : if (!(iTry == 0 && bFoundProductSpecification &&
311 111 : poOpenInfo->nHeaderBytes == 1024 &&
312 40 : poOpenInfo->TryToIngest(4096)))
313 : {
314 364 : break;
315 : }
316 : }
317 : }
318 :
319 365 : return false;
320 : }
321 :
322 : /************************************************************************/
323 : /* S102DatasetIdentify() */
324 : /************************************************************************/
325 :
326 61774 : int S102DatasetIdentify(GDALOpenInfo *poOpenInfo)
327 :
328 : {
329 61774 : return IdentifySxx(poOpenInfo, "S102", "GDAL_S102_IDENTIFY",
330 61774 : "BathymetryCoverage");
331 : }
332 :
333 : /************************************************************************/
334 : /* S104DatasetIdentify() */
335 : /************************************************************************/
336 :
337 61795 : int S104DatasetIdentify(GDALOpenInfo *poOpenInfo)
338 :
339 : {
340 61795 : return IdentifySxx(poOpenInfo, "S104", "GDAL_S104_IDENTIFY", "WaterLevel");
341 : }
342 :
343 : /************************************************************************/
344 : /* S111DatasetIdentify() */
345 : /************************************************************************/
346 :
347 61719 : int S111DatasetIdentify(GDALOpenInfo *poOpenInfo)
348 :
349 : {
350 61719 : return IdentifySxx(poOpenInfo, "S111", "GDAL_S111_IDENTIFY",
351 61719 : "SurfaceCurrent");
352 : }
353 :
354 : /************************************************************************/
355 : /* BAGDatasetIdentify() */
356 : /************************************************************************/
357 :
358 72675 : int BAGDatasetIdentify(GDALOpenInfo *poOpenInfo)
359 :
360 : {
361 72675 : if (STARTS_WITH(poOpenInfo->pszFilename, "BAG:"))
362 30 : return TRUE;
363 :
364 : // Is it an HDF5 file?
365 : static const char achSignature[] = "\211HDF\r\n\032\n";
366 :
367 72645 : if (poOpenInfo->pabyHeader == nullptr ||
368 13189 : memcmp(poOpenInfo->pabyHeader, achSignature, 8) != 0)
369 72345 : return FALSE;
370 :
371 : // Does it have the extension .bag?
372 300 : if (!poOpenInfo->IsExtensionEqualToCI("bag"))
373 : {
374 164 : if (poOpenInfo->IsSingleAllowedDriver("BAG"))
375 : {
376 1 : return TRUE;
377 : }
378 163 : return FALSE;
379 : }
380 :
381 136 : return TRUE;
382 : }
383 :
384 : /************************************************************************/
385 : /* HDF5DriverSetCommonMetadata() */
386 : /************************************************************************/
387 :
388 1789 : void HDF5DriverSetCommonMetadata(GDALDriver *poDriver)
389 : {
390 1789 : poDriver->SetDescription(HDF5_DRIVER_NAME);
391 1789 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
392 1789 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
393 1789 : "Hierarchical Data Format Release 5");
394 1789 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/hdf5.html");
395 1789 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "h5 hdf5");
396 1789 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
397 1789 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
398 :
399 1789 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
400 :
401 1789 : poDriver->pfnIdentify = HDF5DatasetIdentify;
402 1789 : poDriver->pfnGetSubdatasetInfoFunc = HDF5DriverGetSubdatasetInfo;
403 1789 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
404 1789 : }
405 :
406 : /************************************************************************/
407 : /* HDF5ImageDriverSetCommonMetadata() */
408 : /************************************************************************/
409 :
410 1789 : void HDF5ImageDriverSetCommonMetadata(GDALDriver *poDriver)
411 : {
412 1789 : poDriver->SetDescription(HDF5_IMAGE_DRIVER_NAME);
413 1789 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
414 1789 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "HDF5 Dataset");
415 1789 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/hdf5.html");
416 1789 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
417 :
418 1789 : poDriver->pfnIdentify = HDF5ImageDatasetIdentify;
419 1789 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
420 1789 : }
421 :
422 : /************************************************************************/
423 : /* BAGDriverSetCommonMetadata() */
424 : /************************************************************************/
425 :
426 1789 : void BAGDriverSetCommonMetadata(GDALDriver *poDriver)
427 : {
428 1789 : poDriver->SetDescription(BAG_DRIVER_NAME);
429 1789 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
430 1789 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
431 1789 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Bathymetry Attributed Grid");
432 1789 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/bag.html");
433 1789 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
434 1789 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "bag");
435 :
436 1789 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Float32");
437 :
438 1789 : poDriver->SetMetadataItem(
439 : GDAL_DMD_OPENOPTIONLIST,
440 : "<OpenOptionList>"
441 : " <Option name='MODE' type='string-select' default='AUTO'>"
442 : " <Value>AUTO</Value>"
443 : " <Value>LOW_RES_GRID</Value>"
444 : " <Value>LIST_SUPERGRIDS</Value>"
445 : " <Value>RESAMPLED_GRID</Value>"
446 : " <Value>INTERPOLATED</Value>"
447 : " </Option>"
448 : " <Option name='SUPERGRIDS_INDICES' type='string' description="
449 : "'Tuple(s) (y1,x1),(y2,x2),... of supergrids, by indices, to expose "
450 : "as subdatasets'/>"
451 : " <Option name='MINX' type='float' description='Minimum X value of "
452 : "area of interest'/>"
453 : " <Option name='MINY' type='float' description='Minimum Y value of "
454 : "area of interest'/>"
455 : " <Option name='MAXX' type='float' description='Maximum X value of "
456 : "area of interest'/>"
457 : " <Option name='MAXY' type='float' description='Maximum Y value of "
458 : "area of interest'/>"
459 : " <Option name='RESX' type='float' description="
460 : "'Horizontal resolution. Only used for "
461 : "MODE=RESAMPLED_GRID/INTERPOLATED'/>"
462 : " <Option name='RESY' type='float' description="
463 : "'Vertical resolution (positive value). Only used for "
464 : "MODE=RESAMPLED_GRID/INTERPOLATED'/>"
465 : " <Option name='RES_STRATEGY' type='string-select' description="
466 : "'Which strategy to apply to select the resampled grid resolution. "
467 : "Only used for MODE=RESAMPLED_GRID/INTERPOLATED' default='AUTO'>"
468 : " <Value>AUTO</Value>"
469 : " <Value>MIN</Value>"
470 : " <Value>MAX</Value>"
471 : " <Value>MEAN</Value>"
472 : " </Option>"
473 : " <Option name='RES_FILTER_MIN' type='float' description="
474 : "'Minimum resolution of supergrids to take into account (excluded "
475 : "bound). "
476 : "Only used for MODE=RESAMPLED_GRID, INTERPOLATED or LIST_SUPERGRIDS' "
477 : "default='0'/>"
478 : " <Option name='RES_FILTER_MAX' type='float' description="
479 : "'Maximum resolution of supergrids to take into account (included "
480 : "bound). "
481 : "Only used for MODE=RESAMPLED_GRID, INTERPOLATED or LIST_SUPERGRIDS' "
482 : "default='inf'/>"
483 : " <Option name='VALUE_POPULATION' type='string-select' description="
484 : "'Which value population strategy to apply to compute the resampled "
485 : "cell "
486 : "values. Only used for MODE=RESAMPLED_GRID' default='MAX'>"
487 : " <Value>MIN</Value>"
488 : " <Value>MAX</Value>"
489 : " <Value>MEAN</Value>"
490 : " <Value>COUNT</Value>"
491 : " </Option>"
492 : " <Option name='SUPERGRIDS_MASK' type='boolean' description="
493 : "'Whether the dataset should consist of a mask band indicating if a "
494 : "supergrid node matches each target pixel. Only used for "
495 : "MODE=RESAMPLED_GRID' default='NO'/>"
496 : " <Option name='NODATA_VALUE' type='float' default='1000000'/>"
497 : " <Option name='REPORT_VERTCRS' type='boolean' default='YES'/>"
498 1789 : "</OpenOptionList>");
499 :
500 1789 : poDriver->SetMetadataItem(
501 : GDAL_DMD_CREATIONOPTIONLIST,
502 : "<CreationOptionList>"
503 : " <Option name='VAR_*' type='string' description="
504 : "'Value to substitute to a variable in the template'/>"
505 : " <Option name='TEMPLATE' type='string' description="
506 : "'.xml template to use'/>"
507 : " <Option name='BAG_VERSION' type='string' description="
508 : "'Version to write in the Bag Version attribute' default='1.6.2'/>"
509 : " <Option name='COMPRESS' type='string-select' default='DEFLATE'>"
510 : " <Value>NONE</Value>"
511 : " <Value>DEFLATE</Value>"
512 : " </Option>"
513 : " <Option name='ZLEVEL' type='int' "
514 : "description='DEFLATE compression level 1-9' default='6' />"
515 : " <Option name='BLOCK_SIZE' type='int' description='Chunk size' />"
516 1789 : "</CreationOptionList>");
517 :
518 1789 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
519 :
520 1789 : poDriver->pfnIdentify = BAGDatasetIdentify;
521 1789 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
522 1789 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
523 1789 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
524 1789 : }
525 :
526 : /************************************************************************/
527 : /* S102DriverSetCommonMetadata() */
528 : /************************************************************************/
529 :
530 1789 : void S102DriverSetCommonMetadata(GDALDriver *poDriver)
531 : {
532 1789 : poDriver->SetDescription(S102_DRIVER_NAME);
533 1789 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
534 1789 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
535 1789 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
536 1789 : "S-102 Bathymetric Surface Product");
537 1789 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/s102.html");
538 1789 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
539 1789 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "h5");
540 1789 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
541 1789 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_SUBDATASETS, "YES");
542 :
543 1789 : poDriver->SetMetadataItem(
544 : GDAL_DMD_OPENOPTIONLIST,
545 : "<OpenOptionList>"
546 : " <Option name='DEPTH_OR_ELEVATION' type='string-select' "
547 : "default='DEPTH'>"
548 : " <Value>DEPTH</Value>"
549 : " <Value>ELEVATION</Value>"
550 : " </Option>"
551 : " <Option name='NORTH_UP' type='boolean' default='YES' "
552 : "description='Whether the top line of the dataset should be the "
553 : "northern-most one'/>"
554 1789 : "</OpenOptionList>");
555 :
556 1789 : poDriver->SetMetadataItem(
557 : GDAL_DMD_CREATIONOPTIONLIST,
558 : "<CreationOptionList>"
559 : " <Option name='VERTICAL_DATUM' type='string' description="
560 : "'Vertical datum abbreviation or code (required)'/>"
561 : " <Option name='ISSUE_DATE' type='string' description="
562 : "'Issue date as YYYYMMDD'/>"
563 : " <Option name='ISSUE_TIME' type='string' description="
564 : "'Issue time as hhmmssZ or hhmmss[+-]HHMM'/>"
565 : " <Option name='HORIZONTAL_POSITION_UNCERTAINTY' type='float' "
566 : "description='Horizontal position uncertainty in meter'/>"
567 : " <Option name='VERTICAL_UNCERTAINTY' type='float' "
568 : "description='Vertical uncertainty in meter'/>"
569 : " <Option name='QUALITY_DATASET' type='string' description="
570 : "'Path to a dataset with the quality of bathymetric coverage'/>"
571 : " <Option name='COMPRESS' type='string-select' default='DEFLATE'>"
572 : " <Value>NONE</Value>"
573 : " <Value>DEFLATE</Value>"
574 : " </Option>"
575 : " <Option name='ZLEVEL' type='int' "
576 : "description='DEFLATE compression level 1-9' default='6' />"
577 : " <Option name='BLOCK_SIZE' type='int' description='Chunk size' />"
578 1789 : "</CreationOptionList>");
579 :
580 1789 : poDriver->pfnIdentify = S102DatasetIdentify;
581 1789 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
582 1789 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
583 1789 : }
584 :
585 : /************************************************************************/
586 : /* S104DriverSetCommonMetadata() */
587 : /************************************************************************/
588 :
589 1789 : void S104DriverSetCommonMetadata(GDALDriver *poDriver)
590 : {
591 1789 : poDriver->SetDescription(S104_DRIVER_NAME);
592 1789 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
593 1789 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
594 1789 : poDriver->SetMetadataItem(
595 : GDAL_DMD_LONGNAME,
596 1789 : "S-104 Water Level Information for Surface Navigation Product");
597 1789 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/s104.html");
598 1789 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
599 1789 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "h5");
600 1789 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
601 1789 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_SUBDATASETS, "YES");
602 :
603 1789 : poDriver->SetMetadataItem(
604 : GDAL_DMD_OPENOPTIONLIST,
605 : "<OpenOptionList>"
606 : " <Option name='NORTH_UP' type='boolean' default='YES' "
607 : "description='Whether the top line of the dataset should be the "
608 : "northern-most one'/>"
609 1789 : "</OpenOptionList>");
610 :
611 1789 : poDriver->SetMetadataItem(
612 : GDAL_DMD_CREATIONOPTIONLIST,
613 : "<CreationOptionList>"
614 : " <Option name='TIME_POINT' type='string' description="
615 : "'Timestamp as YYYYMMDDTHHMMSSZ format (required)'/>"
616 : " <Option name='VERTICAL_DATUM' type='string' description="
617 : "'Vertical datum abbreviation or code (required)'/>"
618 : " <Option name='VERTICAL_CS' type='string-select' description="
619 : "'Vertical coordinate system (required).'>"
620 : " <Value alias='6498'>DEPTH</Value>"
621 : " <Value alias='6499'>HEIGHT</Value>"
622 : " </Option>"
623 : " <Option name='WATER_LEVEL_TREND_THRESHOLD' type='float' description="
624 : "'Critical value used to determine steady water level trend (required)."
625 : "Units are meters/hour (m/hr)'/>"
626 : " <Option name='DATA_DYNAMICITY' type='string-select' description="
627 : "'Classification of data according to the relationship between the "
628 : "time of its collection, generation, or calculation of generation "
629 : "parameters, in relation to the time of publication of the dataset "
630 : "(required).'>"
631 : " <Value alias='1'>observation</Value>"
632 : " <Value alias='2'>astronomicalPrediction</Value>"
633 : " <Value alias='3'>analysisOrHybrid</Value>"
634 : " <Value alias='5'>hydrodynamicForecast</Value>"
635 : " </Option>"
636 : " <Option name='DATASETS' type='string' description="
637 : "'Comma separated list of datasets at different timestamps.'/>"
638 : " <Option name='DATASETS_TIME_POINT' type='string' description="
639 : "'Comma separated list of the time point value of each dataset of "
640 : "DATASETS.'/>"
641 : " <Option name='GEOGRAPHIC_IDENTIFIER' type='string' description="
642 : "'Description, or location code from list agreed by data producers'/>"
643 : " <Option name='ISSUE_DATE' type='string' description="
644 : "'Issue date as YYYYMMDD'/>"
645 : " <Option name='ISSUE_TIME' type='string' description="
646 : "'Issue time as hhmmssZ or hhmmss[+-]HHMM'/>"
647 : " <Option name='TREND_INTERVAL' type='integer' "
648 : "description='Interval, in minutes, over which trend at a a particular "
649 : "time is calculated'/>"
650 : " <Option name='DATASET_DELIVERY_INTERVAL' type='string' description="
651 : "'Expected time interval between availability of successive datasets "
652 : "for time-varying data. Must be formatted as PnYnMnDTnHnMnS "
653 : "(ISO8601 duration)'/>"
654 : " <Option name='TIME_RECORD_INTERVAL' type='integer' description="
655 : "'Interval in seconds between time records.'/>"
656 : " <Option name='COMMON_POINT_RULE' type='string-select' description="
657 : "'Procedure used for evaluating the coverage at a position that falls "
658 : "on the boundary or in an area of overlap between geographic objects' "
659 : "default='all'>"
660 : " <Value alias='1'>average</Value>"
661 : " <Value alias='2'>low</Value>"
662 : " <Value alias='3'>high</Value>"
663 : " <Value alias='4'>all</Value>"
664 : " </Option>"
665 : " <Option name='UNCERTAINTY' type='float' "
666 : "description='Uncertainty of depth values in meter'/>"
667 : " <Option name='HORIZONTAL_POSITION_UNCERTAINTY' type='float' "
668 : "description='Horizontal position uncertainty in meter'/>"
669 : " <Option name='VERTICAL_UNCERTAINTY' type='float' "
670 : "description='Vertical uncertainty in meter'/>"
671 : " <Option name='TIME_UNCERTAINTY' type='float' "
672 : "description='Time uncertainty in second'/>"
673 : " <Option name='COMPRESS' type='string-select' default='DEFLATE'>"
674 : " <Value>NONE</Value>"
675 : " <Value>DEFLATE</Value>"
676 : " </Option>"
677 : " <Option name='ZLEVEL' type='int' "
678 : "description='DEFLATE compression level 1-9' default='6' />"
679 : " <Option name='BLOCK_SIZE' type='int' description='Chunk size' />"
680 1789 : "</CreationOptionList>");
681 :
682 1789 : poDriver->pfnIdentify = S104DatasetIdentify;
683 1789 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
684 1789 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
685 1789 : }
686 :
687 : /************************************************************************/
688 : /* S111DriverSetCommonMetadata() */
689 : /************************************************************************/
690 :
691 1789 : void S111DriverSetCommonMetadata(GDALDriver *poDriver)
692 : {
693 1789 : poDriver->SetDescription(S111_DRIVER_NAME);
694 1789 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
695 1789 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
696 1789 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
697 1789 : "S-111 Surface Currents Product");
698 1789 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/s111.html");
699 1789 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
700 1789 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "h5");
701 1789 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
702 1789 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_SUBDATASETS, "YES");
703 :
704 1789 : poDriver->SetMetadataItem(
705 : GDAL_DMD_OPENOPTIONLIST,
706 : "<OpenOptionList>"
707 : " <Option name='NORTH_UP' type='boolean' default='YES' "
708 : "description='Whether the top line of the dataset should be the "
709 : "northern-most one'/>"
710 1789 : "</OpenOptionList>");
711 :
712 1789 : poDriver->SetMetadataItem(
713 : GDAL_DMD_CREATIONOPTIONLIST,
714 : "<CreationOptionList>"
715 : " <Option name='TIME_POINT' type='string' description="
716 : "'Timestamp as YYYYMMDDTHHMMSSZ format (required)'/>"
717 : " <Option name='DEPTH_TYPE' type='string-select' description="
718 : "'Type of depth (required). When selecting heightOrDepth, "
719 : "the interpretation depends on the VERTICAL_CS value.'>"
720 : " <Value alias='1'>heightOrDepth</Value>"
721 : " <Value alias='2'>layerAverage</Value>"
722 : " </Option>"
723 : " <Option name='VERTICAL_DATUM' type='string' description="
724 : "'Vertical datum abbreviation or code (required if "
725 : "DEPTH_TYPE=heightOrDepth)'/>"
726 : " <Option name='VERTICAL_CS' type='string-select' description="
727 : "'Vertical coordinate system (required if DEPTH_TYPE=heightOrDepth).'>"
728 : " <Value alias='6498'>DEPTH</Value>"
729 : " <Value alias='6499'>HEIGHT</Value>"
730 : " </Option>"
731 : " <Option name='SURFACE_CURRENT_DEPTH' type='float' description="
732 : "'Depth/height value or layer thickness (m) (required)'/>"
733 : " <Option name='DATA_DYNAMICITY' type='string-select' description="
734 : "'Classification of data according to the relationship between the "
735 : "time of its collection, generation, or calculation of generation "
736 : "parameters, in relation to the time of publication of the dataset "
737 : "(required).'>"
738 : " <Value alias='1'>observation</Value>"
739 : " <Value alias='2'>astronomicalPrediction</Value>"
740 : " <Value alias='3'>analysisOrHybrid</Value>"
741 : " <Value alias='5'>hydrodynamicForecast</Value>"
742 : " </Option>"
743 : " <Option name='DATASETS' type='string' description="
744 : "'Comma separated list of datasets at different timestamps.'/>"
745 : " <Option name='DATASETS_TIME_POINT' type='string' description="
746 : "'Comma separated list of the time point value of each dataset of "
747 : "DATASETS.'/>"
748 : " <Option name='GEOGRAPHIC_IDENTIFIER' type='string' description="
749 : "'Description, or location code from list agreed by data producers'/>"
750 : " <Option name='ISSUE_DATE' type='string' description="
751 : "'Issue date as YYYYMMDD'/>"
752 : " <Option name='ISSUE_TIME' type='string' description="
753 : "'Issue time as hhmmssZ or hhmmss[+-]HHMM'/>"
754 : " <Option name='DATASET_DELIVERY_INTERVAL' type='string' description="
755 : "'Expected time interval between availability of successive datasets "
756 : "for time-varying data. Must be formatted as PnYnMnDTnHnMnS "
757 : "(ISO8601 duration)'/>"
758 : " <Option name='TIME_RECORD_INTERVAL' type='integer' description="
759 : "'Interval in seconds between time records.'/>"
760 : " <Option name='COMMON_POINT_RULE' type='string-select' description="
761 : "'Procedure used for evaluating the coverage at a position that falls "
762 : "on the boundary or in an area of overlap between geographic objects' "
763 : "default='high'>"
764 : " <Value alias='1'>average</Value>"
765 : " <Value alias='2'>low</Value>"
766 : " <Value alias='3'>high</Value>"
767 : " <Value alias='4'>all</Value>"
768 : " </Option>"
769 : " <Option name='UNCERTAINTY_SPEED' type='float' "
770 : "description='Uncertainty of speeds in knot'/>"
771 : " <Option name='UNCERTAINTY_DIRECTION' type='float' "
772 : "description='Uncertainty of direction angles in degree'/>"
773 : " <Option name='HORIZONTAL_POSITION_UNCERTAINTY' type='float' "
774 : "description='Horizontal position uncertainty in meter'/>"
775 : " <Option name='VERTICAL_UNCERTAINTY' type='float' "
776 : "description='Vertical uncertainty in meter'/>"
777 : " <Option name='TIME_UNCERTAINTY' type='float' "
778 : "description='Time uncertainty in second'/>"
779 : " <Option name='COMPRESS' type='string-select' default='DEFLATE'>"
780 : " <Value>NONE</Value>"
781 : " <Value>DEFLATE</Value>"
782 : " </Option>"
783 : " <Option name='ZLEVEL' type='int' "
784 : "description='DEFLATE compression level 1-9' default='6' />"
785 : " <Option name='BLOCK_SIZE' type='int' description='Chunk size' />"
786 1789 : "</CreationOptionList>");
787 :
788 1789 : poDriver->pfnIdentify = S111DatasetIdentify;
789 1789 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
790 1789 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
791 1789 : }
792 :
793 : /************************************************************************/
794 : /* DeclareDeferredHDF5Plugin() */
795 : /************************************************************************/
796 :
797 : #ifdef PLUGIN_FILENAME
798 2058 : void DeclareDeferredHDF5Plugin()
799 : {
800 2058 : if (GDALGetDriverByName(HDF5_DRIVER_NAME) != nullptr)
801 : {
802 283 : return;
803 : }
804 : {
805 1775 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
806 : #ifdef PLUGIN_INSTALLATION_MESSAGE
807 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
808 : PLUGIN_INSTALLATION_MESSAGE);
809 : #endif
810 1775 : HDF5DriverSetCommonMetadata(poDriver);
811 1775 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
812 : }
813 : {
814 1775 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
815 : #ifdef PLUGIN_INSTALLATION_MESSAGE
816 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
817 : PLUGIN_INSTALLATION_MESSAGE);
818 : #endif
819 1775 : HDF5ImageDriverSetCommonMetadata(poDriver);
820 1775 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
821 : }
822 : {
823 1775 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
824 : #ifdef PLUGIN_INSTALLATION_MESSAGE
825 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
826 : PLUGIN_INSTALLATION_MESSAGE);
827 : #endif
828 1775 : BAGDriverSetCommonMetadata(poDriver);
829 1775 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
830 : }
831 : {
832 1775 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
833 : #ifdef PLUGIN_INSTALLATION_MESSAGE
834 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
835 : PLUGIN_INSTALLATION_MESSAGE);
836 : #endif
837 1775 : S102DriverSetCommonMetadata(poDriver);
838 1775 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
839 : }
840 : {
841 1775 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
842 : #ifdef PLUGIN_INSTALLATION_MESSAGE
843 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
844 : PLUGIN_INSTALLATION_MESSAGE);
845 : #endif
846 1775 : S104DriverSetCommonMetadata(poDriver);
847 1775 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
848 : }
849 : {
850 1775 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
851 : #ifdef PLUGIN_INSTALLATION_MESSAGE
852 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
853 : PLUGIN_INSTALLATION_MESSAGE);
854 : #endif
855 1775 : S111DriverSetCommonMetadata(poDriver);
856 1775 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
857 : }
858 : }
859 : #endif
|