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 <algorithm>
16 : #include <cctype>
17 :
18 : /************************************************************************/
19 : /* HDF5DatasetIdentify() */
20 : /************************************************************************/
21 :
22 58444 : int HDF5DatasetIdentify(GDALOpenInfo *poOpenInfo)
23 :
24 : {
25 58444 : if ((poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) &&
26 680 : STARTS_WITH(poOpenInfo->pszFilename, "HDF5:"))
27 : {
28 14 : return TRUE;
29 : }
30 :
31 : // Is it an HDF5 file?
32 58430 : constexpr char achSignature[] = "\211HDF\r\n\032\n";
33 :
34 58430 : if (!poOpenInfo->pabyHeader)
35 54778 : return FALSE;
36 :
37 7303 : const CPLString osExt(poOpenInfo->osExtension);
38 :
39 550 : const auto IsRecognizedByNetCDFDriver = [&osExt, poOpenInfo]()
40 : {
41 275 : if ((EQUAL(osExt, "NC") || EQUAL(osExt, "CDF") || EQUAL(osExt, "NC4") ||
42 280 : EQUAL(osExt, "gmac")) &&
43 5 : GDALGetDriverByName("netCDF") != nullptr)
44 : {
45 5 : const char *const apszAllowedDriver[] = {"netCDF", nullptr};
46 5 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
47 10 : return std::unique_ptr<GDALDataset>(GDALDataset::Open(
48 5 : poOpenInfo->pszFilename,
49 : GDAL_OF_RASTER | GDAL_OF_MULTIDIM_RASTER |
50 : GDAL_OF_VECTOR,
51 5 : apszAllowedDriver, nullptr, nullptr)) != nullptr;
52 : }
53 135 : return false;
54 3651 : };
55 :
56 3651 : if (memcmp(poOpenInfo->pabyHeader, achSignature, 8) == 0 ||
57 3508 : (poOpenInfo->nHeaderBytes > 512 + 8 &&
58 2209 : memcmp(poOpenInfo->pabyHeader + 512, achSignature, 8) == 0))
59 : {
60 143 : if (poOpenInfo->IsSingleAllowedDriver("HDF5"))
61 : {
62 4 : return TRUE;
63 : }
64 :
65 : // The tests to avoid opening KEA and BAG drivers are not
66 : // necessary when drivers are built in the core lib, as they
67 : // are registered after HDF5, but in the case of plugins, we
68 : // cannot do assumptions about the registration order.
69 :
70 : // Avoid opening kea files if the kea driver is available.
71 139 : if (EQUAL(osExt, "KEA") && GDALGetDriverByName("KEA") != nullptr)
72 : {
73 0 : return FALSE;
74 : }
75 :
76 : // Avoid opening BAG files if the bag driver is available.
77 139 : if (EQUAL(osExt, "BAG") && GDALGetDriverByName("BAG") != nullptr)
78 : {
79 1 : return FALSE;
80 : }
81 :
82 : // Avoid opening NC files if the netCDF driver is available and
83 : // they are recognized by it.
84 138 : if (IsRecognizedByNetCDFDriver())
85 : {
86 3 : return FALSE;
87 : }
88 :
89 135 : return TRUE;
90 : }
91 :
92 3508 : if (memcmp(poOpenInfo->pabyHeader, "<HDF_UserBlock>", 15) == 0)
93 : {
94 0 : return TRUE;
95 : }
96 :
97 : // The HDF5 signature can be at offsets 512, 1024, 2048, etc.
98 6962 : if (poOpenInfo->fpL != nullptr &&
99 3454 : (EQUAL(osExt, "h5") || EQUAL(osExt, "hdf5") || EQUAL(osExt, "nc") ||
100 3442 : EQUAL(osExt, "cdf") || EQUAL(osExt, "nc4") ||
101 3442 : poOpenInfo->IsSingleAllowedDriver("HDF5")))
102 : {
103 14 : vsi_l_offset nOffset = 512;
104 38 : for (int i = 0; i < 64; i++)
105 : {
106 : GByte abyBuf[8];
107 76 : if (VSIFSeekL(poOpenInfo->fpL, nOffset, SEEK_SET) != 0 ||
108 38 : VSIFReadL(abyBuf, 1, 8, poOpenInfo->fpL) != 8)
109 : {
110 8 : break;
111 : }
112 30 : if (memcmp(abyBuf, achSignature, 8) == 0)
113 : {
114 6 : if (poOpenInfo->IsSingleAllowedDriver("HDF5"))
115 : {
116 6 : return TRUE;
117 : }
118 : // Avoid opening NC files if the netCDF driver is available and
119 : // they are recognized by it.
120 2 : if (IsRecognizedByNetCDFDriver())
121 : {
122 0 : return FALSE;
123 : }
124 :
125 2 : return TRUE;
126 : }
127 24 : nOffset *= 2;
128 : }
129 : }
130 :
131 3502 : return FALSE;
132 : }
133 :
134 : /************************************************************************/
135 : /* HDF5ImageDatasetIdentify() */
136 : /************************************************************************/
137 :
138 57660 : int HDF5ImageDatasetIdentify(GDALOpenInfo *poOpenInfo)
139 :
140 : {
141 57660 : if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF5:"))
142 57601 : return FALSE;
143 :
144 59 : return TRUE;
145 : }
146 :
147 : /************************************************************************/
148 : /* HDF5DriverGetSubdatasetInfo() */
149 : /************************************************************************/
150 :
151 : struct HDF5DriverSubdatasetInfo : public GDALSubdatasetInfo
152 : {
153 : public:
154 12 : explicit HDF5DriverSubdatasetInfo(const std::string &fileName)
155 12 : : GDALSubdatasetInfo(fileName)
156 : {
157 12 : }
158 :
159 : // GDALSubdatasetInfo interface
160 : private:
161 : void parseFileName() override;
162 : };
163 :
164 12 : void HDF5DriverSubdatasetInfo::parseFileName()
165 : {
166 :
167 12 : if (!STARTS_WITH_CI(m_fileName.c_str(), "HDF5:"))
168 : {
169 0 : return;
170 : }
171 :
172 24 : CPLStringList aosParts{CSLTokenizeString2(m_fileName.c_str(), ":", 0)};
173 12 : const int iPartsCount{CSLCount(aosParts)};
174 :
175 12 : if (iPartsCount >= 3)
176 : {
177 :
178 10 : m_driverPrefixComponent = aosParts[0];
179 :
180 20 : std::string part1{aosParts[1]};
181 10 : if (!part1.empty() && part1[0] == '"')
182 : {
183 6 : part1 = part1.substr(1);
184 : }
185 :
186 10 : int subdatasetIndex{2};
187 : const bool hasDriveLetter{
188 10 : part1.length() == 1 &&
189 16 : std::isalpha(static_cast<unsigned char>(part1.at(0))) &&
190 6 : (strlen(aosParts[2]) > 1 &&
191 5 : (aosParts[2][0] == '\\' ||
192 3 : (aosParts[2][0] == '/' && aosParts[2][1] != '/')))};
193 :
194 19 : const bool hasProtocol{part1 == "/vsicurl/http" ||
195 18 : part1 == "/vsicurl/https" ||
196 28 : part1 == "/vsicurl_streaming/http" ||
197 9 : part1 == "/vsicurl_streaming/https"};
198 :
199 10 : m_pathComponent = aosParts[1];
200 :
201 10 : if (hasDriveLetter || hasProtocol)
202 : {
203 5 : m_pathComponent.append(":");
204 5 : m_pathComponent.append(aosParts[2]);
205 5 : subdatasetIndex++;
206 : }
207 :
208 10 : if (iPartsCount > subdatasetIndex)
209 : {
210 10 : m_subdatasetComponent = aosParts[subdatasetIndex];
211 :
212 : // Append any remaining part
213 10 : for (int i = subdatasetIndex + 1; i < iPartsCount; ++i)
214 : {
215 0 : m_subdatasetComponent.append(":");
216 0 : m_subdatasetComponent.append(aosParts[i]);
217 : }
218 : }
219 : }
220 : }
221 :
222 2697 : static GDALSubdatasetInfo *HDF5DriverGetSubdatasetInfo(const char *pszFileName)
223 : {
224 2697 : if (STARTS_WITH_CI(pszFileName, "HDF5:"))
225 : {
226 : std::unique_ptr<GDALSubdatasetInfo> info =
227 12 : std::make_unique<HDF5DriverSubdatasetInfo>(pszFileName);
228 34 : if (!info->GetSubdatasetComponent().empty() &&
229 22 : !info->GetPathComponent().empty())
230 : {
231 10 : return info.release();
232 : }
233 : }
234 2687 : return nullptr;
235 : }
236 :
237 : /************************************************************************/
238 : /* IdentifySxx() */
239 : /************************************************************************/
240 :
241 175168 : static bool IdentifySxx(GDALOpenInfo *poOpenInfo, const char *pszDriverName,
242 : const char *pszConfigOption,
243 : const char *pszMainGroupName)
244 : {
245 175168 : if (STARTS_WITH(poOpenInfo->pszFilename, pszDriverName) &&
246 34 : poOpenInfo->pszFilename[strlen(pszDriverName)] == ':')
247 34 : return TRUE;
248 :
249 : // Is it an HDF5 file?
250 : static const char achSignature[] = "\211HDF\r\n\032\n";
251 :
252 175134 : if (poOpenInfo->pabyHeader == nullptr ||
253 10766 : memcmp(poOpenInfo->pabyHeader, achSignature, 8) != 0)
254 174873 : return FALSE;
255 :
256 261 : if (poOpenInfo->IsSingleAllowedDriver(pszDriverName))
257 : {
258 1 : return TRUE;
259 : }
260 :
261 : // GDAL_Sxxx_IDENTIFY can be set to NO only for tests, to test that
262 : // HDF5Dataset::Open() can redirect to Sxxx if the below logic fails
263 260 : if (CPLTestBool(CPLGetConfigOption(pszConfigOption, "YES")))
264 : {
265 : // The below identification logic may be a bit fragile...
266 : // Works at least on:
267 : // - /vsis3/noaa-s102-pds/ed2.1.0/national_bathymetric_source/boston/dcf2/tiles/102US00_US4MA1GC.h5
268 : // - https://datahub.admiralty.co.uk/portal/sharing/rest/content/items/6fd07bde26124d48820b6dee60695389/data (S-102_Liverpool_Trial_Cells.zip)
269 259 : const int nLenMainGroup = static_cast<int>(strlen(pszMainGroupName));
270 259 : const int nLenGroupF = static_cast<int>(strlen("Group_F"));
271 259 : const int nLenProductSpecification =
272 : static_cast<int>(strlen("productSpecification"));
273 259 : bool bFoundMainGroup = false;
274 259 : bool bFoundGroupF = false;
275 259 : bool bFoundProductSpecification = false;
276 259 : for (int iTry = 0; iTry < 2; ++iTry)
277 : {
278 253301 : for (int i = 0; i <= poOpenInfo->nHeaderBytes - nLenGroupF; ++i)
279 : {
280 253080 : if (i <= poOpenInfo->nHeaderBytes - nLenMainGroup &&
281 251529 : poOpenInfo->pabyHeader[i] == pszMainGroupName[0] &&
282 152 : memcmp(poOpenInfo->pabyHeader + i, pszMainGroupName,
283 : nLenMainGroup) == 0)
284 : {
285 38 : bFoundMainGroup = true;
286 38 : if (bFoundGroupF)
287 0 : return true;
288 : }
289 253080 : if (poOpenInfo->pabyHeader[i] == 'G' &&
290 225 : memcmp(poOpenInfo->pabyHeader + i, "Group_F", nLenGroupF) ==
291 : 0)
292 : {
293 46 : bFoundGroupF = true;
294 46 : if (bFoundMainGroup)
295 38 : return true;
296 : }
297 253042 : if (i <= poOpenInfo->nHeaderBytes - nLenProductSpecification &&
298 250169 : poOpenInfo->pabyHeader[i] == 'p' &&
299 221 : memcmp(poOpenInfo->pabyHeader + i, "productSpecification",
300 : nLenProductSpecification) == 0)
301 : {
302 : // For 102DE00OS08J.H5
303 0 : bFoundProductSpecification = true;
304 : }
305 : }
306 221 : if (!(iTry == 0 && bFoundProductSpecification &&
307 0 : poOpenInfo->nHeaderBytes == 1024 &&
308 0 : poOpenInfo->TryToIngest(4096)))
309 : {
310 221 : break;
311 : }
312 : }
313 : }
314 :
315 222 : return false;
316 : }
317 :
318 : /************************************************************************/
319 : /* S102DatasetIdentify() */
320 : /************************************************************************/
321 :
322 58425 : int S102DatasetIdentify(GDALOpenInfo *poOpenInfo)
323 :
324 : {
325 58425 : return IdentifySxx(poOpenInfo, "S102", "GDAL_S102_IDENTIFY",
326 58423 : "BathymetryCoverage");
327 : }
328 :
329 : /************************************************************************/
330 : /* S104DatasetIdentify() */
331 : /************************************************************************/
332 :
333 58376 : int S104DatasetIdentify(GDALOpenInfo *poOpenInfo)
334 :
335 : {
336 58376 : return IdentifySxx(poOpenInfo, "S104", "GDAL_S104_IDENTIFY", "WaterLevel");
337 : }
338 :
339 : /************************************************************************/
340 : /* S111DatasetIdentify() */
341 : /************************************************************************/
342 :
343 58369 : int S111DatasetIdentify(GDALOpenInfo *poOpenInfo)
344 :
345 : {
346 58369 : return IdentifySxx(poOpenInfo, "S111", "GDAL_S111_IDENTIFY",
347 58370 : "SurfaceCurrent");
348 : }
349 :
350 : /************************************************************************/
351 : /* BAGDatasetIdentify() */
352 : /************************************************************************/
353 :
354 68903 : int BAGDatasetIdentify(GDALOpenInfo *poOpenInfo)
355 :
356 : {
357 68903 : if (STARTS_WITH(poOpenInfo->pszFilename, "BAG:"))
358 30 : return TRUE;
359 :
360 : // Is it an HDF5 file?
361 : static const char achSignature[] = "\211HDF\r\n\032\n";
362 :
363 68873 : if (poOpenInfo->pabyHeader == nullptr ||
364 11599 : memcmp(poOpenInfo->pabyHeader, achSignature, 8) != 0)
365 68634 : return FALSE;
366 :
367 : // Does it have the extension .bag?
368 239 : if (!poOpenInfo->IsExtensionEqualToCI("bag"))
369 : {
370 103 : if (poOpenInfo->IsSingleAllowedDriver("BAG"))
371 : {
372 1 : return TRUE;
373 : }
374 102 : return FALSE;
375 : }
376 :
377 136 : return TRUE;
378 : }
379 :
380 : /************************************************************************/
381 : /* HDF5DriverSetCommonMetadata() */
382 : /************************************************************************/
383 :
384 1689 : void HDF5DriverSetCommonMetadata(GDALDriver *poDriver)
385 : {
386 1689 : poDriver->SetDescription(HDF5_DRIVER_NAME);
387 1689 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
388 1689 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
389 1689 : "Hierarchical Data Format Release 5");
390 1689 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/hdf5.html");
391 1689 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "h5 hdf5");
392 1689 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
393 1689 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
394 :
395 1689 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
396 :
397 1689 : poDriver->pfnIdentify = HDF5DatasetIdentify;
398 1689 : poDriver->pfnGetSubdatasetInfoFunc = HDF5DriverGetSubdatasetInfo;
399 1689 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
400 1689 : }
401 :
402 : /************************************************************************/
403 : /* HDF5ImageDriverSetCommonMetadata() */
404 : /************************************************************************/
405 :
406 1689 : void HDF5ImageDriverSetCommonMetadata(GDALDriver *poDriver)
407 : {
408 1689 : poDriver->SetDescription(HDF5_IMAGE_DRIVER_NAME);
409 1689 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
410 1689 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "HDF5 Dataset");
411 1689 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/hdf5.html");
412 1689 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
413 :
414 1689 : poDriver->pfnIdentify = HDF5ImageDatasetIdentify;
415 1689 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
416 1689 : }
417 :
418 : /************************************************************************/
419 : /* BAGDriverSetCommonMetadata() */
420 : /************************************************************************/
421 :
422 1689 : void BAGDriverSetCommonMetadata(GDALDriver *poDriver)
423 : {
424 1689 : poDriver->SetDescription(BAG_DRIVER_NAME);
425 1689 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
426 1689 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
427 1689 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Bathymetry Attributed Grid");
428 1689 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/bag.html");
429 1689 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
430 1689 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "bag");
431 :
432 1689 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Float32");
433 :
434 1689 : poDriver->SetMetadataItem(
435 : GDAL_DMD_OPENOPTIONLIST,
436 : "<OpenOptionList>"
437 : " <Option name='MODE' type='string-select' default='AUTO'>"
438 : " <Value>AUTO</Value>"
439 : " <Value>LOW_RES_GRID</Value>"
440 : " <Value>LIST_SUPERGRIDS</Value>"
441 : " <Value>RESAMPLED_GRID</Value>"
442 : " <Value>INTERPOLATED</Value>"
443 : " </Option>"
444 : " <Option name='SUPERGRIDS_INDICES' type='string' description="
445 : "'Tuple(s) (y1,x1),(y2,x2),... of supergrids, by indices, to expose "
446 : "as subdatasets'/>"
447 : " <Option name='MINX' type='float' description='Minimum X value of "
448 : "area of interest'/>"
449 : " <Option name='MINY' type='float' description='Minimum Y value of "
450 : "area of interest'/>"
451 : " <Option name='MAXX' type='float' description='Maximum X value of "
452 : "area of interest'/>"
453 : " <Option name='MAXY' type='float' description='Maximum Y value of "
454 : "area of interest'/>"
455 : " <Option name='RESX' type='float' description="
456 : "'Horizontal resolution. Only used for "
457 : "MODE=RESAMPLED_GRID/INTERPOLATED'/>"
458 : " <Option name='RESY' type='float' description="
459 : "'Vertical resolution (positive value). Only used for "
460 : "MODE=RESAMPLED_GRID/INTERPOLATED'/>"
461 : " <Option name='RES_STRATEGY' type='string-select' description="
462 : "'Which strategy to apply to select the resampled grid resolution. "
463 : "Only used for MODE=RESAMPLED_GRID/INTERPOLATED' default='AUTO'>"
464 : " <Value>AUTO</Value>"
465 : " <Value>MIN</Value>"
466 : " <Value>MAX</Value>"
467 : " <Value>MEAN</Value>"
468 : " </Option>"
469 : " <Option name='RES_FILTER_MIN' type='float' description="
470 : "'Minimum resolution of supergrids to take into account (excluded "
471 : "bound). "
472 : "Only used for MODE=RESAMPLED_GRID, INTERPOLATED or LIST_SUPERGRIDS' "
473 : "default='0'/>"
474 : " <Option name='RES_FILTER_MAX' type='float' description="
475 : "'Maximum resolution of supergrids to take into account (included "
476 : "bound). "
477 : "Only used for MODE=RESAMPLED_GRID, INTERPOLATED or LIST_SUPERGRIDS' "
478 : "default='inf'/>"
479 : " <Option name='VALUE_POPULATION' type='string-select' description="
480 : "'Which value population strategy to apply to compute the resampled "
481 : "cell "
482 : "values. Only used for MODE=RESAMPLED_GRID' default='MAX'>"
483 : " <Value>MIN</Value>"
484 : " <Value>MAX</Value>"
485 : " <Value>MEAN</Value>"
486 : " <Value>COUNT</Value>"
487 : " </Option>"
488 : " <Option name='SUPERGRIDS_MASK' type='boolean' description="
489 : "'Whether the dataset should consist of a mask band indicating if a "
490 : "supergrid node matches each target pixel. Only used for "
491 : "MODE=RESAMPLED_GRID' default='NO'/>"
492 : " <Option name='NODATA_VALUE' type='float' default='1000000'/>"
493 : " <Option name='REPORT_VERTCRS' type='boolean' default='YES'/>"
494 1689 : "</OpenOptionList>");
495 :
496 1689 : poDriver->SetMetadataItem(
497 : GDAL_DMD_CREATIONOPTIONLIST,
498 : "<CreationOptionList>"
499 : " <Option name='VAR_*' type='string' description="
500 : "'Value to substitute to a variable in the template'/>"
501 : " <Option name='TEMPLATE' type='string' description="
502 : "'.xml template to use'/>"
503 : " <Option name='BAG_VERSION' type='string' description="
504 : "'Version to write in the Bag Version attribute' default='1.6.2'/>"
505 : " <Option name='COMPRESS' type='string-select' default='DEFLATE'>"
506 : " <Value>NONE</Value>"
507 : " <Value>DEFLATE</Value>"
508 : " </Option>"
509 : " <Option name='ZLEVEL' type='int' "
510 : "description='DEFLATE compression level 1-9' default='6' />"
511 : " <Option name='BLOCK_SIZE' type='int' description='Chunk size' />"
512 1689 : "</CreationOptionList>");
513 :
514 1689 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
515 :
516 1689 : poDriver->pfnIdentify = BAGDatasetIdentify;
517 1689 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
518 1689 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
519 1689 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
520 1689 : }
521 :
522 : /************************************************************************/
523 : /* S102DriverSetCommonMetadata() */
524 : /************************************************************************/
525 :
526 1689 : void S102DriverSetCommonMetadata(GDALDriver *poDriver)
527 : {
528 1689 : poDriver->SetDescription(S102_DRIVER_NAME);
529 1689 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
530 1689 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
531 1689 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
532 1689 : "S-102 Bathymetric Surface Product");
533 1689 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/s102.html");
534 1689 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
535 1689 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "h5");
536 1689 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
537 :
538 1689 : poDriver->SetMetadataItem(
539 : GDAL_DMD_OPENOPTIONLIST,
540 : "<OpenOptionList>"
541 : " <Option name='DEPTH_OR_ELEVATION' type='string-select' "
542 : "default='DEPTH'>"
543 : " <Value>DEPTH</Value>"
544 : " <Value>ELEVATION</Value>"
545 : " </Option>"
546 : " <Option name='NORTH_UP' type='boolean' default='YES' "
547 : "description='Whether the top line of the dataset should be the "
548 : "northern-most one'/>"
549 1689 : "</OpenOptionList>");
550 1689 : poDriver->pfnIdentify = S102DatasetIdentify;
551 1689 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
552 1689 : }
553 :
554 : /************************************************************************/
555 : /* S104DriverSetCommonMetadata() */
556 : /************************************************************************/
557 :
558 1689 : void S104DriverSetCommonMetadata(GDALDriver *poDriver)
559 : {
560 1689 : poDriver->SetDescription(S104_DRIVER_NAME);
561 1689 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
562 1689 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
563 1689 : poDriver->SetMetadataItem(
564 : GDAL_DMD_LONGNAME,
565 1689 : "S-104 Water Level Information for Surface Navigation Product");
566 1689 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/s104.html");
567 1689 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
568 1689 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "h5");
569 :
570 1689 : poDriver->SetMetadataItem(
571 : GDAL_DMD_OPENOPTIONLIST,
572 : "<OpenOptionList>"
573 : " <Option name='NORTH_UP' type='boolean' default='YES' "
574 : "description='Whether the top line of the dataset should be the "
575 : "northern-most one'/>"
576 1689 : "</OpenOptionList>");
577 1689 : poDriver->pfnIdentify = S104DatasetIdentify;
578 1689 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
579 1689 : }
580 :
581 : /************************************************************************/
582 : /* S111DriverSetCommonMetadata() */
583 : /************************************************************************/
584 :
585 1689 : void S111DriverSetCommonMetadata(GDALDriver *poDriver)
586 : {
587 1689 : poDriver->SetDescription(S111_DRIVER_NAME);
588 1689 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
589 1689 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
590 1689 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Surface Currents Product");
591 1689 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/s111.html");
592 1689 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
593 1689 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "h5");
594 :
595 1689 : poDriver->SetMetadataItem(
596 : GDAL_DMD_OPENOPTIONLIST,
597 : "<OpenOptionList>"
598 : " <Option name='NORTH_UP' type='boolean' default='YES' "
599 : "description='Whether the top line of the dataset should be the "
600 : "northern-most one'/>"
601 1689 : "</OpenOptionList>");
602 1689 : poDriver->pfnIdentify = S111DatasetIdentify;
603 1689 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
604 1689 : }
605 :
606 : /************************************************************************/
607 : /* DeclareDeferredHDF5Plugin() */
608 : /************************************************************************/
609 :
610 : #ifdef PLUGIN_FILENAME
611 1961 : void DeclareDeferredHDF5Plugin()
612 : {
613 1961 : if (GDALGetDriverByName(HDF5_DRIVER_NAME) != nullptr)
614 : {
615 283 : return;
616 : }
617 : {
618 1678 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
619 : #ifdef PLUGIN_INSTALLATION_MESSAGE
620 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
621 : PLUGIN_INSTALLATION_MESSAGE);
622 : #endif
623 1678 : HDF5DriverSetCommonMetadata(poDriver);
624 1678 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
625 : }
626 : {
627 1678 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
628 : #ifdef PLUGIN_INSTALLATION_MESSAGE
629 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
630 : PLUGIN_INSTALLATION_MESSAGE);
631 : #endif
632 1678 : HDF5ImageDriverSetCommonMetadata(poDriver);
633 1678 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
634 : }
635 : {
636 1678 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
637 : #ifdef PLUGIN_INSTALLATION_MESSAGE
638 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
639 : PLUGIN_INSTALLATION_MESSAGE);
640 : #endif
641 1678 : BAGDriverSetCommonMetadata(poDriver);
642 1678 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
643 : }
644 : {
645 1678 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
646 : #ifdef PLUGIN_INSTALLATION_MESSAGE
647 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
648 : PLUGIN_INSTALLATION_MESSAGE);
649 : #endif
650 1678 : S102DriverSetCommonMetadata(poDriver);
651 1678 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
652 : }
653 : {
654 1678 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
655 : #ifdef PLUGIN_INSTALLATION_MESSAGE
656 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
657 : PLUGIN_INSTALLATION_MESSAGE);
658 : #endif
659 1678 : S104DriverSetCommonMetadata(poDriver);
660 1678 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
661 : }
662 : {
663 1678 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
664 : #ifdef PLUGIN_INSTALLATION_MESSAGE
665 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
666 : PLUGIN_INSTALLATION_MESSAGE);
667 : #endif
668 1678 : S111DriverSetCommonMetadata(poDriver);
669 1678 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
670 : }
671 : }
672 : #endif
|