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