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

Generated by: LCOV version 1.14