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