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 58814 : int HDF5DatasetIdentify(GDALOpenInfo *poOpenInfo)
27 :
28 : {
29 58814 : if ((poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) &&
30 688 : STARTS_WITH(poOpenInfo->pszFilename, "HDF5:"))
31 : {
32 16 : return TRUE;
33 : }
34 :
35 : // Is it an HDF5 file?
36 58798 : constexpr char achSignature[] = "\211HDF\r\n\032\n";
37 :
38 58798 : if (!poOpenInfo->pabyHeader)
39 55080 : return FALSE;
40 :
41 7436 : const CPLString osExt(poOpenInfo->osExtension);
42 :
43 574 : const auto IsRecognizedByNetCDFDriver = [&osExt, poOpenInfo]()
44 : {
45 287 : if ((EQUAL(osExt, "NC") || EQUAL(osExt, "CDF") || EQUAL(osExt, "NC4") ||
46 292 : 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 141 : return false;
58 3718 : };
59 :
60 3718 : if (memcmp(poOpenInfo->pabyHeader, achSignature, 8) == 0 ||
61 3569 : (poOpenInfo->nHeaderBytes > 512 + 8 &&
62 2269 : memcmp(poOpenInfo->pabyHeader + 512, achSignature, 8) == 0))
63 : {
64 149 : 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 145 : 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 145 : 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 144 : if (IsRecognizedByNetCDFDriver())
89 : {
90 3 : return FALSE;
91 : }
92 :
93 141 : return TRUE;
94 : }
95 :
96 3569 : 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 7084 : if (poOpenInfo->fpL != nullptr &&
103 3515 : (EQUAL(osExt, "h5") || EQUAL(osExt, "hdf5") || EQUAL(osExt, "nc") ||
104 3503 : EQUAL(osExt, "cdf") || EQUAL(osExt, "nc4") ||
105 3503 : poOpenInfo->IsSingleAllowedDriver("HDF5")))
106 : {
107 14 : vsi_l_offset nOffset = 512;
108 38 : for (int i = 0; i < 64; i++)
109 : {
110 : GByte abyBuf[8];
111 76 : if (VSIFSeekL(poOpenInfo->fpL, nOffset, SEEK_SET) != 0 ||
112 38 : VSIFReadL(abyBuf, 1, 8, poOpenInfo->fpL) != 8)
113 : {
114 8 : 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 3563 : return FALSE;
136 : }
137 :
138 : /************************************************************************/
139 : /* HDF5ImageDatasetIdentify() */
140 : /************************************************************************/
141 :
142 58019 : int HDF5ImageDatasetIdentify(GDALOpenInfo *poOpenInfo)
143 :
144 : {
145 58019 : if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF5:"))
146 57959 : return FALSE;
147 :
148 60 : return TRUE;
149 : }
150 :
151 : /************************************************************************/
152 : /* HDF5DriverGetSubdatasetInfo() */
153 : /************************************************************************/
154 :
155 : struct HDF5DriverSubdatasetInfo final : public GDALSubdatasetInfo
156 : {
157 : public:
158 26 : explicit HDF5DriverSubdatasetInfo(const std::string &fileName)
159 26 : : GDALSubdatasetInfo(fileName)
160 : {
161 26 : }
162 :
163 : // GDALSubdatasetInfo interface
164 : private:
165 : void parseFileName() override;
166 : };
167 :
168 26 : void HDF5DriverSubdatasetInfo::parseFileName()
169 : {
170 :
171 26 : if (!STARTS_WITH_CI(m_fileName.c_str(), "HDF5:"))
172 : {
173 0 : return;
174 : }
175 :
176 52 : CPLStringList aosParts{CSLTokenizeString2(m_fileName.c_str(), ":", 0)};
177 26 : const int iPartsCount{CSLCount(aosParts)};
178 :
179 26 : if (iPartsCount >= 3)
180 : {
181 :
182 24 : m_driverPrefixComponent = aosParts[0];
183 :
184 48 : std::string part1{aosParts[1]};
185 24 : if (!part1.empty() && part1[0] == '"')
186 : {
187 20 : part1 = part1.substr(1);
188 : }
189 :
190 24 : int subdatasetIndex{2};
191 : const bool hasDriveLetter{
192 24 : part1.length() == 1 &&
193 30 : 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 47 : const bool hasProtocol{part1 == "/vsicurl/http" ||
199 46 : part1 == "/vsicurl/https" ||
200 70 : part1 == "/vsicurl_streaming/http" ||
201 23 : part1 == "/vsicurl_streaming/https"};
202 :
203 24 : m_pathComponent = aosParts[1];
204 :
205 24 : if (hasDriveLetter || hasProtocol)
206 : {
207 5 : m_pathComponent.append(":");
208 5 : m_pathComponent.append(aosParts[2]);
209 5 : subdatasetIndex++;
210 : }
211 :
212 24 : if (iPartsCount > subdatasetIndex)
213 : {
214 24 : m_subdatasetComponent = aosParts[subdatasetIndex];
215 :
216 : // Append any remaining part
217 24 : 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 2711 : static GDALSubdatasetInfo *HDF5DriverGetSubdatasetInfo(const char *pszFileName)
227 : {
228 2711 : if (STARTS_WITH_CI(pszFileName, "HDF5:"))
229 : {
230 : std::unique_ptr<GDALSubdatasetInfo> info =
231 26 : std::make_unique<HDF5DriverSubdatasetInfo>(pszFileName);
232 76 : if (!info->GetSubdatasetComponent().empty() &&
233 50 : !info->GetPathComponent().empty())
234 : {
235 24 : return info.release();
236 : }
237 : }
238 2687 : return nullptr;
239 : }
240 :
241 : /************************************************************************/
242 : /* IdentifySxx() */
243 : /************************************************************************/
244 :
245 176259 : static bool IdentifySxx(GDALOpenInfo *poOpenInfo, const char *pszDriverName,
246 : const char *pszConfigOption,
247 : const char *pszMainGroupName)
248 : {
249 176259 : if (STARTS_WITH(poOpenInfo->pszFilename, pszDriverName) &&
250 34 : poOpenInfo->pszFilename[strlen(pszDriverName)] == ':')
251 34 : return TRUE;
252 :
253 : // Is it an HDF5 file?
254 : static const char achSignature[] = "\211HDF\r\n\032\n";
255 :
256 176225 : if (poOpenInfo->pabyHeader == nullptr ||
257 10958 : memcmp(poOpenInfo->pabyHeader, achSignature, 8) != 0)
258 175955 : return FALSE;
259 :
260 270 : if (poOpenInfo->IsSingleAllowedDriver(pszDriverName))
261 : {
262 1 : 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 269 : 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 268 : const int nLenMainGroup = static_cast<int>(strlen(pszMainGroupName));
274 268 : const int nLenGroupF = static_cast<int>(strlen("Group_F"));
275 268 : const int nLenProductSpecification =
276 : static_cast<int>(strlen("productSpecification"));
277 268 : bool bFoundMainGroup = false;
278 268 : bool bFoundGroupF = false;
279 268 : bool bFoundProductSpecification = false;
280 268 : for (int iTry = 0; iTry < 2; ++iTry)
281 : {
282 262472 : for (int i = 0; i <= poOpenInfo->nHeaderBytes - nLenGroupF; ++i)
283 : {
284 262242 : if (i <= poOpenInfo->nHeaderBytes - nLenMainGroup &&
285 260628 : poOpenInfo->pabyHeader[i] == pszMainGroupName[0] &&
286 164 : memcmp(poOpenInfo->pabyHeader + i, pszMainGroupName,
287 : nLenMainGroup) == 0)
288 : {
289 38 : bFoundMainGroup = true;
290 38 : if (bFoundGroupF)
291 0 : return true;
292 : }
293 262242 : if (poOpenInfo->pabyHeader[i] == 'G' &&
294 225 : memcmp(poOpenInfo->pabyHeader + i, "Group_F", nLenGroupF) ==
295 : 0)
296 : {
297 46 : bFoundGroupF = true;
298 46 : if (bFoundMainGroup)
299 38 : return true;
300 : }
301 262204 : if (i <= poOpenInfo->nHeaderBytes - nLenProductSpecification &&
302 259214 : poOpenInfo->pabyHeader[i] == 'p' &&
303 221 : memcmp(poOpenInfo->pabyHeader + i, "productSpecification",
304 : nLenProductSpecification) == 0)
305 : {
306 : // For 102DE00OS08J.H5
307 0 : bFoundProductSpecification = true;
308 : }
309 : }
310 230 : if (!(iTry == 0 && bFoundProductSpecification &&
311 0 : poOpenInfo->nHeaderBytes == 1024 &&
312 0 : poOpenInfo->TryToIngest(4096)))
313 : {
314 230 : break;
315 : }
316 : }
317 : }
318 :
319 231 : return false;
320 : }
321 :
322 : /************************************************************************/
323 : /* S102DatasetIdentify() */
324 : /************************************************************************/
325 :
326 58789 : int S102DatasetIdentify(GDALOpenInfo *poOpenInfo)
327 :
328 : {
329 58789 : return IdentifySxx(poOpenInfo, "S102", "GDAL_S102_IDENTIFY",
330 58788 : "BathymetryCoverage");
331 : }
332 :
333 : /************************************************************************/
334 : /* S104DatasetIdentify() */
335 : /************************************************************************/
336 :
337 58740 : int S104DatasetIdentify(GDALOpenInfo *poOpenInfo)
338 :
339 : {
340 58740 : return IdentifySxx(poOpenInfo, "S104", "GDAL_S104_IDENTIFY", "WaterLevel");
341 : }
342 :
343 : /************************************************************************/
344 : /* S111DatasetIdentify() */
345 : /************************************************************************/
346 :
347 58735 : int S111DatasetIdentify(GDALOpenInfo *poOpenInfo)
348 :
349 : {
350 58735 : return IdentifySxx(poOpenInfo, "S111", "GDAL_S111_IDENTIFY",
351 58735 : "SurfaceCurrent");
352 : }
353 :
354 : /************************************************************************/
355 : /* BAGDatasetIdentify() */
356 : /************************************************************************/
357 :
358 69472 : int BAGDatasetIdentify(GDALOpenInfo *poOpenInfo)
359 :
360 : {
361 69472 : 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 69442 : if (poOpenInfo->pabyHeader == nullptr ||
368 11845 : memcmp(poOpenInfo->pabyHeader, achSignature, 8) != 0)
369 69200 : return FALSE;
370 :
371 : // Does it have the extension .bag?
372 242 : if (!poOpenInfo->IsExtensionEqualToCI("bag"))
373 : {
374 106 : if (poOpenInfo->IsSingleAllowedDriver("BAG"))
375 : {
376 1 : return TRUE;
377 : }
378 105 : return FALSE;
379 : }
380 :
381 136 : return TRUE;
382 : }
383 :
384 : /************************************************************************/
385 : /* HDF5DriverSetCommonMetadata() */
386 : /************************************************************************/
387 :
388 2105 : void HDF5DriverSetCommonMetadata(GDALDriver *poDriver)
389 : {
390 2105 : poDriver->SetDescription(HDF5_DRIVER_NAME);
391 2105 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
392 2105 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
393 2105 : "Hierarchical Data Format Release 5");
394 2105 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/hdf5.html");
395 2105 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "h5 hdf5");
396 2105 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
397 2105 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
398 :
399 2105 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
400 :
401 2105 : poDriver->pfnIdentify = HDF5DatasetIdentify;
402 2105 : poDriver->pfnGetSubdatasetInfoFunc = HDF5DriverGetSubdatasetInfo;
403 2105 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
404 2105 : }
405 :
406 : /************************************************************************/
407 : /* HDF5ImageDriverSetCommonMetadata() */
408 : /************************************************************************/
409 :
410 2105 : void HDF5ImageDriverSetCommonMetadata(GDALDriver *poDriver)
411 : {
412 2105 : poDriver->SetDescription(HDF5_IMAGE_DRIVER_NAME);
413 2105 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
414 2105 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "HDF5 Dataset");
415 2105 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/hdf5.html");
416 2105 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
417 :
418 2105 : poDriver->pfnIdentify = HDF5ImageDatasetIdentify;
419 2105 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
420 2105 : }
421 :
422 : /************************************************************************/
423 : /* BAGDriverSetCommonMetadata() */
424 : /************************************************************************/
425 :
426 2105 : void BAGDriverSetCommonMetadata(GDALDriver *poDriver)
427 : {
428 2105 : poDriver->SetDescription(BAG_DRIVER_NAME);
429 2105 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
430 2105 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
431 2105 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Bathymetry Attributed Grid");
432 2105 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/bag.html");
433 2105 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
434 2105 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "bag");
435 :
436 2105 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Float32");
437 :
438 2105 : 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 2105 : "</OpenOptionList>");
499 :
500 2105 : 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 2105 : "</CreationOptionList>");
517 :
518 2105 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
519 :
520 2105 : poDriver->pfnIdentify = BAGDatasetIdentify;
521 2105 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
522 2105 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
523 2105 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
524 2105 : }
525 :
526 : /************************************************************************/
527 : /* S102DriverSetCommonMetadata() */
528 : /************************************************************************/
529 :
530 2105 : void S102DriverSetCommonMetadata(GDALDriver *poDriver)
531 : {
532 2105 : poDriver->SetDescription(S102_DRIVER_NAME);
533 2105 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
534 2105 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
535 2105 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
536 2105 : "S-102 Bathymetric Surface Product");
537 2105 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/s102.html");
538 2105 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
539 2105 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "h5");
540 2105 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
541 :
542 2105 : poDriver->SetMetadataItem(
543 : GDAL_DMD_OPENOPTIONLIST,
544 : "<OpenOptionList>"
545 : " <Option name='DEPTH_OR_ELEVATION' type='string-select' "
546 : "default='DEPTH'>"
547 : " <Value>DEPTH</Value>"
548 : " <Value>ELEVATION</Value>"
549 : " </Option>"
550 : " <Option name='NORTH_UP' type='boolean' default='YES' "
551 : "description='Whether the top line of the dataset should be the "
552 : "northern-most one'/>"
553 2105 : "</OpenOptionList>");
554 2105 : poDriver->pfnIdentify = S102DatasetIdentify;
555 2105 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
556 2105 : }
557 :
558 : /************************************************************************/
559 : /* S104DriverSetCommonMetadata() */
560 : /************************************************************************/
561 :
562 2105 : void S104DriverSetCommonMetadata(GDALDriver *poDriver)
563 : {
564 2105 : poDriver->SetDescription(S104_DRIVER_NAME);
565 2105 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
566 2105 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
567 2105 : poDriver->SetMetadataItem(
568 : GDAL_DMD_LONGNAME,
569 2105 : "S-104 Water Level Information for Surface Navigation Product");
570 2105 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/s104.html");
571 2105 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
572 2105 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "h5");
573 :
574 2105 : poDriver->SetMetadataItem(
575 : GDAL_DMD_OPENOPTIONLIST,
576 : "<OpenOptionList>"
577 : " <Option name='NORTH_UP' type='boolean' default='YES' "
578 : "description='Whether the top line of the dataset should be the "
579 : "northern-most one'/>"
580 2105 : "</OpenOptionList>");
581 2105 : poDriver->pfnIdentify = S104DatasetIdentify;
582 2105 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
583 2105 : }
584 :
585 : /************************************************************************/
586 : /* S111DriverSetCommonMetadata() */
587 : /************************************************************************/
588 :
589 2105 : void S111DriverSetCommonMetadata(GDALDriver *poDriver)
590 : {
591 2105 : poDriver->SetDescription(S111_DRIVER_NAME);
592 2105 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
593 2105 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
594 2105 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Surface Currents Product");
595 2105 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/s111.html");
596 2105 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
597 2105 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "h5");
598 :
599 2105 : poDriver->SetMetadataItem(
600 : GDAL_DMD_OPENOPTIONLIST,
601 : "<OpenOptionList>"
602 : " <Option name='NORTH_UP' type='boolean' default='YES' "
603 : "description='Whether the top line of the dataset should be the "
604 : "northern-most one'/>"
605 2105 : "</OpenOptionList>");
606 2105 : poDriver->pfnIdentify = S111DatasetIdentify;
607 2105 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
608 2105 : }
609 :
610 : /************************************************************************/
611 : /* DeclareDeferredHDF5Plugin() */
612 : /************************************************************************/
613 :
614 : #ifdef PLUGIN_FILENAME
615 2033 : void DeclareDeferredHDF5Plugin()
616 : {
617 2033 : if (GDALGetDriverByName(HDF5_DRIVER_NAME) != nullptr)
618 : {
619 283 : return;
620 : }
621 : {
622 1750 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
623 : #ifdef PLUGIN_INSTALLATION_MESSAGE
624 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
625 : PLUGIN_INSTALLATION_MESSAGE);
626 : #endif
627 1750 : HDF5DriverSetCommonMetadata(poDriver);
628 1750 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
629 : }
630 : {
631 1750 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
632 : #ifdef PLUGIN_INSTALLATION_MESSAGE
633 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
634 : PLUGIN_INSTALLATION_MESSAGE);
635 : #endif
636 1750 : HDF5ImageDriverSetCommonMetadata(poDriver);
637 1750 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
638 : }
639 : {
640 1750 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
641 : #ifdef PLUGIN_INSTALLATION_MESSAGE
642 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
643 : PLUGIN_INSTALLATION_MESSAGE);
644 : #endif
645 1750 : BAGDriverSetCommonMetadata(poDriver);
646 1750 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
647 : }
648 : {
649 1750 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
650 : #ifdef PLUGIN_INSTALLATION_MESSAGE
651 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
652 : PLUGIN_INSTALLATION_MESSAGE);
653 : #endif
654 1750 : S102DriverSetCommonMetadata(poDriver);
655 1750 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
656 : }
657 : {
658 1750 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
659 : #ifdef PLUGIN_INSTALLATION_MESSAGE
660 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
661 : PLUGIN_INSTALLATION_MESSAGE);
662 : #endif
663 1750 : S104DriverSetCommonMetadata(poDriver);
664 1750 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
665 : }
666 : {
667 1750 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
668 : #ifdef PLUGIN_INSTALLATION_MESSAGE
669 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
670 : PLUGIN_INSTALLATION_MESSAGE);
671 : #endif
672 1750 : S111DriverSetCommonMetadata(poDriver);
673 1750 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
674 : }
675 : }
676 : #endif
|