LCOV - code coverage report
Current view: top level - frmts/hdf5 - hdf5drivercore.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 264 271 97.4 %
Date: 2026-05-07 11:45:54 Functions: 31 31 100.0 %

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

Generated by: LCOV version 1.14