LCOV - code coverage report
Current view: top level - frmts/hdf5 - hdf5dataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 671 839 80.0 %
Date: 2026-05-29 23:25:07 Functions: 23 24 95.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Hierarchical Data Format Release 5 (HDF5)
       4             :  * Purpose:  HDF5 Datasets. Open HDF5 file, fetch metadata and list of
       5             :  *           subdatasets.
       6             :  *           This driver initially based on code supplied by Markus Neteler
       7             :  * Author:  Denis Nadeau <denis.nadeau@gmail.com>
       8             :  *
       9             :  ******************************************************************************
      10             :  * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
      11             :  * Copyright (c) 2008-2018, Even Rouault <even.rouault at spatialys.com>
      12             :  *
      13             :  * SPDX-License-Identifier: MIT
      14             :  ****************************************************************************/
      15             : 
      16             : #ifdef _POSIX_C_SOURCE
      17             : #undef _POSIX_C_SOURCE
      18             : #endif
      19             : 
      20             : #include "cpl_port.h"
      21             : 
      22             : #include "hdf5_api.h"
      23             : #include "hdf5dataset.h"
      24             : #include "hdf5drivercore.h"
      25             : #include "hdf5vfl.h"
      26             : 
      27             : #include <algorithm>
      28             : #include <stdio.h>
      29             : #include <string.h>
      30             : #include <string>
      31             : #include <cctype>
      32             : #include <limits>
      33             : 
      34             : #include "cpl_conv.h"
      35             : #include "cpl_error.h"
      36             : #include "cpl_float.h"
      37             : #include "cpl_string.h"
      38             : #include "gdal.h"
      39             : #include "gdal_frmts.h"
      40             : #include "gdal_priv.h"
      41             : 
      42             : constexpr size_t MAX_METADATA_LEN = 32768;
      43             : 
      44             : #ifdef ENABLE_HDF5_GLOBAL_LOCK
      45             : 
      46             : /************************************************************************/
      47             : /*                         GetHDF5GlobalMutex()                         */
      48             : /************************************************************************/
      49             : 
      50             : std::recursive_mutex &GetHDF5GlobalMutex()
      51             : {
      52             :     static std::recursive_mutex oMutex;
      53             :     return oMutex;
      54             : }
      55             : 
      56             : #endif
      57             : 
      58             : /************************************************************************/
      59             : /*                         HDF5GetFileDriver()                          */
      60             : /************************************************************************/
      61             : 
      62         601 : hid_t HDF5GetFileDriver()
      63             : {
      64         601 :     return HDF5VFLGetFileDriver();
      65             : }
      66             : 
      67             : /************************************************************************/
      68             : /*                        HDF5UnloadFileDriver()                        */
      69             : /************************************************************************/
      70             : 
      71          54 : void HDF5UnloadFileDriver()
      72             : {
      73          54 :     HDF5VFLUnloadFileDriver();
      74          54 : }
      75             : 
      76             : /************************************************************************/
      77             : /*                      HDF5DatasetDriverUnload()                       */
      78             : /************************************************************************/
      79             : 
      80           9 : static void HDF5DatasetDriverUnload(GDALDriver *)
      81             : {
      82           9 :     HDF5UnloadFileDriver();
      83           9 : }
      84             : 
      85             : /************************************************************************/
      86             : /* ==================================================================== */
      87             : /*                              HDF5Dataset                             */
      88             : /* ==================================================================== */
      89             : /************************************************************************/
      90             : 
      91             : /************************************************************************/
      92             : /*                         GDALRegister_HDF5()                          */
      93             : /************************************************************************/
      94          14 : void GDALRegister_HDF5()
      95             : 
      96             : {
      97          14 :     if (GDALGetDriverByName(HDF5_DRIVER_NAME) != nullptr)
      98           0 :         return;
      99             : 
     100          14 :     GDALDriver *poDriver = new GDALDriver();
     101             : 
     102          14 :     HDF5DriverSetCommonMetadata(poDriver);
     103             : 
     104          14 :     poDriver->pfnOpen = HDF5Dataset::Open;
     105          14 :     poDriver->pfnUnloadDriver = HDF5DatasetDriverUnload;
     106             : 
     107             : #if (defined(H5_VERS_MAJOR) &&                                                 \
     108             :      (H5_VERS_MAJOR >= 2 || (H5_VERS_MAJOR == 1 && H5_VERS_MINOR > 10) ||      \
     109             :       (H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 10 && H5_VERS_RELEASE >= 5)))
     110             :     poDriver->SetMetadataItem("HAVE_H5Dget_chunk_info", "YES");
     111             : #endif
     112             : 
     113          14 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     114             : 
     115             : #ifdef HDF5_PLUGIN
     116          14 :     GDALRegister_HDF5Image();
     117          14 :     GDALRegister_BAG();
     118          14 :     GDALRegister_S102();
     119          14 :     GDALRegister_S104();
     120          14 :     GDALRegister_S111();
     121             : #endif
     122             : }
     123             : 
     124             : /************************************************************************/
     125             : /*                            HDF5Dataset()                             */
     126             : /************************************************************************/
     127         172 : HDF5Dataset::HDF5Dataset()
     128             :     : hGroupID(-1), papszSubDatasets(nullptr), nDatasetType(-1),
     129         172 :       nSubDataCount(0), poH5RootGroup(nullptr)
     130             : {
     131         172 : }
     132             : 
     133             : /************************************************************************/
     134             : /*                            ~HDF5Dataset()                            */
     135             : /************************************************************************/
     136         281 : HDF5Dataset::~HDF5Dataset()
     137             : {
     138             :     HDF5_GLOBAL_LOCK();
     139             : 
     140         172 :     if (hGroupID > 0)
     141         139 :         H5Gclose(hGroupID);
     142         172 :     if (m_hHDF5 > 0)
     143         139 :         H5Fclose(m_hHDF5);
     144             : 
     145         172 :     CSLDestroy(papszSubDatasets);
     146         172 :     if (poH5RootGroup != nullptr)
     147             :     {
     148         139 :         DestroyH5Objects(poH5RootGroup);
     149         139 :         CPLFree(poH5RootGroup->pszName);
     150         139 :         CPLFree(poH5RootGroup->pszPath);
     151         139 :         CPLFree(poH5RootGroup->pszUnderscorePath);
     152         139 :         CPLFree(poH5RootGroup->poHchild);
     153         139 :         CPLFree(poH5RootGroup);
     154             :     }
     155         281 : }
     156             : 
     157             : /************************************************************************/
     158             : /*                            GetDataType()                             */
     159             : /*                                                                      */
     160             : /*      Transform HDF5 datatype to GDAL datatype                        */
     161             : /************************************************************************/
     162      191155 : GDALDataType HDF5Dataset::GetDataType(hid_t TypeID)
     163             : {
     164             :     // Check for native types first
     165      191155 :     if (H5Tget_class(TypeID) != H5T_COMPOUND)
     166             :     {
     167             : 
     168      189550 :         if (H5Tequal(H5T_NATIVE_SCHAR, TypeID))
     169          78 :             return GDT_Int8;
     170      378944 :         else if (H5Tequal(H5T_NATIVE_CHAR, TypeID) ||
     171      189472 :                  H5Tequal(H5T_NATIVE_UCHAR, TypeID))
     172       20659 :             return GDT_UInt8;
     173      168813 :         else if (H5Tequal(H5T_NATIVE_SHORT, TypeID))
     174         793 :             return GDT_Int16;
     175      168020 :         else if (H5Tequal(H5T_NATIVE_USHORT, TypeID))
     176        2085 :             return GDT_UInt16;
     177      165935 :         else if (H5Tequal(H5T_NATIVE_INT, TypeID))
     178       12994 :             return GDT_Int32;
     179      152941 :         else if (H5Tequal(H5T_NATIVE_UINT, TypeID))
     180       26250 :             return GDT_UInt32;
     181      126691 :         else if (H5Tequal(H5T_NATIVE_INT64, TypeID))
     182        1529 :             return GDT_Int64;
     183      125162 :         else if (H5Tequal(H5T_NATIVE_UINT64, TypeID))
     184          39 :             return GDT_UInt64;
     185      125123 :         else if (H5Tequal(H5T_NATIVE_LONG, TypeID))
     186             :         {
     187             : #if SIZEOF_UNSIGNED_LONG == 4
     188             :             return GDT_Int32;
     189             : #else
     190           0 :             return GDT_Unknown;
     191             : #endif
     192             :         }
     193      125123 :         else if (H5Tequal(H5T_NATIVE_ULONG, TypeID))
     194             :         {
     195             : #if SIZEOF_UNSIGNED_LONG == 4
     196             :             return GDT_UInt32;
     197             : #else
     198           0 :             return GDT_Unknown;
     199             : #endif
     200             :         }
     201             : #ifdef HDF5_HAVE_FLOAT16
     202             :         else if (H5Tequal(H5T_NATIVE_FLOAT16, TypeID))
     203             :             return GDT_Float32;
     204             : #endif
     205      125123 :         else if (H5Tequal(H5T_NATIVE_FLOAT, TypeID))
     206       38035 :             return GDT_Float32;
     207       87088 :         else if (H5Tequal(H5T_NATIVE_DOUBLE, TypeID))
     208       38730 :             return GDT_Float64;
     209       48358 :         else if (H5Tequal(H5T_NATIVE_LLONG, TypeID))
     210           0 :             return GDT_Unknown;
     211       48358 :         else if (H5Tequal(H5T_NATIVE_ULLONG, TypeID))
     212           0 :             return GDT_Unknown;
     213             :     }
     214             :     else  // Parse compound type to determine if data is complex
     215             :     {
     216             :         // For complex the compound type must contain 2 elements
     217        1605 :         if (H5Tget_nmembers(TypeID) != 2)
     218         595 :             return GDT_Unknown;
     219             : 
     220             :         // For complex the native types of both elements should be the same
     221        1010 :         hid_t ElemTypeID = H5Tget_member_type(TypeID, 0);
     222        1010 :         hid_t Elem2TypeID = H5Tget_member_type(TypeID, 1);
     223        1010 :         const bool bTypeEqual = H5Tequal(ElemTypeID, Elem2TypeID) > 0;
     224        1010 :         H5Tclose(Elem2TypeID);
     225        1010 :         if (!bTypeEqual)
     226             :         {
     227         599 :             H5Tclose(ElemTypeID);
     228         599 :             return GDT_Unknown;
     229             :         }
     230             : 
     231         411 :         char *pszName1 = H5Tget_member_name(TypeID, 0);
     232         411 :         const bool bIsReal =
     233         411 :             pszName1 && (pszName1[0] == 'r' || pszName1[0] == 'R');
     234         411 :         H5free_memory(pszName1);
     235             : 
     236         411 :         char *pszName2 = H5Tget_member_name(TypeID, 1);
     237         411 :         const bool bIsImaginary =
     238         411 :             pszName2 && (pszName2[0] == 'i' || pszName2[0] == 'I');
     239         411 :         H5free_memory(pszName2);
     240             : 
     241         411 :         if (!bIsReal || !bIsImaginary)
     242             :         {
     243         172 :             H5Tclose(ElemTypeID);
     244         172 :             return GDT_Unknown;
     245             :         }
     246             : 
     247             :         // Check the native types to determine CInt16, CFloat32 or CFloat64
     248         239 :         GDALDataType eDataType = GDT_Unknown;
     249             : 
     250         239 :         if (H5Tequal(H5T_NATIVE_SHORT, ElemTypeID))
     251          58 :             eDataType = GDT_CInt16;
     252         181 :         else if (H5Tequal(H5T_NATIVE_INT, ElemTypeID))
     253          55 :             eDataType = GDT_CInt32;
     254         126 :         else if (H5Tequal(H5T_NATIVE_LONG, ElemTypeID))
     255             :         {
     256             : #if SIZEOF_UNSIGNED_LONG == 4
     257             :             eDataType = GDT_CInt32;
     258             : #else
     259           0 :             eDataType = GDT_Unknown;
     260             : #endif
     261             :         }
     262             : #ifdef HDF5_HAVE_FLOAT16
     263             :         else if (H5Tequal(H5T_NATIVE_FLOAT16, ElemTypeID))
     264             :             eDataType = GDT_CFloat32;
     265             : #endif
     266         126 :         else if (H5Tequal(H5T_NATIVE_FLOAT, ElemTypeID))
     267          66 :             eDataType = GDT_CFloat32;
     268          60 :         else if (H5Tequal(H5T_NATIVE_DOUBLE, ElemTypeID))
     269          60 :             eDataType = GDT_CFloat64;
     270             : 
     271             :         // Close the data type
     272         239 :         H5Tclose(ElemTypeID);
     273             : 
     274         239 :         return eDataType;
     275             :     }
     276             : 
     277       48358 :     return GDT_Unknown;
     278             : }
     279             : 
     280             : /************************************************************************/
     281             : /*                          IsNativeCFloat16()                          */
     282             : /************************************************************************/
     283             : 
     284           0 : /* static*/ bool HDF5Dataset::IsNativeCFloat16(hid_t hDataType)
     285             : {
     286             : #ifdef HDF5_HAVE_FLOAT16
     287             :     // For complex the compound type must contain 2 elements
     288             :     if (H5Tget_class(hDataType) != H5T_COMPOUND ||
     289             :         H5Tget_nmembers(hDataType) != 2)
     290             :         return false;
     291             : 
     292             :     // For complex the native types of both elements should be the same
     293             :     hid_t ElemTypeID = H5Tget_member_type(hDataType, 0);
     294             :     hid_t Elem2TypeID = H5Tget_member_type(hDataType, 1);
     295             :     const bool bRet = H5Tequal(ElemTypeID, H5T_NATIVE_FLOAT16) > 0 &&
     296             :                       H5Tequal(Elem2TypeID, H5T_NATIVE_FLOAT16) > 0;
     297             :     H5Tclose(ElemTypeID);
     298             :     H5Tclose(Elem2TypeID);
     299             :     return bRet;
     300             : #else
     301           0 :     CPL_IGNORE_RET_VAL(hDataType);
     302           0 :     return false;
     303             : #endif
     304             : }
     305             : 
     306             : /************************************************************************/
     307             : /*                          GetDataTypeName()                           */
     308             : /*                                                                      */
     309             : /*      Return the human readable name of data type                     */
     310             : /************************************************************************/
     311         180 : const char *HDF5Dataset::GetDataTypeName(hid_t TypeID)
     312             : {
     313             :     // Check for native types first
     314         180 :     if (H5Tget_class(TypeID) != H5T_COMPOUND)
     315             :     {
     316         168 :         if (H5Tequal(H5T_NATIVE_CHAR, TypeID))
     317           0 :             return "8-bit character";
     318         168 :         else if (H5Tequal(H5T_NATIVE_SCHAR, TypeID))
     319           0 :             return "8-bit signed character";
     320         168 :         else if (H5Tequal(H5T_NATIVE_UCHAR, TypeID))
     321          28 :             return "8-bit unsigned character";
     322         140 :         else if (H5Tequal(H5T_NATIVE_SHORT, TypeID))
     323           0 :             return "16-bit integer";
     324         140 :         else if (H5Tequal(H5T_NATIVE_USHORT, TypeID))
     325           9 :             return "16-bit unsigned integer";
     326         131 :         else if (H5Tequal(H5T_NATIVE_INT, TypeID))
     327          88 :             return "32-bit integer";
     328          43 :         else if (H5Tequal(H5T_NATIVE_UINT, TypeID))
     329           4 :             return "32-bit unsigned integer";
     330          39 :         else if (H5Tequal(H5T_NATIVE_INT64, TypeID))
     331           4 :             return "64-bit integer";
     332          35 :         else if (H5Tequal(H5T_NATIVE_UINT64, TypeID))
     333           4 :             return "64-bit unsigned integer";
     334          31 :         else if (H5Tequal(H5T_NATIVE_LONG, TypeID))
     335           0 :             return "32/64-bit integer";
     336          31 :         else if (H5Tequal(H5T_NATIVE_ULONG, TypeID))
     337           0 :             return "32/64-bit unsigned integer";
     338             : #ifdef HDF5_HAVE_FLOAT16
     339             :         else if (H5Tequal(H5T_NATIVE_FLOAT16, TypeID))
     340             :             return "16-bit floating-point";
     341             : #endif
     342          31 :         else if (H5Tequal(H5T_NATIVE_FLOAT, TypeID))
     343          15 :             return "32-bit floating-point";
     344          16 :         else if (H5Tequal(H5T_NATIVE_DOUBLE, TypeID))
     345           0 :             return "64-bit floating-point";
     346          16 :         else if (H5Tequal(H5T_NATIVE_LLONG, TypeID))
     347           0 :             return "64-bit integer";
     348          16 :         else if (H5Tequal(H5T_NATIVE_ULLONG, TypeID))
     349           0 :             return "64-bit unsigned integer";
     350          16 :         else if (H5Tequal(H5T_NATIVE_DOUBLE, TypeID))
     351           0 :             return "64-bit floating-point";
     352             :     }
     353             :     else
     354             :     {
     355             :         // For complex the compound type must contain 2 elements
     356          12 :         if (H5Tget_nmembers(TypeID) != 2)
     357           2 :             return "Unknown";
     358             : 
     359             :         // For complex the native types of both elements should be the same
     360          10 :         hid_t ElemTypeID = H5Tget_member_type(TypeID, 0);
     361          10 :         hid_t Elem2TypeID = H5Tget_member_type(TypeID, 1);
     362          10 :         const bool bTypeEqual = H5Tequal(ElemTypeID, Elem2TypeID) > 0;
     363          10 :         H5Tclose(Elem2TypeID);
     364          10 :         if (!bTypeEqual)
     365             :         {
     366           0 :             H5Tclose(ElemTypeID);
     367           0 :             return "Unknown";
     368             :         }
     369             : 
     370             :         // Check the native types to determine CInt16, CFloat32 or CFloat64
     371          10 :         if (H5Tequal(H5T_NATIVE_SHORT, ElemTypeID))
     372             :         {
     373           0 :             H5Tclose(ElemTypeID);
     374           0 :             return "complex, 16-bit integer";
     375             :         }
     376          10 :         else if (H5Tequal(H5T_NATIVE_INT, ElemTypeID))
     377             :         {
     378           0 :             H5Tclose(ElemTypeID);
     379           0 :             return "complex, 32-bit integer";
     380             :         }
     381          10 :         else if (H5Tequal(H5T_NATIVE_LONG, ElemTypeID))
     382             :         {
     383           0 :             H5Tclose(ElemTypeID);
     384           0 :             return "complex, 32/64-bit integer";
     385             :         }
     386             : #ifdef HDF5_HAVE_FLOAT16
     387             :         else if (H5Tequal(H5T_NATIVE_FLOAT16, ElemTypeID))
     388             :         {
     389             :             H5Tclose(ElemTypeID);
     390             :             return "complex, 16-bit floating-point";
     391             :         }
     392             : #endif
     393          10 :         else if (H5Tequal(H5T_NATIVE_FLOAT, ElemTypeID))
     394             :         {
     395           7 :             H5Tclose(ElemTypeID);
     396           7 :             return "complex, 32-bit floating-point";
     397             :         }
     398           3 :         else if (H5Tequal(H5T_NATIVE_DOUBLE, ElemTypeID))
     399             :         {
     400           3 :             H5Tclose(ElemTypeID);
     401           3 :             return "complex, 64-bit floating-point";
     402             :         }
     403             :     }
     404             : 
     405          16 :     return "Unknown";
     406             : }
     407             : 
     408             : /************************************************************************/
     409             : /*                           GDAL_HDF5Open()                            */
     410             : /************************************************************************/
     411         173 : hid_t GDAL_HDF5Open(const std::string &osFilename)
     412             : {
     413             :     hid_t hHDF5;
     414             :     // Heuristics to able datasets split over several files, using the 'family'
     415             :     // driver. If passed the first file, and it contains a single 0, or
     416             :     // ends up with 0.h5 or 0.hdf5, replace the 0 with %d and try the family
     417             :     // driver.
     418         339 :     if (std::count(osFilename.begin(), osFilename.end(), '0') == 1 ||
     419         339 :         osFilename.find("0.h5") != std::string::npos ||
     420         165 :         osFilename.find("0.hdf5") != std::string::npos)
     421             :     {
     422           8 :         const auto zero_pos = osFilename.rfind('0');
     423          16 :         const auto osNewName = osFilename.substr(0, zero_pos) + "%d" +
     424          16 :                                osFilename.substr(zero_pos + 1);
     425           8 :         hid_t fapl = H5Pcreate(H5P_FILE_ACCESS);
     426           8 :         H5Pset_fapl_family(fapl, H5F_FAMILY_DEFAULT, H5P_DEFAULT);
     427             : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
     428             : #pragma GCC diagnostic push
     429             : #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
     430             : #endif
     431           8 :         H5E_BEGIN_TRY
     432             :         {
     433           8 :             hHDF5 = H5Fopen(osNewName.c_str(), H5F_ACC_RDONLY, fapl);
     434             :         }
     435           8 :         H5E_END_TRY;
     436             : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
     437             : #pragma GCC diagnostic pop
     438             : #endif
     439           8 :         H5Pclose(fapl);
     440           8 :         if (hHDF5 >= 0)
     441             :         {
     442           4 :             CPLDebug("HDF5", "Actually opening %s with 'family' driver",
     443             :                      osNewName.c_str());
     444           4 :             return hHDF5;
     445             :         }
     446             :     }
     447             : 
     448         169 :     hid_t fapl = H5Pcreate(H5P_FILE_ACCESS);
     449         169 :     H5Pset_driver(fapl, HDF5GetFileDriver(), nullptr);
     450         169 :     hHDF5 = H5Fopen(osFilename.c_str(), H5F_ACC_RDONLY, fapl);
     451         169 :     H5Pclose(fapl);
     452         169 :     return hHDF5;
     453             : }
     454             : 
     455             : /************************************************************************/
     456             : /*                                Open()                                */
     457             : /************************************************************************/
     458         106 : GDALDataset *HDF5Dataset::Open(GDALOpenInfo *poOpenInfo)
     459             : {
     460         106 :     if (!HDF5DatasetIdentify(poOpenInfo))
     461           0 :         return nullptr;
     462             : 
     463             :     HDF5_GLOBAL_LOCK();
     464             : 
     465         106 :     if (poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER)
     466             :     {
     467          30 :         return OpenMultiDim(poOpenInfo);
     468             :     }
     469             : 
     470             :     // Create datasource.
     471          76 :     HDF5Dataset *const poDS = new HDF5Dataset();
     472             : 
     473          76 :     poDS->SetDescription(poOpenInfo->pszFilename);
     474             : 
     475             :     // Try opening the dataset.
     476          76 :     poDS->m_hHDF5 = GDAL_HDF5Open(poOpenInfo->pszFilename);
     477          76 :     if (poDS->m_hHDF5 < 0)
     478             :     {
     479           0 :         delete poDS;
     480           0 :         return nullptr;
     481             :     }
     482             : 
     483          76 :     poDS->hGroupID = H5Gopen(poDS->m_hHDF5, "/");
     484          76 :     if (poDS->hGroupID < 0)
     485             :     {
     486           0 :         delete poDS;
     487           0 :         return nullptr;
     488             :     }
     489             : 
     490          76 :     if (HDF5EOSParser::HasHDFEOS(poDS->hGroupID))
     491             :     {
     492           7 :         if (poDS->m_oHDFEOSParser.Parse(poDS->hGroupID))
     493             :         {
     494           7 :             CPLDebug("HDF5", "Successfully parsed HDFEOS metadata");
     495             :         }
     496             :     }
     497             : 
     498          76 :     poDS->ReadGlobalAttributes(true);
     499             : 
     500          76 :     if (STARTS_WITH(poDS->m_aosMetadata.FetchNameValueDef("mission_name", ""),
     501           0 :                     "Sentinel 3") &&
     502           0 :         EQUAL(
     503             :             poDS->m_aosMetadata.FetchNameValueDef("altimeter_sensor_name", ""),
     504           0 :             "SRAL") &&
     505           0 :         EQUAL(
     506             :             poDS->m_aosMetadata.FetchNameValueDef("radiometer_sensor_name", ""),
     507          76 :             "MWR") &&
     508           0 :         GDALGetDriverByName("netCDF") != nullptr)
     509             :     {
     510           0 :         delete poDS;
     511           0 :         return nullptr;
     512             :     }
     513             : 
     514             :     // Safety belt if S102Dataset::Identify() failed
     515          76 :     if (STARTS_WITH(
     516             :             poDS->m_aosMetadata.FetchNameValueDef("productSpecification", ""),
     517          77 :             "INT.IHO.S-102.") &&
     518           1 :         GDALGetDriverByName("S102") != nullptr)
     519             :     {
     520           1 :         delete poDS;
     521           2 :         std::string osS102Filename("S102:\"");
     522             :         osS102Filename +=
     523           1 :             CPLString(poOpenInfo->pszFilename).replaceAll("\"", "\\\"");
     524           1 :         osS102Filename += '"';
     525           1 :         return GDALDataset::Open(osS102Filename.c_str(), GDAL_OF_RASTER);
     526             :     }
     527             : 
     528             :     // Safety belt if S104Dataset::Identify() failed
     529          75 :     if (STARTS_WITH(
     530             :             poDS->m_aosMetadata.FetchNameValueDef("productSpecification", ""),
     531          77 :             "INT.IHO.S-104.") &&
     532           2 :         GDALGetDriverByName("S104") != nullptr)
     533             :     {
     534           2 :         delete poDS;
     535           4 :         std::string osS104Filename("S104:\"");
     536             :         osS104Filename +=
     537           2 :             CPLString(poOpenInfo->pszFilename).replaceAll("\"", "\\\"");
     538           2 :         osS104Filename += '"';
     539           2 :         return GDALDataset::Open(osS104Filename.c_str(), GDAL_OF_RASTER);
     540             :     }
     541             : 
     542             :     // Safety belt if S111Dataset::Identify() failed
     543          73 :     if (STARTS_WITH(
     544             :             poDS->m_aosMetadata.FetchNameValueDef("productSpecification", ""),
     545          74 :             "INT.IHO.S-111.") &&
     546           1 :         GDALGetDriverByName("S111") != nullptr)
     547             :     {
     548           1 :         delete poDS;
     549           2 :         std::string osS111Filename("S111:\"");
     550             :         osS111Filename +=
     551           1 :             CPLString(poOpenInfo->pszFilename).replaceAll("\"", "\\\"");
     552           1 :         osS111Filename += '"';
     553           1 :         return GDALDataset::Open(osS111Filename.c_str(), GDAL_OF_RASTER);
     554             :     }
     555             : 
     556          72 :     poDS->SetMetadata(poDS->m_aosMetadata.List());
     557             : 
     558          72 :     if (CSLCount(poDS->papszSubDatasets) / 2 >= 1)
     559          56 :         poDS->SetMetadata(poDS->papszSubDatasets, "SUBDATASETS");
     560             : 
     561             :     // Make sure we don't try to do any pam stuff with this dataset.
     562          72 :     poDS->nPamFlags |= GPF_NOSAVE;
     563             : 
     564             :     // If we have single subdataset only, open it immediately.
     565          72 :     int nSubDatasets = CSLCount(poDS->papszSubDatasets) / 2;
     566          72 :     if (nSubDatasets == 1)
     567             :     {
     568             :         CPLString osDSName =
     569          62 :             CSLFetchNameValue(poDS->papszSubDatasets, "SUBDATASET_1_NAME");
     570          31 :         delete poDS;
     571          31 :         return GDALDataset::Open(osDSName, poOpenInfo->nOpenFlags, nullptr,
     572          62 :                                  poOpenInfo->papszOpenOptions, nullptr);
     573             :     }
     574             :     else
     575             :     {
     576             :         // Confirm the requested access is supported.
     577          41 :         if (poOpenInfo->eAccess == GA_Update)
     578             :         {
     579           0 :             delete poDS;
     580           0 :             ReportUpdateNotSupportedByDriver("HDF5");
     581           0 :             return nullptr;
     582             :         }
     583             :     }
     584          41 :     return poDS;
     585             : }
     586             : 
     587             : /************************************************************************/
     588             : /*                          DestroyH5Objects()                          */
     589             : /*                                                                      */
     590             : /*      Erase all objects                                               */
     591             : /************************************************************************/
     592         886 : void HDF5Dataset::DestroyH5Objects(HDF5GroupObjects *poH5Object)
     593             : {
     594             :     // Visit all objects.
     595        1633 :     for (unsigned i = 0; i < poH5Object->nbObjs; i++)
     596         747 :         DestroyH5Objects(poH5Object->poHchild + i);
     597             : 
     598         886 :     if (poH5Object->poHparent == nullptr)
     599         146 :         return;
     600             : 
     601             :     // Erase some data.
     602         740 :     CPLFree(poH5Object->paDims);
     603         740 :     poH5Object->paDims = nullptr;
     604             : 
     605         740 :     CPLFree(poH5Object->pszPath);
     606         740 :     poH5Object->pszPath = nullptr;
     607             : 
     608         740 :     CPLFree(poH5Object->pszName);
     609         740 :     poH5Object->pszName = nullptr;
     610             : 
     611         740 :     CPLFree(poH5Object->pszUnderscorePath);
     612         740 :     poH5Object->pszUnderscorePath = nullptr;
     613             : 
     614         740 :     if (poH5Object->native > 0)
     615         446 :         H5Tclose(poH5Object->native);
     616         740 :     poH5Object->native = 0;
     617             : 
     618             :     // All Children are visited and can be deleted.
     619         740 :     if (poH5Object->nbObjs != 0)
     620             :     {
     621         241 :         CPLFree(poH5Object->poHchild);
     622         241 :         poH5Object->poHchild = nullptr;
     623             :     }
     624             : }
     625             : 
     626             : /************************************************************************/
     627             : /*                             CreatePath()                             */
     628             : /*                                                                      */
     629             : /*      Find Dataset path for HDopen                                    */
     630             : /************************************************************************/
     631        2415 : static void CreatePath(HDF5GroupObjects *poH5Object)
     632             : {
     633             :     // Recurse to the root path.
     634        4830 :     CPLString osPath;
     635        2415 :     if (poH5Object->poHparent != nullptr)
     636             :     {
     637        1675 :         CreatePath(poH5Object->poHparent);
     638        1675 :         osPath = poH5Object->poHparent->pszPath;
     639             :     }
     640             : 
     641             :     // Add name to the path.
     642        2415 :     if (!EQUAL(poH5Object->pszName, "/"))
     643             :     {
     644        1675 :         osPath.append("/");
     645        1675 :         osPath.append(poH5Object->pszName);
     646             :     }
     647             : 
     648             :     // Fill up path for each object.
     649        4830 :     CPLString osUnderscoreSpaceInName;
     650        2415 :     if (poH5Object->pszPath == nullptr)
     651             :     {
     652             :         // This is completely useless but needed if we want to keep
     653             :         // subdataset names as they have "always" been formatted,
     654             :         // with double slash at the beginning
     655         865 :         if (osPath.empty())
     656         125 :             osPath = "/";
     657             : 
     658             :         // Change space for underscore.
     659             :         char **papszPath =
     660         865 :             CSLTokenizeString2(osPath.c_str(), " ", CSLT_HONOURSTRINGS);
     661             : 
     662        2091 :         for (int i = 0; papszPath[i] != nullptr; i++)
     663             :         {
     664        1226 :             if (i > 0)
     665         361 :                 osUnderscoreSpaceInName.append("_");
     666        1226 :             osUnderscoreSpaceInName.append(papszPath[i]);
     667             :         }
     668         865 :         CSLDestroy(papszPath);
     669             : 
     670             :         // -1 to give room for NUL in C strings.
     671         865 :         constexpr size_t MAX_PATH = 8192 - 1;
     672             :         // TODO(schwehr): Is it an issue if the results are longer than 8192?
     673             :         // It appears that the output can never be longer than the source.
     674         865 :         if (osUnderscoreSpaceInName.size() > MAX_PATH)
     675           0 :             CPLError(CE_Fatal, CPLE_AppDefined,
     676             :                      "osUnderscoreSpaceInName longer than MAX_PATH: "
     677             :                      "%u > %u",
     678           0 :                      static_cast<unsigned int>(osUnderscoreSpaceInName.size()),
     679             :                      static_cast<unsigned int>(MAX_PATH));
     680         865 :         if (osPath.size() > MAX_PATH)
     681           0 :             CPLError(CE_Fatal, CPLE_AppDefined,
     682             :                      "osPath longer than MAX_PATH: %u > %u",
     683           0 :                      static_cast<unsigned int>(osPath.size()),
     684             :                      static_cast<unsigned int>(MAX_PATH));
     685             : 
     686         865 :         poH5Object->pszUnderscorePath =
     687         865 :             CPLStrdup(osUnderscoreSpaceInName.c_str());
     688         865 :         poH5Object->pszPath = CPLStrdup(osPath.c_str());
     689             :     }
     690        2415 : }
     691             : 
     692             : /************************************************************************/
     693             : /*                      HDF5GroupCheckDuplicate()                       */
     694             : /*                                                                      */
     695             : /*      Returns TRUE if an ancestor has the same objno[] as passed      */
     696             : /*      in - used to avoid looping in files with "links up" #(3218).    */
     697             : /************************************************************************/
     698             : 
     699         916 : static int HDF5GroupCheckDuplicate(HDF5GroupObjects *poHparent,
     700             :                                    unsigned long *objno)
     701             : 
     702             : {
     703         916 :     while (poHparent != nullptr)
     704             :     {
     705         628 :         if (poHparent->objno[0] == objno[0] && poHparent->objno[1] == objno[1])
     706           2 :             return TRUE;
     707             : 
     708         626 :         poHparent = poHparent->poHparent;
     709             :     }
     710             : 
     711         288 :     return FALSE;
     712             : }
     713             : 
     714             : /************************************************************************/
     715             : /*                      HDF5CreateGroupObjs()                           */
     716             : /*                                                                      */
     717             : /*      Create HDF5 hierarchy into a linked list                        */
     718             : /************************************************************************/
     719         740 : herr_t HDF5CreateGroupObjs(hid_t hHDF5, const char *pszObjName,
     720             :                            void *poHObjParent)
     721             : {
     722         740 :     HDF5GroupObjects *const poHparent =
     723             :         static_cast<HDF5GroupObjects *>(poHObjParent);
     724         740 :     HDF5GroupObjects *poHchild = poHparent->poHchild;
     725             :     H5G_stat_t oStatbuf;
     726             : 
     727         740 :     if (H5Gget_objinfo(hHDF5, pszObjName, FALSE, &oStatbuf) < 0)
     728           0 :         return -1;
     729             : 
     730             :     // Look for next child.
     731         740 :     unsigned idx = 0;  // idx is used after the for loop.
     732        1486 :     for (; idx < poHparent->nbObjs; idx++)
     733             :     {
     734        1486 :         if (poHchild->pszName == nullptr)
     735         740 :             break;
     736         746 :         poHchild++;
     737             :     }
     738             : 
     739         740 :     if (idx == poHparent->nbObjs)
     740           0 :         return -1;  // All children parsed.
     741             : 
     742             :     // Save child information.
     743         740 :     poHchild->pszName = CPLStrdup(pszObjName);
     744             : 
     745         740 :     poHchild->nType = oStatbuf.type;
     746         740 :     poHchild->nIndex = idx;
     747         740 :     poHchild->poHparent = poHparent;
     748         740 :     poHchild->nRank = 0;
     749         740 :     poHchild->paDims = nullptr;
     750         740 :     poHchild->HDatatype = 0;
     751         740 :     poHchild->objno[0] = oStatbuf.objno[0];
     752         740 :     poHchild->objno[1] = oStatbuf.objno[1];
     753         740 :     if (poHchild->pszPath == nullptr)
     754             :     {
     755         740 :         CreatePath(poHchild);
     756             :     }
     757         740 :     if (poHparent->pszPath == nullptr)
     758             :     {
     759           0 :         CreatePath(poHparent);
     760             :     }
     761             : 
     762         740 :     switch (oStatbuf.type)
     763             :     {
     764           3 :         case H5G_LINK:
     765             :         {
     766           3 :             poHchild->nbAttrs = 0;
     767           3 :             poHchild->nbObjs = 0;
     768           3 :             poHchild->poHchild = nullptr;
     769           3 :             poHchild->nRank = 0;
     770           3 :             poHchild->paDims = nullptr;
     771           3 :             poHchild->HDatatype = 0;
     772           3 :             break;
     773             :         }
     774         290 :         case H5G_GROUP:
     775             :         {
     776         290 :             hid_t hGroupID = H5I_INVALID_HID;  // Identifier of group.
     777         290 :             if ((hGroupID = H5Gopen(hHDF5, pszObjName)) == -1)
     778             :             {
     779           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     780             :                          "unable to access \"%s\" group.", pszObjName);
     781           0 :                 return -1;
     782             :             }
     783             :             // Number of attributes in object.
     784         290 :             const int nbAttrs = H5Aget_num_attrs(hGroupID);
     785         290 :             hsize_t nbObjs = 0;  // Number of objects in a group.
     786         290 :             H5Gget_num_objs(hGroupID, &nbObjs);
     787             :             // Arbitrary threshold bigger than any conceivable reasonable use,
     788             :             // to prevent denial of service and integer overflow.
     789         290 :             if (nbObjs > 10 * 1000 * 1000)
     790             :             {
     791           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     792             :                          "Too many attributes in \"%s\" group.", pszObjName);
     793           0 :                 H5Gclose(hGroupID);
     794           0 :                 return -1;
     795             :             }
     796         290 :             poHchild->nbAttrs = nbAttrs;
     797         290 :             poHchild->nbObjs = nbObjs;
     798         290 :             poHchild->nRank = 0;
     799         290 :             poHchild->paDims = nullptr;
     800         290 :             poHchild->HDatatype = 0;
     801             : 
     802         290 :             if (nbObjs > 0)
     803             :             {
     804         241 :                 poHchild->poHchild =
     805         241 :                     static_cast<HDF5GroupObjects *>(VSI_CALLOC_VERBOSE(
     806             :                         static_cast<int>(nbObjs), sizeof(HDF5GroupObjects)));
     807         241 :                 if (!poHchild->poHchild)
     808             :                 {
     809           0 :                     H5Gclose(hGroupID);
     810           0 :                     return -1;
     811             :                 }
     812             :             }
     813             :             else
     814             :             {
     815          49 :                 poHchild->poHchild = nullptr;
     816             :             }
     817             : 
     818         290 :             if (!HDF5GroupCheckDuplicate(poHparent, oStatbuf.objno))
     819         288 :                 H5Giterate(hHDF5, pszObjName, nullptr, HDF5CreateGroupObjs,
     820             :                            poHchild);
     821             :             else
     822           2 :                 CPLDebug("HDF5", "avoiding link looping on node '%s'.",
     823             :                          pszObjName);
     824             : 
     825         290 :             H5Gclose(hGroupID);
     826         290 :             break;
     827             :         }
     828         446 :         case H5G_DATASET:
     829             :         {
     830         446 :             hid_t hDatasetID = H5I_INVALID_HID;  // Identifier of dataset.
     831         446 :             if ((hDatasetID = H5Dopen(hHDF5, pszObjName)) == -1)
     832             :             {
     833           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     834             :                          "unable to access \"%s\" dataset.", pszObjName);
     835           0 :                 return -1;
     836             :             }
     837         446 :             const int nbAttrs = H5Aget_num_attrs(hDatasetID);
     838         446 :             const hid_t datatype = H5Dget_type(hDatasetID);
     839         446 :             const hid_t dataspace = H5Dget_space(hDatasetID);
     840         446 :             const int n_dims = H5Sget_simple_extent_ndims(dataspace);
     841         446 :             const hid_t native = H5Tget_native_type(datatype, H5T_DIR_ASCEND);
     842         446 :             hsize_t *maxdims = nullptr;
     843         446 :             hsize_t *dims = nullptr;
     844             : 
     845         446 :             if (n_dims > 0)
     846             :             {
     847             :                 dims =
     848         396 :                     static_cast<hsize_t *>(CPLCalloc(n_dims, sizeof(hsize_t)));
     849             :                 maxdims =
     850         396 :                     static_cast<hsize_t *>(CPLCalloc(n_dims, sizeof(hsize_t)));
     851             :             }
     852         446 :             H5Sget_simple_extent_dims(dataspace, dims, maxdims);
     853         446 :             if (maxdims != nullptr)
     854         396 :                 CPLFree(maxdims);
     855             : 
     856         446 :             if (n_dims > 0)
     857             :             {
     858         396 :                 poHchild->nRank = n_dims;        // rank of the array
     859         396 :                 poHchild->paDims = dims;         // dimension of the array.
     860         396 :                 poHchild->HDatatype = datatype;  // HDF5 datatype
     861             :             }
     862             :             else
     863             :             {
     864          50 :                 poHchild->nRank = -1;
     865          50 :                 poHchild->paDims = nullptr;
     866          50 :                 poHchild->HDatatype = 0;
     867             :             }
     868         446 :             poHchild->nbAttrs = nbAttrs;
     869         446 :             poHchild->nbObjs = 0;
     870         446 :             poHchild->poHchild = nullptr;
     871         446 :             poHchild->native = native;
     872         446 :             H5Tclose(datatype);
     873         446 :             H5Sclose(dataspace);
     874         446 :             H5Dclose(hDatasetID);
     875         446 :             break;
     876             :         }
     877           0 :         case H5G_TYPE:
     878             :         {
     879           0 :             poHchild->nbAttrs = 0;
     880           0 :             poHchild->nbObjs = 0;
     881           0 :             poHchild->poHchild = nullptr;
     882           0 :             poHchild->nRank = 0;
     883           0 :             poHchild->paDims = nullptr;
     884           0 :             poHchild->HDatatype = 0;
     885           0 :             break;
     886             :         }
     887           1 :         default:
     888           1 :             break;
     889             :     }
     890             : 
     891         740 :     return 0;
     892             : }
     893             : 
     894             : /************************************************************************/
     895             : /*                   HDF5DatasetCreateMetadataContext                   */
     896             : /************************************************************************/
     897             : 
     898             : struct HDF5DatasetCreateMetadataContext
     899             : {
     900             :     std::string m_osKey{};
     901             :     CPLStringList &m_aosMetadata;
     902             : 
     903             :     // Work variables
     904             :     std::string m_osValue{};
     905             : 
     906         688 :     explicit HDF5DatasetCreateMetadataContext(CPLStringList &aosMetadata)
     907         688 :         : m_aosMetadata(aosMetadata)
     908             :     {
     909         688 :     }
     910             : };
     911             : 
     912             : /************************************************************************/
     913             : /*                          HDF5AttrIterate()                           */
     914             : /************************************************************************/
     915             : 
     916        1453 : static herr_t HDF5AttrIterate(hid_t hH5ObjID, const char *pszAttrName,
     917             :                               void *pContext)
     918             : {
     919        1453 :     HDF5DatasetCreateMetadataContext *const psContext =
     920             :         static_cast<HDF5DatasetCreateMetadataContext *>(pContext);
     921             : 
     922        1453 :     psContext->m_osValue.clear();
     923             : 
     924        2906 :     std::string osKey(psContext->m_osKey);
     925             :     // Convert whitespaces into "_" for the attribute name component
     926             :     const CPLStringList aosTokens(CSLTokenizeString2(
     927        2906 :         pszAttrName, " ", CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES));
     928        3651 :     for (int i = 0; i < aosTokens.size(); ++i)
     929             :     {
     930        2198 :         if (!osKey.empty())
     931        1671 :             osKey += '_';
     932        2198 :         osKey += aosTokens[i];
     933             :     }
     934             : 
     935        1453 :     const hid_t hAttrID = H5Aopen_name(hH5ObjID, pszAttrName);
     936        1453 :     const hid_t hAttrTypeID = H5Aget_type(hAttrID);
     937             :     const hid_t hAttrNativeType =
     938        1453 :         H5Tget_native_type(hAttrTypeID, H5T_DIR_DEFAULT);
     939        1453 :     const hid_t hAttrSpace = H5Aget_space(hAttrID);
     940             : 
     941        1453 :     if (H5Tget_class(hAttrNativeType) == H5T_VLEN)
     942             :     {
     943          40 :         H5Sclose(hAttrSpace);
     944          40 :         H5Tclose(hAttrNativeType);
     945          40 :         H5Tclose(hAttrTypeID);
     946          40 :         H5Aclose(hAttrID);
     947          40 :         return 0;
     948             :     }
     949             : 
     950        1413 :     hsize_t nSize[64] = {};
     951             :     const unsigned int nAttrDims =
     952        1413 :         H5Sget_simple_extent_dims(hAttrSpace, nSize, nullptr);
     953             : 
     954        1413 :     size_t nAttrElmts = 1;
     955        2109 :     for (hsize_t i = 0; i < nAttrDims; i++)
     956             :     {
     957         696 :         if (nSize[i] > std::numeric_limits<size_t>::max() / nAttrElmts)
     958             :         {
     959           0 :             H5Sclose(hAttrSpace);
     960           0 :             H5Tclose(hAttrNativeType);
     961           0 :             H5Tclose(hAttrTypeID);
     962           0 :             H5Aclose(hAttrID);
     963           0 :             return 0;
     964             :         }
     965         696 :         nAttrElmts *= static_cast<size_t>(nSize[i]);
     966             :     }
     967             : 
     968        1413 :     if (H5Tget_class(hAttrNativeType) == H5T_STRING)
     969             :     {
     970         625 :         if (H5Tis_variable_str(hAttrNativeType))
     971             :         {
     972             :             char **papszStrings = static_cast<char **>(
     973          92 :                 VSI_MALLOC2_VERBOSE(nAttrElmts, sizeof(char *)));
     974          92 :             if (papszStrings)
     975             :             {
     976             :                 // Read the values.
     977          92 :                 H5Aread(hAttrID, hAttrNativeType, papszStrings);
     978             : 
     979             :                 // Concatenate all values as one string separated by a space.
     980             :                 psContext->m_osValue =
     981          92 :                     papszStrings[0] ? papszStrings[0] : "{NULL}";
     982         174 :                 for (hsize_t i = 1; i < nAttrElmts; i++)
     983             :                 {
     984          82 :                     psContext->m_osValue += " ";
     985             :                     psContext->m_osValue +=
     986          82 :                         papszStrings[i] ? papszStrings[i] : "{NULL}";
     987             :                 }
     988             : 
     989          92 :                 H5Dvlen_reclaim(hAttrNativeType, hAttrSpace, H5P_DEFAULT,
     990             :                                 papszStrings);
     991          92 :                 CPLFree(papszStrings);
     992             :             }
     993             :         }
     994             :         else
     995             :         {
     996         533 :             const hsize_t nAttrSize = H5Aget_storage_size(hAttrID);
     997         533 :             if (nAttrSize <= static_cast<hsize_t>(INT_MAX))
     998             :             {
     999             :                 try
    1000             :                 {
    1001         533 :                     psContext->m_osValue.resize(static_cast<size_t>(nAttrSize));
    1002         533 :                     H5Aread(hAttrID, hAttrNativeType, &psContext->m_osValue[0]);
    1003             :                 }
    1004           0 :                 catch (const std::exception &)
    1005             :                 {
    1006             :                 }
    1007             :             }
    1008             :         }
    1009             :     }
    1010             :     else
    1011             :     {
    1012         788 :         constexpr size_t nDataLen = 32;
    1013             :         char szData[nDataLen];
    1014             : 
    1015         788 :         void *buf = nullptr;
    1016             : 
    1017         788 :         if (nAttrElmts > 0)
    1018             :         {
    1019         788 :             buf = VSI_MALLOC2_VERBOSE(nAttrElmts, H5Tget_size(hAttrNativeType));
    1020         788 :             if (buf)
    1021         788 :                 H5Aread(hAttrID, hAttrNativeType, buf);
    1022             :         }
    1023         788 :         const bool bIsSCHAR = H5Tequal(H5T_NATIVE_SCHAR, hAttrNativeType) > 0;
    1024         788 :         const bool bIsUCHAR = H5Tequal(H5T_NATIVE_UCHAR, hAttrNativeType) > 0;
    1025         799 :         if (buf && (bIsSCHAR || bIsUCHAR) &&
    1026          11 :             CPLTestBool(CPLGetConfigOption("GDAL_HDF5_CHAR_AS_STRING", "NO")))
    1027             :         {
    1028             :             // Compatibility mode with ancient GDAL versions where we consider
    1029             :             // array of SCHAR/UCHAR as strings. Likely inappropriate mode...
    1030           0 :             for (hsize_t i = 0; i < nAttrElmts; i++)
    1031             :             {
    1032           0 :                 snprintf(szData, nDataLen, "%c", static_cast<char *>(buf)[i]);
    1033           0 :                 if (psContext->m_osValue.size() > MAX_METADATA_LEN)
    1034             :                 {
    1035           0 :                     CPLError(CE_Warning, CPLE_OutOfMemory,
    1036             :                              "Header data too long. Truncated");
    1037           0 :                     break;
    1038             :                 }
    1039           0 :                 psContext->m_osValue += szData;
    1040             :             }
    1041             :         }
    1042         788 :         else if (buf && bIsSCHAR)
    1043             :         {
    1044           4 :             for (hsize_t i = 0; i < nAttrElmts; i++)
    1045             :             {
    1046           2 :                 snprintf(szData, nDataLen, "%d",
    1047           2 :                          static_cast<signed char *>(buf)[i]);
    1048           2 :                 if (psContext->m_osValue.size() > MAX_METADATA_LEN)
    1049             :                 {
    1050           0 :                     CPLError(CE_Warning, CPLE_OutOfMemory,
    1051             :                              "Header data too long. Truncated");
    1052           0 :                     break;
    1053             :                 }
    1054           2 :                 if (i > 0)
    1055           0 :                     psContext->m_osValue += ' ';
    1056           2 :                 psContext->m_osValue += szData;
    1057           2 :             }
    1058             :         }
    1059         786 :         else if (buf && bIsUCHAR)
    1060             :         {
    1061          18 :             for (hsize_t i = 0; i < nAttrElmts; i++)
    1062             :             {
    1063           9 :                 snprintf(szData, nDataLen, "%u",
    1064           9 :                          static_cast<unsigned char *>(buf)[i]);
    1065           9 :                 if (psContext->m_osValue.size() > MAX_METADATA_LEN)
    1066             :                 {
    1067           0 :                     CPLError(CE_Warning, CPLE_OutOfMemory,
    1068             :                              "Header data too long. Truncated");
    1069           0 :                     break;
    1070             :                 }
    1071           9 :                 if (i > 0)
    1072           0 :                     psContext->m_osValue += ' ';
    1073           9 :                 psContext->m_osValue += szData;
    1074           9 :             }
    1075             :         }
    1076         777 :         else if (buf && H5Tequal(H5T_NATIVE_SHORT, hAttrNativeType) > 0)
    1077             :         {
    1078          38 :             for (hsize_t i = 0; i < nAttrElmts; i++)
    1079             :             {
    1080          19 :                 snprintf(szData, nDataLen, "%d", static_cast<short *>(buf)[i]);
    1081          19 :                 if (psContext->m_osValue.size() > MAX_METADATA_LEN)
    1082             :                 {
    1083           0 :                     CPLError(CE_Warning, CPLE_OutOfMemory,
    1084             :                              "Header data too long. Truncated");
    1085           0 :                     break;
    1086             :                 }
    1087          19 :                 if (i > 0)
    1088           0 :                     psContext->m_osValue += ' ';
    1089          19 :                 psContext->m_osValue += szData;
    1090             :             }
    1091             :         }
    1092         758 :         else if (buf && H5Tequal(H5T_NATIVE_USHORT, hAttrNativeType) > 0)
    1093             :         {
    1094          46 :             for (hsize_t i = 0; i < nAttrElmts; i++)
    1095             :             {
    1096          23 :                 snprintf(szData, nDataLen, "%u",
    1097          23 :                          static_cast<unsigned short *>(buf)[i]);
    1098          23 :                 if (psContext->m_osValue.size() > MAX_METADATA_LEN)
    1099             :                 {
    1100           0 :                     CPLError(CE_Warning, CPLE_OutOfMemory,
    1101             :                              "Header data too long. Truncated");
    1102           0 :                     break;
    1103             :                 }
    1104          23 :                 if (i > 0)
    1105           0 :                     psContext->m_osValue += ' ';
    1106          23 :                 psContext->m_osValue += szData;
    1107             :             }
    1108             :         }
    1109         735 :         else if (buf && H5Tequal(H5T_NATIVE_INT, hAttrNativeType) > 0)
    1110             :         {
    1111         370 :             for (hsize_t i = 0; i < nAttrElmts; i++)
    1112             :             {
    1113         199 :                 snprintf(szData, nDataLen, "%d", static_cast<int *>(buf)[i]);
    1114         199 :                 if (psContext->m_osValue.size() > MAX_METADATA_LEN)
    1115             :                 {
    1116           0 :                     CPLError(CE_Warning, CPLE_OutOfMemory,
    1117             :                              "Header data too long. Truncated");
    1118           0 :                     break;
    1119             :                 }
    1120         199 :                 if (i > 0)
    1121          28 :                     psContext->m_osValue += ' ';
    1122         199 :                 psContext->m_osValue += szData;
    1123             :             }
    1124             :         }
    1125         564 :         else if (buf && H5Tequal(H5T_NATIVE_UINT, hAttrNativeType) > 0)
    1126             :         {
    1127         216 :             for (hsize_t i = 0; i < nAttrElmts; i++)
    1128             :             {
    1129         108 :                 snprintf(szData, nDataLen, "%u",
    1130         108 :                          static_cast<unsigned int *>(buf)[i]);
    1131         108 :                 if (psContext->m_osValue.size() > MAX_METADATA_LEN)
    1132             :                 {
    1133           0 :                     CPLError(CE_Warning, CPLE_OutOfMemory,
    1134             :                              "Header data too long. Truncated");
    1135           0 :                     break;
    1136             :                 }
    1137         108 :                 if (i > 0)
    1138           0 :                     psContext->m_osValue += ' ';
    1139         108 :                 psContext->m_osValue += szData;
    1140             :             }
    1141             :         }
    1142         456 :         else if (buf && H5Tequal(H5T_NATIVE_INT64, hAttrNativeType) > 0)
    1143             :         {
    1144         100 :             for (hsize_t i = 0; i < nAttrElmts; i++)
    1145             :             {
    1146          65 :                 snprintf(szData, nDataLen, CPL_FRMT_GIB,
    1147          65 :                          static_cast<GIntBig *>(buf)[i]);
    1148          65 :                 if (psContext->m_osValue.size() > MAX_METADATA_LEN)
    1149             :                 {
    1150           0 :                     CPLError(CE_Warning, CPLE_OutOfMemory,
    1151             :                              "Header data too long. Truncated");
    1152           0 :                     break;
    1153             :                 }
    1154          65 :                 if (i > 0)
    1155          30 :                     psContext->m_osValue += ' ';
    1156          65 :                 psContext->m_osValue += szData;
    1157             :             }
    1158             :         }
    1159         421 :         else if (buf && H5Tequal(H5T_NATIVE_UINT64, hAttrNativeType) > 0)
    1160             :         {
    1161          10 :             for (hsize_t i = 0; i < nAttrElmts; i++)
    1162             :             {
    1163           5 :                 snprintf(szData, nDataLen, CPL_FRMT_GUIB,
    1164           5 :                          static_cast<GUIntBig *>(buf)[i]);
    1165           5 :                 if (psContext->m_osValue.size() > MAX_METADATA_LEN)
    1166             :                 {
    1167           0 :                     CPLError(CE_Warning, CPLE_OutOfMemory,
    1168             :                              "Header data too long. Truncated");
    1169           0 :                     break;
    1170             :                 }
    1171           5 :                 if (i > 0)
    1172           0 :                     psContext->m_osValue += ' ';
    1173           5 :                 psContext->m_osValue += szData;
    1174             :             }
    1175             :         }
    1176         416 :         else if (buf && H5Tequal(H5T_NATIVE_LONG, hAttrNativeType) > 0)
    1177             :         {
    1178           0 :             for (hsize_t i = 0; i < nAttrElmts; i++)
    1179             :             {
    1180           0 :                 snprintf(szData, nDataLen, "%ld", static_cast<long *>(buf)[i]);
    1181           0 :                 if (psContext->m_osValue.size() > MAX_METADATA_LEN)
    1182             :                 {
    1183           0 :                     CPLError(CE_Warning, CPLE_OutOfMemory,
    1184             :                              "Header data too long. Truncated");
    1185           0 :                     break;
    1186             :                 }
    1187           0 :                 if (i > 0)
    1188           0 :                     psContext->m_osValue += ' ';
    1189           0 :                 psContext->m_osValue += szData;
    1190             :             }
    1191             :         }
    1192         416 :         else if (buf && H5Tequal(H5T_NATIVE_ULONG, hAttrNativeType) > 0)
    1193             :         {
    1194           0 :             for (hsize_t i = 0; i < nAttrElmts; i++)
    1195             :             {
    1196           0 :                 snprintf(szData, nDataLen, "%lu",
    1197           0 :                          static_cast<unsigned long *>(buf)[i]);
    1198           0 :                 if (psContext->m_osValue.size() > MAX_METADATA_LEN)
    1199             :                 {
    1200           0 :                     CPLError(CE_Warning, CPLE_OutOfMemory,
    1201             :                              "Header data too long. Truncated");
    1202           0 :                     break;
    1203             :                 }
    1204           0 :                 if (i > 0)
    1205           0 :                     psContext->m_osValue += ' ';
    1206           0 :                 psContext->m_osValue += szData;
    1207             :             }
    1208             :         }
    1209             : #ifdef HDF5_HAVE_FLOAT16
    1210             :         else if (buf && H5Tequal(H5T_NATIVE_FLOAT16, hAttrNativeType) > 0)
    1211             :         {
    1212             :             for (hsize_t i = 0; i < nAttrElmts; i++)
    1213             :             {
    1214             :                 const uint16_t nVal16 = static_cast<uint16_t *>(buf)[i];
    1215             :                 const uint32_t nVal32 = CPLHalfToFloat(nVal16);
    1216             :                 float fVal;
    1217             :                 memcpy(&fVal, &nVal32, sizeof(fVal));
    1218             :                 CPLsnprintf(szData, nDataLen, "%.8g", fVal);
    1219             :                 if (psContext->m_osValue.size() > MAX_METADATA_LEN)
    1220             :                 {
    1221             :                     CPLError(CE_Warning, CPLE_OutOfMemory,
    1222             :                              "Header data too long. Truncated");
    1223             :                     break;
    1224             :                 }
    1225             :                 if (i > 0)
    1226             :                     psContext->m_osValue += ' ';
    1227             :                 psContext->m_osValue += szData;
    1228             :             }
    1229             :         }
    1230             : #endif
    1231         416 :         else if (buf && H5Tequal(H5T_NATIVE_FLOAT, hAttrNativeType) > 0)
    1232             :         {
    1233         283 :             for (hsize_t i = 0; i < nAttrElmts; i++)
    1234             :             {
    1235         144 :                 CPLsnprintf(szData, nDataLen, "%.8g",
    1236         144 :                             static_cast<float *>(buf)[i]);
    1237         144 :                 if (psContext->m_osValue.size() > MAX_METADATA_LEN)
    1238             :                 {
    1239           0 :                     CPLError(CE_Warning, CPLE_OutOfMemory,
    1240             :                              "Header data too long. Truncated");
    1241           0 :                     break;
    1242             :                 }
    1243         144 :                 if (i > 0)
    1244           5 :                     psContext->m_osValue += ' ';
    1245         144 :                 psContext->m_osValue += szData;
    1246             :             }
    1247             :         }
    1248         277 :         else if (buf && H5Tequal(H5T_NATIVE_DOUBLE, hAttrNativeType) > 0)
    1249             :         {
    1250         602 :             for (hsize_t i = 0; i < nAttrElmts; i++)
    1251             :             {
    1252         380 :                 CPLsnprintf(szData, nDataLen, "%.15g",
    1253         380 :                             static_cast<double *>(buf)[i]);
    1254         380 :                 if (psContext->m_osValue.size() > MAX_METADATA_LEN)
    1255             :                 {
    1256           0 :                     CPLError(CE_Warning, CPLE_OutOfMemory,
    1257             :                              "Header data too long. Truncated");
    1258           0 :                     break;
    1259             :                 }
    1260         380 :                 if (i > 0)
    1261         158 :                     psContext->m_osValue += ' ';
    1262         380 :                 psContext->m_osValue += szData;
    1263             :             }
    1264             :         }
    1265         788 :         CPLFree(buf);
    1266             :     }
    1267        1413 :     H5Sclose(hAttrSpace);
    1268        1413 :     H5Tclose(hAttrNativeType);
    1269        1413 :     H5Tclose(hAttrTypeID);
    1270        1413 :     H5Aclose(hAttrID);
    1271        1413 :     psContext->m_aosMetadata.SetNameValue(osKey.c_str(),
    1272        1413 :                                           psContext->m_osValue.c_str());
    1273             : 
    1274        1413 :     return 0;
    1275             : }
    1276             : 
    1277             : /************************************************************************/
    1278             : /*                           CreateMetadata()                           */
    1279             : /************************************************************************/
    1280         709 : CPLErr HDF5Dataset::CreateMetadata(hid_t hHDF5, HDF5GroupObjects *poH5Object,
    1281             :                                    int nType, bool bPrefixWithDatasetName,
    1282             :                                    CPLStringList &aosMetadata)
    1283             : {
    1284             : 
    1285         709 :     if (!poH5Object->pszPath)
    1286          21 :         return CE_None;
    1287             : 
    1288         688 :     if (EQUAL(poH5Object->pszPath, ""))
    1289           0 :         return CE_None;
    1290             : 
    1291         688 :     const int nbAttrs = poH5Object->nbAttrs;
    1292             : 
    1293         688 :     HDF5DatasetCreateMetadataContext sContext(aosMetadata);
    1294             : 
    1295         688 :     if (bPrefixWithDatasetName)
    1296             :     {
    1297             :         // Convert "/" into "_" for the path component
    1298         617 :         const char *pszPath = poH5Object->pszUnderscorePath;
    1299         617 :         if (pszPath != nullptr && strlen(pszPath) > 0)
    1300             :         {
    1301             :             const CPLStringList aosTokens(
    1302        1234 :                 CSLTokenizeString2(pszPath, "/", CSLT_HONOURSTRINGS));
    1303        1588 :             for (int i = 0; i < aosTokens.size(); ++i)
    1304             :             {
    1305         971 :                 if (i != 0)
    1306         479 :                     sContext.m_osKey += '_';
    1307         971 :                 sContext.m_osKey += aosTokens[i];
    1308             :             }
    1309             :         }
    1310             :     }
    1311             : 
    1312         688 :     switch (nType)
    1313             :     {
    1314         415 :         case H5G_GROUP:
    1315         415 :             if (nbAttrs > 0)
    1316             :             {
    1317             :                 // Identifier of group.
    1318         109 :                 const hid_t l_hGroupID = H5Gopen(hHDF5, poH5Object->pszPath);
    1319         109 :                 H5Aiterate(l_hGroupID, nullptr, HDF5AttrIterate, &sContext);
    1320         109 :                 H5Gclose(l_hGroupID);
    1321             :             }
    1322         415 :             break;
    1323         273 :         case H5G_DATASET:
    1324         273 :             if (nbAttrs > 0)
    1325             :             {
    1326         194 :                 const hid_t hDatasetID = H5Dopen(hHDF5, poH5Object->pszPath);
    1327         194 :                 H5Aiterate(hDatasetID, nullptr, HDF5AttrIterate, &sContext);
    1328         194 :                 H5Dclose(hDatasetID);
    1329             :             }
    1330         273 :             break;
    1331             : 
    1332           0 :         default:
    1333           0 :             break;
    1334             :     }
    1335             : 
    1336         688 :     return CE_None;
    1337             : }
    1338             : 
    1339             : /************************************************************************/
    1340             : /*                       HDF5FindDatasetObjectsbyPath()                 */
    1341             : /*      Find object by name                                             */
    1342             : /************************************************************************/
    1343             : HDF5GroupObjects *
    1344         381 : HDF5Dataset::HDF5FindDatasetObjectsbyPath(HDF5GroupObjects *poH5Objects,
    1345             :                                           const char *pszDatasetPath)
    1346             : {
    1347         381 :     if (poH5Objects->nType == H5G_DATASET &&
    1348         149 :         EQUAL(poH5Objects->pszUnderscorePath, pszDatasetPath))
    1349             :     {
    1350             : 
    1351             : #ifdef DEBUG_VERBOSE
    1352             :         printf("found it! %p\n", poH5Objects); /*ok*/
    1353             : #endif
    1354          76 :         return poH5Objects;
    1355             :     }
    1356             : 
    1357         305 :     HDF5Dataset *const poDS = this;
    1358             : 
    1359         305 :     if (poH5Objects->nbObjs > 0)
    1360             :     {
    1361         336 :         for (unsigned int i = 0; i < poH5Objects->nbObjs; i++)
    1362             :         {
    1363             :             HDF5GroupObjects *poObjectsFound =
    1364         305 :                 poDS->HDF5FindDatasetObjectsbyPath(poH5Objects->poHchild + i,
    1365             :                                                    pszDatasetPath);
    1366             :             // Is this our dataset?
    1367         305 :             if (poObjectsFound != nullptr)
    1368         173 :                 return poObjectsFound;
    1369             :         }
    1370             :     }
    1371             :     // Dataset has not been found.
    1372         132 :     return nullptr;
    1373             : }
    1374             : 
    1375             : /************************************************************************/
    1376             : /*                       HDF5FindDatasetObjects()                       */
    1377             : /*      Find object by name                                             */
    1378             : /************************************************************************/
    1379             : HDF5GroupObjects *
    1380          32 : HDF5Dataset::HDF5FindDatasetObjects(HDF5GroupObjects *poH5Objects,
    1381             :                                     const char *pszDatasetName)
    1382             : {
    1383          32 :     if (poH5Objects->nType == H5G_DATASET &&
    1384          23 :         EQUAL(poH5Objects->pszName, pszDatasetName))
    1385             :     {
    1386             : 
    1387             : #ifdef DEBUG_VERBOSE
    1388             :         printf("found it! %p\n", poH5Objects); /*ok*/
    1389             : #endif
    1390           0 :         return poH5Objects;
    1391             :     }
    1392             : 
    1393          32 :     HDF5Dataset *poDS = this;
    1394             : 
    1395          32 :     if (poH5Objects->nbObjs > 0)
    1396             :     {
    1397          32 :         for (unsigned int i = 0; i < poH5Objects->nbObjs; i++)
    1398             :         {
    1399          48 :             HDF5GroupObjects *poObjectsFound = poDS->HDF5FindDatasetObjects(
    1400          24 :                 poH5Objects->poHchild + i, pszDatasetName);
    1401             :             // Is this our dataset?
    1402          24 :             if (poObjectsFound != nullptr)
    1403           0 :                 return poObjectsFound;
    1404             :         }
    1405             :     }
    1406             : 
    1407             :     // Dataset has not been found.
    1408          32 :     return nullptr;
    1409             : }
    1410             : 
    1411             : /************************************************************************/
    1412             : /*                        HDF5ListGroupObjects()                        */
    1413             : /*                                                                      */
    1414             : /*      List all objects in HDF5                                        */
    1415             : /************************************************************************/
    1416         886 : CPLErr HDF5Dataset::HDF5ListGroupObjects(HDF5GroupObjects *poRootGroup,
    1417             :                                          int bSUBDATASET)
    1418             : {
    1419         886 :     HDF5Dataset *poDS = this;
    1420             : 
    1421         886 :     if (poRootGroup->nbObjs > 0)
    1422        1113 :         for (hsize_t i = 0; i < poRootGroup->nbObjs; i++)
    1423             :         {
    1424         747 :             poDS->HDF5ListGroupObjects(poRootGroup->poHchild + i, bSUBDATASET);
    1425             :         }
    1426             : 
    1427         886 :     if (poRootGroup->nType == H5G_GROUP)
    1428             :     {
    1429         436 :         CreateMetadata(m_hHDF5, poRootGroup, H5G_GROUP, true, m_aosMetadata);
    1430             :     }
    1431             : 
    1432             :     // Create Sub dataset list.
    1433             : 
    1434        1114 :     if (poRootGroup->nType == H5G_DATASET && bSUBDATASET &&
    1435         228 :         poDS->GetDataType(poRootGroup->native) == GDT_Unknown)
    1436             :     {
    1437          26 :         if (!EQUAL(poRootGroup->pszUnderscorePath,
    1438             :                    "//HDFEOS_INFORMATION/StructMetadata.0"))
    1439             :         {
    1440          19 :             CPLDebug("HDF5", "Skipping unsupported %s of type %s",
    1441             :                      poRootGroup->pszUnderscorePath,
    1442             :                      poDS->GetDataTypeName(poRootGroup->native));
    1443             :         }
    1444             :     }
    1445         860 :     else if (poRootGroup->nType == H5G_DATASET && bSUBDATASET)
    1446             :     {
    1447         202 :         CreateMetadata(m_hHDF5, poRootGroup, H5G_DATASET, true, m_aosMetadata);
    1448             : 
    1449         571 :         for (int i = 0; i < poRootGroup->nRank; ++i)
    1450             :         {
    1451         742 :             if (poRootGroup->paDims[i] >
    1452         371 :                 static_cast<hsize_t>(std::numeric_limits<int>::max()))
    1453             :             {
    1454           2 :                 CPLDebug("HDF5",
    1455             :                          "Not reporting %s as subdataset as at least one of "
    1456             :                          "its dimension size exceeds INT_MAX!",
    1457             :                          poRootGroup->pszUnderscorePath);
    1458          41 :                 return CE_None;
    1459             :             }
    1460             :         }
    1461             : 
    1462         200 :         CPLString osStr;
    1463         200 :         switch (poRootGroup->nRank)
    1464             :         {
    1465         151 :             case 2:
    1466         151 :                 osStr.Printf("%dx%d", static_cast<int>(poRootGroup->paDims[0]),
    1467         151 :                              static_cast<int>(poRootGroup->paDims[1]));
    1468         151 :                 break;
    1469          10 :             case 3:
    1470             :                 osStr.Printf("%dx%dx%d",
    1471          10 :                              static_cast<int>(poRootGroup->paDims[0]),
    1472          10 :                              static_cast<int>(poRootGroup->paDims[1]),
    1473          10 :                              static_cast<int>(poRootGroup->paDims[2]));
    1474          10 :                 break;
    1475          39 :             default:
    1476          39 :                 return CE_None;
    1477             :         }
    1478             : 
    1479         322 :         HDF5EOSParser::GridMetadata oGridMetadata;
    1480         322 :         HDF5EOSParser::SwathFieldMetadata oSwathFieldMetadata;
    1481         334 :         if (m_oHDFEOSParser.GetDataModel() == HDF5EOSParser::DataModel::GRID &&
    1482         167 :             m_oHDFEOSParser.GetGridMetadata(poRootGroup->pszUnderscorePath,
    1483         167 :                                             oGridMetadata) &&
    1484           0 :             static_cast<int>(oGridMetadata.aoDimensions.size()) ==
    1485           0 :                 poRootGroup->nRank)
    1486             :         {
    1487           0 :             int nXDimSize = 0;
    1488           0 :             int nYDimSize = 0;
    1489           0 :             int nOtherDimSize = 0;
    1490           0 :             std::string osOtherDimName;
    1491           0 :             for (const auto &oDim : oGridMetadata.aoDimensions)
    1492             :             {
    1493           0 :                 if (oDim.osName == "XDim")
    1494           0 :                     nXDimSize = oDim.nSize;
    1495           0 :                 else if (oDim.osName == "YDim")
    1496           0 :                     nYDimSize = oDim.nSize;
    1497             :                 else
    1498             :                 {
    1499           0 :                     osOtherDimName = oDim.osName;
    1500           0 :                     nOtherDimSize = oDim.nSize;
    1501             :                 }
    1502             :             }
    1503           0 :             switch (poRootGroup->nRank)
    1504             :             {
    1505           0 :                 case 2:
    1506           0 :                     osStr.Printf("(y=%d)x(x=%d)", nYDimSize, nXDimSize);
    1507           0 :                     break;
    1508           0 :                 case 3:
    1509             :                 {
    1510           0 :                     if (osOtherDimName == oGridMetadata.aoDimensions[0].osName)
    1511             :                         osStr.Printf("(%s=%d)x(y=%d)x(x=%d)",
    1512             :                                      osOtherDimName.c_str(), nOtherDimSize,
    1513           0 :                                      nYDimSize, nXDimSize);
    1514             :                     else
    1515             :                         osStr.Printf("(y=%d)x(x=%d)x(%s=%d)", nYDimSize,
    1516             :                                      nXDimSize, osOtherDimName.c_str(),
    1517           0 :                                      nOtherDimSize);
    1518           0 :                     break;
    1519             :                 }
    1520           0 :                 default:
    1521           0 :                     break;
    1522             :             }
    1523             :         }
    1524         161 :         else if (m_oHDFEOSParser.GetDataModel() ==
    1525           3 :                      HDF5EOSParser::DataModel::SWATH &&
    1526           3 :                  m_oHDFEOSParser.GetSwathFieldMetadata(
    1527           3 :                      poRootGroup->pszUnderscorePath, oSwathFieldMetadata) &&
    1528           3 :                  static_cast<int>(oSwathFieldMetadata.aoDimensions.size()) ==
    1529           3 :                      poRootGroup->nRank &&
    1530         167 :                  oSwathFieldMetadata.iXDim >= 0 &&
    1531           3 :                  oSwathFieldMetadata.iYDim >= 0)
    1532             :         {
    1533             :             const std::string &osXDimName =
    1534           3 :                 oSwathFieldMetadata.aoDimensions[oSwathFieldMetadata.iXDim]
    1535           3 :                     .osName;
    1536             :             const int nXDimSize =
    1537           3 :                 oSwathFieldMetadata.aoDimensions[oSwathFieldMetadata.iXDim]
    1538           3 :                     .nSize;
    1539             :             const std::string &osYDimName =
    1540           3 :                 oSwathFieldMetadata.aoDimensions[oSwathFieldMetadata.iYDim]
    1541           3 :                     .osName;
    1542             :             const int nYDimSize =
    1543           3 :                 oSwathFieldMetadata.aoDimensions[oSwathFieldMetadata.iYDim]
    1544           3 :                     .nSize;
    1545           3 :             switch (poRootGroup->nRank)
    1546             :             {
    1547           2 :                 case 2:
    1548             :                     osStr.Printf("(%s=%d)x(%s=%d)", osYDimName.c_str(),
    1549           2 :                                  nYDimSize, osXDimName.c_str(), nXDimSize);
    1550           2 :                     break;
    1551           1 :                 case 3:
    1552             :                 {
    1553             :                     const std::string &osOtherDimName =
    1554             :                         oSwathFieldMetadata
    1555           1 :                             .aoDimensions[oSwathFieldMetadata.iOtherDim]
    1556           1 :                             .osName;
    1557             :                     const int nOtherDimSize =
    1558             :                         oSwathFieldMetadata
    1559           1 :                             .aoDimensions[oSwathFieldMetadata.iOtherDim]
    1560           1 :                             .nSize;
    1561           1 :                     if (oSwathFieldMetadata.iOtherDim == 0)
    1562             :                     {
    1563             :                         osStr.Printf("(%s=%d)x(%s=%d)x(%s=%d)",
    1564             :                                      osOtherDimName.c_str(), nOtherDimSize,
    1565             :                                      osYDimName.c_str(), nYDimSize,
    1566           1 :                                      osXDimName.c_str(), nXDimSize);
    1567             :                     }
    1568             :                     else
    1569             :                     {
    1570             :                         osStr.Printf("(%s=%d)x(%s=%d)x(%s=%d)",
    1571             :                                      osYDimName.c_str(), nYDimSize,
    1572             :                                      osXDimName.c_str(), nXDimSize,
    1573           0 :                                      osOtherDimName.c_str(), nOtherDimSize);
    1574             :                     }
    1575           1 :                     break;
    1576             :                 }
    1577           0 :                 default:
    1578           0 :                     break;
    1579             :             }
    1580             :         }
    1581             : 
    1582         161 :         const std::string osDim = osStr;
    1583             : 
    1584         161 :         osStr.Printf("SUBDATASET_%d_NAME", ++(poDS->nSubDataCount));
    1585             : 
    1586         161 :         poDS->papszSubDatasets =
    1587         161 :             CSLSetNameValue(poDS->papszSubDatasets, osStr.c_str(),
    1588         161 :                             CPLSPrintf("HDF5:\"%s\":%s", poDS->GetDescription(),
    1589             :                                        poRootGroup->pszUnderscorePath));
    1590             : 
    1591         161 :         osStr.Printf("SUBDATASET_%d_DESC", poDS->nSubDataCount);
    1592             : 
    1593         161 :         poDS->papszSubDatasets = CSLSetNameValue(
    1594             :             poDS->papszSubDatasets, osStr.c_str(),
    1595             :             CPLSPrintf("[%s] %s (%s)", osDim.c_str(),
    1596             :                        poRootGroup->pszUnderscorePath,
    1597             :                        poDS->GetDataTypeName(poRootGroup->native)));
    1598             :     }
    1599             : 
    1600         845 :     return CE_None;
    1601             : }
    1602             : 
    1603             : /************************************************************************/
    1604             : /*                        ReadGlobalAttributes()                        */
    1605             : /************************************************************************/
    1606         139 : CPLErr HDF5Dataset::ReadGlobalAttributes(int bSUBDATASET)
    1607             : {
    1608             :     HDF5GroupObjects *poRootGroup =
    1609         139 :         static_cast<HDF5GroupObjects *>(CPLCalloc(sizeof(HDF5GroupObjects), 1));
    1610             : 
    1611         139 :     poH5RootGroup = poRootGroup;
    1612         139 :     poRootGroup->pszName = CPLStrdup("/");
    1613         139 :     poRootGroup->nType = H5G_GROUP;
    1614         139 :     poRootGroup->poHparent = nullptr;
    1615         139 :     poRootGroup->pszPath = nullptr;
    1616         139 :     poRootGroup->pszUnderscorePath = nullptr;
    1617             : 
    1618         139 :     if (m_hHDF5 < 0)
    1619             :     {
    1620           0 :         CPLError(CE_Failure, CPLE_AppDefined, "hHDF5 < 0!");
    1621           0 :         return CE_None;
    1622             :     }
    1623             : 
    1624         139 :     H5G_stat_t oStatbuf = {{0, 0}, {0, 0}, 0, H5G_UNKNOWN, 0, 0, {0, 0, 0, 0}};
    1625             : 
    1626         139 :     if (H5Gget_objinfo(m_hHDF5, "/", FALSE, &oStatbuf) < 0)
    1627           0 :         return CE_Failure;
    1628         139 :     poRootGroup->objno[0] = oStatbuf.objno[0];
    1629         139 :     poRootGroup->objno[1] = oStatbuf.objno[1];
    1630             : 
    1631         139 :     if (hGroupID > 0)
    1632         139 :         H5Gclose(hGroupID);
    1633         139 :     hGroupID = H5Gopen(m_hHDF5, "/");
    1634         139 :     if (hGroupID < 0)
    1635             :     {
    1636           0 :         CPLError(CE_Failure, CPLE_AppDefined, "hGroupId <0!");
    1637           0 :         return CE_None;
    1638             :     }
    1639             : 
    1640         139 :     poRootGroup->nbAttrs = H5Aget_num_attrs(hGroupID);
    1641             : 
    1642         139 :     H5Gget_num_objs(hGroupID, &(poRootGroup->nbObjs));
    1643             : 
    1644         139 :     if (poRootGroup->nbObjs > 0)
    1645             :     {
    1646         125 :         poRootGroup->poHchild = static_cast<HDF5GroupObjects *>(
    1647         125 :             CPLCalloc(static_cast<size_t>(poRootGroup->nbObjs),
    1648             :                       sizeof(HDF5GroupObjects)));
    1649         125 :         H5Giterate(hGroupID, "/", nullptr, HDF5CreateGroupObjs, poRootGroup);
    1650             :     }
    1651             :     else
    1652             :     {
    1653          14 :         poRootGroup->poHchild = nullptr;
    1654             :     }
    1655             : 
    1656         139 :     HDF5ListGroupObjects(poRootGroup, bSUBDATASET);
    1657         139 :     return CE_None;
    1658             : }
    1659             : 
    1660             : /**
    1661             :  * Reads an array of double attributes from the HDF5 metadata.
    1662             :  * It reads the attributes directly on its binary form directly,
    1663             :  * thus avoiding string conversions.
    1664             :  *
    1665             :  * Important: It allocates the memory for the attributes internally,
    1666             :  * so the caller must free the returned array after using it.
    1667             :  * @param pszAttrFullPath Name of the attribute to be read.
    1668             :  *        the attribute name must be the form:
    1669             :  *            root attribute name
    1670             :  *            SUBDATASET/subdataset attribute name
    1671             :  * @param pdfValues pointer which will store the array of doubles read.
    1672             :  * @param nLen it stores the length of the array read. If NULL it doesn't
    1673             :  *        inform the length of the array.
    1674             :  * @return CPLErr CE_None in case of success, CE_Failure in case of failure
    1675             :  */
    1676          10 : CPLErr HDF5Dataset::HDF5ReadDoubleAttr(const char *pszAttrFullPath,
    1677             :                                        double **pdfValues, int *nLen)
    1678             : {
    1679          20 :     CPLString osAttrFullPath(pszAttrFullPath);
    1680             : 
    1681             :     // Search for the last "/" in order to get the path to the attribute.
    1682          10 :     const size_t nSlashPos = osAttrFullPath.find_last_of("/");
    1683             : 
    1684          20 :     CPLString osObjName;
    1685          10 :     CPLString osAttrName;
    1686             : 
    1687             :     // If objects name have been found.
    1688          10 :     if (nSlashPos != CPLString::npos)
    1689             :     {
    1690             :         // Split Object name (dataset, group).
    1691           7 :         osObjName = osAttrFullPath.substr(0, nSlashPos);
    1692             :         // Split attribute name.
    1693           7 :         osAttrName = osAttrFullPath.substr(nSlashPos + 1);
    1694             :     }
    1695             :     else
    1696             :     {
    1697             :         // By default the group is root, and
    1698             :         // the attribute is the full path.
    1699           3 :         osObjName = "/";
    1700           3 :         osAttrName = pszAttrFullPath;
    1701             :     }
    1702             : 
    1703          10 :     const hid_t hObjAttrID = H5Oopen(m_hHDF5, osObjName.c_str(), H5P_DEFAULT);
    1704             : 
    1705          10 :     CPLErr retVal = CE_Failure;
    1706             : 
    1707          10 :     if (hObjAttrID < 0)
    1708             :     {
    1709           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "Object %s could not be opened",
    1710             :                  pszAttrFullPath);
    1711           0 :         retVal = CE_Failure;
    1712             :     }
    1713             :     else
    1714             :     {
    1715             :         // Open attribute handler by name, from the object handler opened
    1716             :         // earlier.
    1717          10 :         const hid_t hAttrID = H5Aopen_name(hObjAttrID, osAttrName.c_str());
    1718             : 
    1719             :         // Check for errors opening the attribute.
    1720          10 :         if (hAttrID < 0)
    1721             :         {
    1722           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
    1723             :                      "Attribute %s could not be opened", pszAttrFullPath);
    1724           0 :             retVal = CE_Failure;
    1725             :         }
    1726             :         else
    1727             :         {
    1728          10 :             const hid_t hAttrTypeID = H5Aget_type(hAttrID);
    1729             :             const hid_t hAttrNativeType =
    1730          10 :                 H5Tget_native_type(hAttrTypeID, H5T_DIR_DEFAULT);
    1731          10 :             const hid_t hAttrSpace = H5Aget_space(hAttrID);
    1732          10 :             hsize_t nSize[64] = {};
    1733             :             const unsigned int nAttrDims =
    1734          10 :                 H5Sget_simple_extent_dims(hAttrSpace, nSize, nullptr);
    1735             : 
    1736          10 :             if (!H5Tequal(H5T_NATIVE_DOUBLE, hAttrNativeType))
    1737             :             {
    1738           0 :                 CPLError(CE_Failure, CPLE_OpenFailed,
    1739             :                          "Attribute %s is not of type double", pszAttrFullPath);
    1740           0 :                 retVal = CE_Failure;
    1741             :             }
    1742             :             else
    1743             :             {
    1744             :                 // Get the amount of elements.
    1745          10 :                 int nAttrElmts = 1;
    1746          17 :                 for (hsize_t i = 0; i < nAttrDims; i++)
    1747             :                 {
    1748          14 :                     if (nSize[i] >
    1749           7 :                         static_cast<hsize_t>(std::numeric_limits<int>::max() /
    1750             :                                              nAttrElmts))
    1751             :                     {
    1752           0 :                         nAttrElmts = 0;
    1753           0 :                         break;
    1754             :                     }
    1755             :                     // For multidimensional attributes
    1756           7 :                     nAttrElmts *= static_cast<int>(nSize[i]);
    1757             :                 }
    1758             : 
    1759          10 :                 if (nLen != nullptr)
    1760           0 :                     *nLen = nAttrElmts;
    1761             : 
    1762          10 :                 *pdfValues = static_cast<double *>(
    1763          10 :                     nAttrElmts ? VSI_MALLOC2_VERBOSE(nAttrElmts, sizeof(double))
    1764             :                                : nullptr);
    1765             : 
    1766             :                 // Read the attribute contents
    1767          20 :                 if (nAttrElmts == 0 ||
    1768          10 :                     H5Aread(hAttrID, hAttrNativeType, *pdfValues) < 0)
    1769             :                 {
    1770           0 :                     CPLError(CE_Failure, CPLE_OpenFailed,
    1771             :                              "Attribute %s could not be opened",
    1772             :                              pszAttrFullPath);
    1773           0 :                     retVal = CE_Failure;
    1774             :                 }
    1775             :                 else
    1776             :                 {
    1777          10 :                     retVal = CE_None;
    1778             :                 }
    1779             :             }
    1780             : 
    1781          10 :             H5Tclose(hAttrNativeType);
    1782          10 :             H5Tclose(hAttrTypeID);
    1783          10 :             H5Sclose(hAttrSpace);
    1784          10 :             H5Aclose(hAttrID);
    1785             :         }
    1786          10 :         H5Oclose(hObjAttrID);
    1787             :     }
    1788             : 
    1789          20 :     return retVal;
    1790             : }

Generated by: LCOV version 1.14