LCOV - code coverage report
Current view: top level - frmts/hdf5 - hdf5multidim.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1340 1494 89.7 %
Date: 2025-05-31 00:00:17 Functions: 63 67 94.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  HDF5 read Driver
       4             :  * Author:   Even Rouault <even.rouault at spatialys.com>
       5             :  *
       6             :  ******************************************************************************
       7             :  * Copyright (c) 2019, Even Rouault <even.rouault at spatialys.com>
       8             :  *
       9             :  * SPDX-License-Identifier: MIT
      10             :  ****************************************************************************/
      11             : 
      12             : #include "hdf5dataset.h"
      13             : #include "hdf5eosparser.h"
      14             : #include "s100.h"
      15             : 
      16             : #include "cpl_float.h"
      17             : 
      18             : #include <algorithm>
      19             : #include <set>
      20             : #include <utility>
      21             : 
      22             : namespace GDAL
      23             : {
      24             : 
      25             : /************************************************************************/
      26             : /*                               HDF5Group                              */
      27             : /************************************************************************/
      28             : 
      29             : class HDF5Group final : public GDALGroup
      30             : {
      31             :     std::shared_ptr<HDF5SharedResources> m_poShared;
      32             :     hid_t m_hGroup;
      33             :     std::set<std::pair<unsigned long, unsigned long>> m_oSetParentIds{};
      34             :     const bool m_bIsEOSGridGroup;
      35             :     const bool m_bIsEOSSwathGroup;
      36             :     mutable std::shared_ptr<GDALMDArray> m_poXIndexingArray{};
      37             :     mutable std::shared_ptr<GDALMDArray> m_poYIndexingArray{};
      38             :     mutable std::vector<std::string> m_osListSubGroups{};
      39             :     mutable std::vector<std::string> m_osListArrays{};
      40             :     mutable std::vector<std::shared_ptr<GDALAttribute>> m_oListAttributes{};
      41             :     mutable bool m_bShowAllAttributes = false;
      42             :     mutable bool m_bGotDims = false;
      43             :     mutable std::vector<std::shared_ptr<GDALDimension>> m_cachedDims{};
      44             : 
      45             :     static herr_t GetGroupNamesCallback(hid_t hGroup, const char *pszObjName,
      46             :                                         void *);
      47             : 
      48             :     static herr_t GetArrayNamesCallback(hid_t hGroup, const char *pszObjName,
      49             :                                         void *);
      50             : 
      51             :     static herr_t GetAttributesCallback(hid_t hGroup, const char *pszObjName,
      52             :                                         void *);
      53             : 
      54             :   protected:
      55         633 :     HDF5Group(
      56             :         const std::string &osParentName, const std::string &osName,
      57             :         const std::shared_ptr<HDF5SharedResources> &poShared,
      58             :         const std::set<std::pair<unsigned long, unsigned long>> &oSetParentIds,
      59             :         hid_t hGroup, unsigned long objIds[2])
      60         633 :         : GDALGroup(osParentName, osName), m_poShared(poShared),
      61             :           m_hGroup(hGroup), m_oSetParentIds(oSetParentIds),
      62         633 :           m_bIsEOSGridGroup(osParentName == "/HDFEOS/GRIDS"),
      63        1266 :           m_bIsEOSSwathGroup(osParentName == "/HDFEOS/SWATHS")
      64             :     {
      65         633 :         m_oSetParentIds.insert(std::pair(objIds[0], objIds[1]));
      66             : 
      67             :         // Force registration of EOS dimensions
      68         633 :         if (m_bIsEOSGridGroup || m_bIsEOSSwathGroup)
      69             :         {
      70           5 :             HDF5Group::GetDimensions();
      71             :         }
      72         633 :     }
      73             : 
      74             :   public:
      75         633 :     static std::shared_ptr<HDF5Group> Create(
      76             :         const std::string &osParentName, const std::string &osName,
      77             :         const std::shared_ptr<HDF5SharedResources> &poShared,
      78             :         const std::set<std::pair<unsigned long, unsigned long>> &oSetParentIds,
      79             :         hid_t hGroup, unsigned long objIds[2])
      80             :     {
      81             :         auto poGroup = std::shared_ptr<HDF5Group>(new HDF5Group(
      82         633 :             osParentName, osName, poShared, oSetParentIds, hGroup, objIds));
      83         633 :         poGroup->SetSelf(poGroup);
      84         633 :         return poGroup;
      85             :     }
      86             : 
      87        1266 :     ~HDF5Group()
      88         633 :     {
      89         633 :         H5Gclose(m_hGroup);
      90        1266 :     }
      91             : 
      92         149 :     hid_t GetID() const
      93             :     {
      94         149 :         return m_hGroup;
      95             :     }
      96             : 
      97             :     std::vector<std::shared_ptr<GDALDimension>>
      98             :     GetDimensions(CSLConstList papszOptions = nullptr) const override;
      99             : 
     100             :     std::vector<std::string>
     101             :     GetGroupNames(CSLConstList papszOptions) const override;
     102             :     std::shared_ptr<GDALGroup> OpenGroup(const std::string &osName,
     103             :                                          CSLConstList) const override;
     104             : 
     105             :     std::vector<std::string>
     106             :     GetMDArrayNames(CSLConstList papszOptions) const override;
     107             :     std::shared_ptr<GDALMDArray>
     108             :     OpenMDArray(const std::string &osName,
     109             :                 CSLConstList papszOptions) const override;
     110             : 
     111             :     std::vector<std::shared_ptr<GDALAttribute>>
     112             :     GetAttributes(CSLConstList papszOptions = nullptr) const override;
     113             : };
     114             : 
     115             : /************************************************************************/
     116             : /*                             HDF5Dimension                            */
     117             : /************************************************************************/
     118             : 
     119             : class HDF5Dimension final : public GDALDimension
     120             : {
     121             :     std::string m_osGroupFullname;
     122             :     std::shared_ptr<HDF5SharedResources> m_poShared;
     123             : 
     124             :   public:
     125          32 :     HDF5Dimension(const std::string &osParentName, const std::string &osName,
     126             :                   const std::string &osType, const std::string &osDirection,
     127             :                   GUInt64 nSize,
     128             :                   const std::shared_ptr<HDF5SharedResources> &poShared)
     129          32 :         : GDALDimension(osParentName, osName, osType, osDirection, nSize),
     130          32 :           m_osGroupFullname(osParentName), m_poShared(poShared)
     131             :     {
     132          32 :     }
     133             : 
     134             :     std::shared_ptr<GDALMDArray> GetIndexingVariable() const override;
     135             : };
     136             : 
     137             : /************************************************************************/
     138             : /*                           BuildDataType()                            */
     139             : /************************************************************************/
     140             : 
     141             : static GDALExtendedDataType
     142       16056 : BuildDataType(hid_t hDataType, bool &bHasString, bool &bNonNativeDataType,
     143             :               const std::vector<std::pair<std::string, hid_t>> &oTypes)
     144             : {
     145       16056 :     const auto klass = H5Tget_class(hDataType);
     146       16056 :     GDALDataType eDT = ::HDF5Dataset::GetDataType(hDataType);
     147       16056 :     if (eDT != GDT_Unknown)
     148             :     {
     149             : #ifdef HDF5_HAVE_FLOAT16
     150             :         if (H5Tequal(hDataType, H5T_NATIVE_FLOAT16) ||
     151             :             HDF5Dataset::IsNativeCFloat16(hDataType))
     152             :         {
     153             :             bNonNativeDataType = true;
     154             :         }
     155             : #endif
     156       11814 :         return GDALExtendedDataType::Create(eDT);
     157             :     }
     158        4242 :     else if (klass == H5T_STRING)
     159             :     {
     160        3156 :         bHasString = true;
     161        3156 :         return GDALExtendedDataType::CreateString();
     162             :     }
     163        1086 :     else if (klass == H5T_COMPOUND)
     164             :     {
     165         734 :         const unsigned nMembers = H5Tget_nmembers(hDataType);
     166        1468 :         std::vector<std::unique_ptr<GDALEDTComponent>> components;
     167         734 :         size_t nOffset = 0;
     168        3463 :         for (unsigned i = 0; i < nMembers; i++)
     169             :         {
     170        2917 :             char *pszName = H5Tget_member_name(hDataType, i);
     171        2917 :             if (!pszName)
     172         188 :                 return GDALExtendedDataType::Create(GDT_Unknown);
     173        2917 :             CPLString osCompName(pszName);
     174        2917 :             H5free_memory(pszName);
     175        2917 :             const auto hMemberType = H5Tget_member_type(hDataType, i);
     176        2917 :             if (hMemberType < 0)
     177           0 :                 return GDALExtendedDataType::Create(GDT_Unknown);
     178             :             const hid_t hNativeMemberType =
     179        2917 :                 H5Tget_native_type(hMemberType, H5T_DIR_ASCEND);
     180             :             auto memberDT = BuildDataType(hNativeMemberType, bHasString,
     181        2917 :                                           bNonNativeDataType, oTypes);
     182        2917 :             H5Tclose(hNativeMemberType);
     183        2917 :             H5Tclose(hMemberType);
     184        5196 :             if (memberDT.GetClass() == GEDTC_NUMERIC &&
     185        2279 :                 memberDT.GetNumericDataType() == GDT_Unknown)
     186         188 :                 return GDALExtendedDataType::Create(GDT_Unknown);
     187        2729 :             if ((nOffset % memberDT.GetSize()) != 0)
     188         216 :                 nOffset += memberDT.GetSize() - (nOffset % memberDT.GetSize());
     189        2729 :             if (nOffset != H5Tget_member_offset(hDataType, i))
     190         523 :                 bNonNativeDataType = true;
     191        5458 :             components.emplace_back(std::unique_ptr<GDALEDTComponent>(
     192        5458 :                 new GDALEDTComponent(osCompName, nOffset, memberDT)));
     193        2729 :             nOffset += memberDT.GetSize();
     194             :         }
     195        1092 :         if (!components.empty() &&
     196         546 :             (nOffset % components[0]->GetType().GetSize()) != 0)
     197          67 :             nOffset += components[0]->GetType().GetSize() -
     198          67 :                        (nOffset % components[0]->GetType().GetSize());
     199         546 :         if (nOffset != H5Tget_size(hDataType))
     200          81 :             bNonNativeDataType = true;
     201        1092 :         std::string osName("unnamed");
     202         717 :         for (const auto &oPair : oTypes)
     203             :         {
     204             :             const auto hPairNativeType =
     205         209 :                 H5Tget_native_type(oPair.second, H5T_DIR_ASCEND);
     206         209 :             const auto matches = H5Tequal(hPairNativeType, hDataType);
     207         209 :             H5Tclose(hPairNativeType);
     208         209 :             if (matches)
     209             :             {
     210          38 :                 osName = oPair.first;
     211          38 :                 break;
     212             :             }
     213             :         }
     214             :         return GDALExtendedDataType::Create(osName, nOffset,
     215         546 :                                             std::move(components));
     216             :     }
     217         352 :     else if (klass == H5T_ENUM)
     218             :     {
     219          34 :         const auto hParent = H5Tget_super(hDataType);
     220          34 :         const hid_t hNativeParent = H5Tget_native_type(hParent, H5T_DIR_ASCEND);
     221             :         auto ret(BuildDataType(hNativeParent, bHasString, bNonNativeDataType,
     222          68 :                                oTypes));
     223          34 :         H5Tclose(hNativeParent);
     224          34 :         H5Tclose(hParent);
     225          34 :         return ret;
     226             :     }
     227             :     else
     228             :     {
     229         318 :         return GDALExtendedDataType::Create(GDT_Unknown);
     230             :     }
     231             : }
     232             : 
     233             : /************************************************************************/
     234             : /*                    GetDataTypesInGroup()                             */
     235             : /************************************************************************/
     236             : 
     237             : static void
     238         372 : GetDataTypesInGroup(hid_t hHDF5, const std::string &osGroupFullName,
     239             :                     std::vector<std::pair<std::string, hid_t>> &oTypes)
     240             : {
     241             :     struct Callback
     242             :     {
     243        7618 :         static herr_t f(hid_t hGroup, const char *pszObjName, void *user_data)
     244             :         {
     245        7618 :             auto *poTypes =
     246             :                 static_cast<std::vector<std::pair<std::string, hid_t>> *>(
     247             :                     user_data);
     248             :             H5G_stat_t oStatbuf;
     249             : 
     250        7618 :             if (H5Gget_objinfo(hGroup, pszObjName, FALSE, &oStatbuf) < 0)
     251           0 :                 return -1;
     252             : 
     253        7618 :             if (oStatbuf.type == H5G_TYPE)
     254             :             {
     255        1485 :                 poTypes->push_back(
     256        2970 :                     std::pair(pszObjName, H5Topen(hGroup, pszObjName)));
     257             :             }
     258             : 
     259        7618 :             return 0;
     260             :         }
     261             :     };
     262             : 
     263         372 :     H5Giterate(hHDF5, osGroupFullName.c_str(), nullptr, &(Callback::f),
     264             :                &oTypes);
     265         372 : }
     266             : 
     267             : /************************************************************************/
     268             : /*                            HDF5Array                                 */
     269             : /************************************************************************/
     270             : 
     271             : class HDF5Array final : public GDALMDArray
     272             : {
     273             :     std::string m_osGroupFullname;
     274             :     std::shared_ptr<HDF5SharedResources> m_poShared;
     275             :     hid_t m_hArray;
     276             :     hid_t m_hDataSpace;
     277             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
     278             :     GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_Unknown);
     279             :     hid_t m_hNativeDT = H5I_INVALID_HID;
     280             :     mutable std::vector<std::shared_ptr<GDALAttribute>> m_oListAttributes{};
     281             :     mutable bool m_bShowAllAttributes = false;
     282             :     bool m_bHasString = false;
     283             :     bool m_bHasNonNativeDataType = false;
     284             :     mutable bool m_bWarnedNoData = false;
     285             :     mutable std::vector<GByte> m_abyNoData{};
     286             :     mutable std::string m_osUnit{};
     287             :     mutable bool m_bHasDimensionList = false;
     288             :     mutable bool m_bHasDimensionLabels = false;
     289             :     std::shared_ptr<OGRSpatialReference> m_poSRS{};
     290             :     haddr_t m_nOffset;
     291             :     mutable CPLStringList m_aosStructuralInfo{};
     292             : 
     293             :     HDF5Array(const std::string &osParentName, const std::string &osName,
     294             :               const std::shared_ptr<HDF5SharedResources> &poShared,
     295             :               hid_t hArray, const HDF5Group *poGroup,
     296             :               bool bSkipFullDimensionInstantiation);
     297             : 
     298             :     void InstantiateDimensions(const std::string &osParentName,
     299             :                                const HDF5Group *poGroup);
     300             : 
     301             :     bool ReadSlow(const GUInt64 *arrayStartIdx, const size_t *count,
     302             :                   const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
     303             :                   const GDALExtendedDataType &bufferDataType,
     304             :                   void *pDstBuffer) const;
     305             : 
     306             :     static herr_t GetAttributesCallback(hid_t hArray, const char *pszObjName,
     307             :                                         void *);
     308             : 
     309             :   protected:
     310             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
     311             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
     312             :                const GDALExtendedDataType &bufferDataType,
     313             :                void *pDstBuffer) const override;
     314             : 
     315             :   public:
     316             :     ~HDF5Array();
     317             : 
     318             :     static std::shared_ptr<HDF5Array>
     319        1112 :     Create(const std::string &osParentName, const std::string &osName,
     320             :            const std::shared_ptr<HDF5SharedResources> &poShared, hid_t hArray,
     321             :            const HDF5Group *poGroup, bool bSkipFullDimensionInstantiation)
     322             :     {
     323             :         HDF5_GLOBAL_LOCK();
     324             : 
     325             :         auto ar(std::shared_ptr<HDF5Array>(
     326             :             new HDF5Array(osParentName, osName, poShared, hArray, poGroup,
     327        2224 :                           bSkipFullDimensionInstantiation)));
     328        1626 :         if (ar->m_dt.GetClass() == GEDTC_NUMERIC &&
     329         514 :             ar->m_dt.GetNumericDataType() == GDT_Unknown)
     330             :         {
     331           0 :             return nullptr;
     332             :         }
     333        1112 :         ar->SetSelf(ar);
     334        1112 :         return ar;
     335             :     }
     336             : 
     337          47 :     bool IsWritable() const override
     338             :     {
     339          47 :         return !m_poShared->IsReadOnly();
     340             :     }
     341             : 
     342         441 :     const std::string &GetFilename() const override
     343             :     {
     344         441 :         return m_poShared->GetFilename();
     345             :     }
     346             : 
     347             :     const std::vector<std::shared_ptr<GDALDimension>> &
     348        1575 :     GetDimensions() const override
     349             :     {
     350        1575 :         return m_dims;
     351             :     }
     352             : 
     353        1120 :     const GDALExtendedDataType &GetDataType() const override
     354             :     {
     355        1120 :         return m_dt;
     356             :     }
     357             : 
     358             :     std::shared_ptr<GDALAttribute>
     359             :     GetAttribute(const std::string &osName) const override;
     360             : 
     361             :     std::vector<std::shared_ptr<GDALAttribute>>
     362             :     GetAttributes(CSLConstList papszOptions = nullptr) const override;
     363             : 
     364             :     std::vector<GUInt64> GetBlockSize() const override;
     365             : 
     366             :     CSLConstList GetStructuralInfo() const override;
     367             : 
     368          76 :     const void *GetRawNoDataValue() const override
     369             :     {
     370          76 :         return m_abyNoData.empty() ? nullptr : m_abyNoData.data();
     371             :     }
     372             : 
     373          10 :     const std::string &GetUnit() const override
     374             :     {
     375          10 :         return m_osUnit;
     376             :     }
     377             : 
     378             :     haddr_t GetFileOffset() const
     379             :     {
     380             :         return m_nOffset;
     381             :     }
     382             : 
     383          10 :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
     384             :     {
     385          10 :         return m_poSRS;
     386             :     }
     387             : 
     388             :     std::vector<std::shared_ptr<GDALMDArray>>
     389             :     GetCoordinateVariables() const override;
     390             : 
     391          30 :     std::shared_ptr<GDALGroup> GetRootGroup() const override
     392             :     {
     393          30 :         return m_poShared->GetRootGroup();
     394             :     }
     395             : };
     396             : 
     397             : /************************************************************************/
     398             : /*                           HDF5Attribute                              */
     399             : /************************************************************************/
     400             : 
     401             : class HDF5Attribute final : public GDALAttribute
     402             : {
     403             :     std::shared_ptr<HDF5SharedResources> m_poShared;
     404             :     hid_t m_hAttribute;
     405             :     hid_t m_hDataSpace;
     406             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
     407             :     GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_Unknown);
     408             :     hid_t m_hNativeDT = H5I_INVALID_HID;
     409             :     size_t m_nElements = 1;
     410             :     bool m_bHasString = false;
     411             :     bool m_bHasNonNativeDataType = false;
     412             : 
     413       11993 :     HDF5Attribute(const std::string &osGroupFullName,
     414             :                   const std::string &osParentName, const std::string &osName,
     415             :                   const std::shared_ptr<HDF5SharedResources> &poShared,
     416             :                   hid_t hAttribute)
     417       11993 :         : GDALAbstractMDArray(osParentName, osName),
     418             :           GDALAttribute(osParentName, osName), m_poShared(poShared),
     419       11993 :           m_hAttribute(hAttribute), m_hDataSpace(H5Aget_space(hAttribute))
     420             :     {
     421       11993 :         const int nDims = H5Sget_simple_extent_ndims(m_hDataSpace);
     422       23986 :         std::vector<hsize_t> anDimSizes(nDims);
     423       11993 :         if (nDims)
     424             :         {
     425         899 :             H5Sget_simple_extent_dims(m_hDataSpace, &anDimSizes[0], nullptr);
     426        1354 :             for (int i = 0; i < nDims; ++i)
     427             :             {
     428         899 :                 m_nElements *= static_cast<size_t>(anDimSizes[i]);
     429         899 :                 if (nDims == 1 && m_nElements == 1)
     430             :                 {
     431             :                     // Expose 1-dim of size 1 as scalar
     432         444 :                     break;
     433             :                 }
     434         910 :                 m_dims.emplace_back(std::make_shared<GDALDimension>(
     435         910 :                     std::string(), CPLSPrintf("dim%d", i), std::string(),
     436        1365 :                     std::string(), anDimSizes[i]));
     437             :             }
     438             :         }
     439             : 
     440       11993 :         const hid_t hDataType = H5Aget_type(hAttribute);
     441       11993 :         m_hNativeDT = H5Tget_native_type(hDataType, H5T_DIR_ASCEND);
     442       11993 :         H5Tclose(hDataType);
     443             : 
     444       23986 :         std::vector<std::pair<std::string, hid_t>> oTypes;
     445       21131 :         if (!osGroupFullName.empty() &&
     446        9138 :             H5Tget_class(m_hNativeDT) == H5T_COMPOUND)
     447             :         {
     448         179 :             GetDataTypesInGroup(m_poShared->GetHDF5(), osGroupFullName, oTypes);
     449             :         }
     450             : 
     451       23986 :         m_dt = BuildDataType(m_hNativeDT, m_bHasString, m_bHasNonNativeDataType,
     452       11993 :                              oTypes);
     453       13208 :         for (auto &oPair : oTypes)
     454        1215 :             H5Tclose(oPair.second);
     455       21520 :         if (m_dt.GetClass() == GEDTC_NUMERIC &&
     456        9527 :             m_dt.GetNumericDataType() == GDT_Unknown)
     457             :         {
     458         318 :             CPLDebug("HDF5",
     459             :                      "Cannot map data type of %s to a type handled by GDAL",
     460             :                      osName.c_str());
     461             :         }
     462       11993 :     }
     463             : 
     464             :   protected:
     465             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
     466             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
     467             :                const GDALExtendedDataType &bufferDataType,
     468             :                void *pDstBuffer) const override;
     469             : 
     470             :   public:
     471             :     ~HDF5Attribute();
     472             : 
     473             :     static std::shared_ptr<HDF5Attribute>
     474       11993 :     Create(const std::string &osGroupFullName, const std::string &osParentName,
     475             :            const std::string &osName,
     476             :            const std::shared_ptr<HDF5SharedResources> &poShared,
     477             :            hid_t hAttribute)
     478             :     {
     479             :         HDF5_GLOBAL_LOCK();
     480             : 
     481             :         auto ar(std::shared_ptr<HDF5Attribute>(new HDF5Attribute(
     482       23986 :             osGroupFullName, osParentName, osName, poShared, hAttribute)));
     483       21520 :         if (ar->m_dt.GetClass() == GEDTC_NUMERIC &&
     484        9527 :             ar->m_dt.GetNumericDataType() == GDT_Unknown)
     485             :         {
     486         318 :             return nullptr;
     487             :         }
     488       11675 :         return ar;
     489             :     }
     490             : 
     491             :     const std::vector<std::shared_ptr<GDALDimension>> &
     492        2415 :     GetDimensions() const override
     493             :     {
     494        2415 :         return m_dims;
     495             :     }
     496             : 
     497        2024 :     const GDALExtendedDataType &GetDataType() const override
     498             :     {
     499        2024 :         return m_dt;
     500             :     }
     501             : };
     502             : 
     503             : /************************************************************************/
     504             : /*                        HDF5SharedResources()                         */
     505             : /************************************************************************/
     506             : 
     507         146 : HDF5SharedResources::HDF5SharedResources(const std::string &osFilename)
     508             :     : m_osFilename(osFilename),
     509         146 :       m_poPAM(std::make_shared<GDALPamMultiDim>(osFilename))
     510             : {
     511         146 : }
     512             : 
     513             : /************************************************************************/
     514             : /*                        ~HDF5SharedResources()                        */
     515             : /************************************************************************/
     516             : 
     517         146 : HDF5SharedResources::~HDF5SharedResources()
     518             : {
     519             :     HDF5_GLOBAL_LOCK();
     520             : 
     521         146 :     if (m_hHDF5 > 0)
     522         146 :         H5Fclose(m_hHDF5);
     523         146 : }
     524             : 
     525             : /************************************************************************/
     526             : /*                          Create()                                    */
     527             : /************************************************************************/
     528             : 
     529             : std::shared_ptr<HDF5SharedResources>
     530         146 : HDF5SharedResources::Create(const std::string &osFilename)
     531             : {
     532             :     auto poSharedResources = std::shared_ptr<HDF5SharedResources>(
     533         146 :         new HDF5SharedResources(osFilename));
     534         146 :     poSharedResources->m_poSelf = poSharedResources;
     535         146 :     return poSharedResources;
     536             : }
     537             : 
     538             : /************************************************************************/
     539             : /*                           GetRootGroup()                             */
     540             : /************************************************************************/
     541             : 
     542         204 : std::shared_ptr<HDF5Group> HDF5SharedResources::GetRootGroup()
     543             : {
     544             : 
     545             :     H5G_stat_t oStatbuf;
     546         204 :     if (H5Gget_objinfo(m_hHDF5, "/", FALSE, &oStatbuf) < 0)
     547             :     {
     548           0 :         return nullptr;
     549             :     }
     550         204 :     auto hGroup = H5Gopen(m_hHDF5, "/");
     551         204 :     if (hGroup < 0)
     552             :     {
     553           0 :         return nullptr;
     554             :     }
     555             : 
     556         204 :     auto poSharedResources = m_poSelf.lock();
     557         204 :     CPLAssert(poSharedResources != nullptr);
     558         408 :     return HDF5Group::Create(std::string(), "/", poSharedResources, {}, hGroup,
     559         612 :                              oStatbuf.objno);
     560             : }
     561             : 
     562             : /************************************************************************/
     563             : /*                         GetDimensions()                              */
     564             : /************************************************************************/
     565             : 
     566             : std::vector<std::shared_ptr<GDALDimension>>
     567          42 : HDF5Group::GetDimensions(CSLConstList) const
     568             : {
     569             :     HDF5_GLOBAL_LOCK();
     570             : 
     571          42 :     if (m_bGotDims)
     572          21 :         return m_cachedDims;
     573             : 
     574             :     struct CallbackData
     575             :     {
     576             :         std::shared_ptr<HDF5SharedResources> poShared{};
     577             :         std::string osFullName{};
     578             :         std::vector<std::shared_ptr<GDALDimension>> oListDim{};
     579             :     };
     580             : 
     581             :     struct Callback
     582             :     {
     583         199 :         static herr_t f(hid_t hGroup, const char *pszObjName, void *user_data)
     584             :         {
     585         199 :             CallbackData *data = static_cast<CallbackData *>(user_data);
     586             :             H5G_stat_t oStatbuf;
     587             : 
     588         199 :             if (H5Gget_objinfo(hGroup, pszObjName, FALSE, &oStatbuf) < 0)
     589           0 :                 return -1;
     590             : 
     591         199 :             if (oStatbuf.type == H5G_DATASET)
     592             :             {
     593         147 :                 auto hArray = H5Dopen(hGroup, pszObjName);
     594         147 :                 if (hArray >= 0)
     595             :                 {
     596         147 :                     auto ar = HDF5Array::Create(data->osFullName, pszObjName,
     597         147 :                                                 data->poShared, hArray, nullptr,
     598         294 :                                                 true);
     599         147 :                     if (ar && ar->GetDimensionCount() == 1)
     600             :                     {
     601          84 :                         auto attrCLASS = ar->GetAttribute("CLASS");
     602          79 :                         if (attrCLASS && attrCLASS->GetDimensionCount() == 0 &&
     603          37 :                             attrCLASS->GetDataType().GetClass() == GEDTC_STRING)
     604             :                         {
     605          37 :                             const char *pszStr = attrCLASS->ReadAsString();
     606          37 :                             if (pszStr && EQUAL(pszStr, "DIMENSION_SCALE"))
     607             :                             {
     608          74 :                                 auto attrNAME = ar->GetAttribute("NAME");
     609          74 :                                 if (attrNAME &&
     610          74 :                                     attrNAME->GetDimensionCount() == 0 &&
     611          37 :                                     attrNAME->GetDataType().GetClass() ==
     612             :                                         GEDTC_STRING)
     613             :                                 {
     614             :                                     const char *pszName =
     615          37 :                                         attrNAME->ReadAsString();
     616          37 :                                     if (pszName &&
     617          37 :                                         STARTS_WITH(
     618             :                                             pszName,
     619             :                                             "This is a netCDF dimension but "
     620             :                                             "not a netCDF variable"))
     621             :                                     {
     622             :                                         data->oListDim.emplace_back(
     623          20 :                                             std::make_shared<GDALDimension>(
     624          20 :                                                 data->osFullName, pszObjName,
     625          40 :                                                 std::string(), std::string(),
     626          20 :                                                 ar->GetDimensions()[0]
     627          60 :                                                     ->GetSize()));
     628          20 :                                         return 0;
     629             :                                     }
     630             :                                 }
     631             : 
     632             :                                 data->oListDim.emplace_back(
     633          17 :                                     std::make_shared<HDF5Dimension>(
     634          17 :                                         data->osFullName, pszObjName,
     635          34 :                                         std::string(), std::string(),
     636          34 :                                         ar->GetDimensions()[0]->GetSize(),
     637          34 :                                         data->poShared));
     638             :                             }
     639             :                         }
     640             :                     }
     641             :                 }
     642             :             }
     643             : 
     644         179 :             return 0;
     645             :         }
     646             :     };
     647             : 
     648          42 :     CallbackData data;
     649          21 :     data.poShared = m_poShared;
     650          21 :     data.osFullName = GetFullName();
     651          21 :     H5Giterate(m_poShared->GetHDF5(), GetFullName().c_str(), nullptr,
     652             :                &(Callback::f), &data);
     653          21 :     m_bGotDims = true;
     654          21 :     m_cachedDims = data.oListDim;
     655             : 
     656          21 :     if (m_cachedDims.empty() && m_bIsEOSGridGroup)
     657             :     {
     658           2 :         const auto poHDF5EOSParser = m_poShared->GetHDF5EOSParser();
     659           4 :         HDF5EOSParser::GridMetadata oGridMetadata;
     660           4 :         if (poHDF5EOSParser &&
     661           2 :             poHDF5EOSParser->GetGridMetadata(GetName(), oGridMetadata))
     662             :         {
     663           2 :             double adfGT[6] = {0};
     664           2 :             const bool bHasGT = oGridMetadata.GetGeoTransform(adfGT) &&
     665           2 :                                 adfGT[2] == 0 && adfGT[4] == 0;
     666           6 :             for (auto &oDim : oGridMetadata.aoDimensions)
     667             :             {
     668           4 :                 if (oDim.osName == "XDim" && bHasGT)
     669             :                 {
     670             :                     auto poDim = std::make_shared<GDALDimensionWeakIndexingVar>(
     671           2 :                         GetFullName(), oDim.osName, GDAL_DIM_TYPE_HORIZONTAL_X,
     672           6 :                         std::string(), oDim.nSize);
     673             :                     auto poIndexingVar = GDALMDArrayRegularlySpaced::Create(
     674           2 :                         GetFullName(), oDim.osName, poDim,
     675           4 :                         adfGT[0] + adfGT[1] / 2, adfGT[1], 0);
     676           2 :                     poDim->SetIndexingVariable(poIndexingVar);
     677           2 :                     m_poXIndexingArray = poIndexingVar;
     678           2 :                     m_poShared->KeepRef(poIndexingVar);
     679           2 :                     m_cachedDims.emplace_back(poDim);
     680             :                 }
     681           2 :                 else if (oDim.osName == "YDim" && bHasGT)
     682             :                 {
     683             :                     auto poDim = std::make_shared<GDALDimensionWeakIndexingVar>(
     684           2 :                         GetFullName(), oDim.osName, GDAL_DIM_TYPE_HORIZONTAL_Y,
     685           6 :                         std::string(), oDim.nSize);
     686             :                     auto poIndexingVar = GDALMDArrayRegularlySpaced::Create(
     687           2 :                         GetFullName(), oDim.osName, poDim,
     688           4 :                         adfGT[3] + adfGT[5] / 2, adfGT[5], 0);
     689           2 :                     poDim->SetIndexingVariable(poIndexingVar);
     690           2 :                     m_poYIndexingArray = poIndexingVar;
     691           2 :                     m_poShared->KeepRef(poIndexingVar);
     692           2 :                     m_cachedDims.emplace_back(poDim);
     693             :                 }
     694             :                 else
     695             :                 {
     696           0 :                     m_cachedDims.emplace_back(std::make_shared<GDALDimension>(
     697           0 :                         GetFullName(), oDim.osName, std::string(),
     698           0 :                         std::string(), oDim.nSize));
     699             :                 }
     700             :             }
     701           2 :             m_poShared->RegisterEOSGridDimensions(GetName(), m_cachedDims);
     702             :         }
     703             :     }
     704          19 :     else if (m_cachedDims.empty() && m_bIsEOSSwathGroup)
     705             :     {
     706           3 :         const auto poHDF5EOSParser = m_poShared->GetHDF5EOSParser();
     707           6 :         HDF5EOSParser::SwathMetadata oSwathMetadata;
     708           6 :         if (poHDF5EOSParser &&
     709           3 :             poHDF5EOSParser->GetSwathMetadata(GetName(), oSwathMetadata))
     710             :         {
     711          12 :             for (auto &oDim : oSwathMetadata.aoDimensions)
     712             :             {
     713          18 :                 m_cachedDims.emplace_back(std::make_shared<GDALDimension>(
     714          18 :                     GetFullName(), oDim.osName, std::string(), std::string(),
     715          18 :                     oDim.nSize));
     716             :             }
     717           3 :             m_poShared->RegisterEOSSwathDimensions(GetName(), m_cachedDims);
     718             :         }
     719             :     }
     720             : 
     721          21 :     return m_cachedDims;
     722             : }
     723             : 
     724             : /************************************************************************/
     725             : /*                          GetGroupNamesCallback()                     */
     726             : /************************************************************************/
     727             : 
     728        1270 : herr_t HDF5Group::GetGroupNamesCallback(hid_t hGroup, const char *pszObjName,
     729             :                                         void *selfIn)
     730             : {
     731        1270 :     HDF5Group *self = static_cast<HDF5Group *>(selfIn);
     732             :     H5G_stat_t oStatbuf;
     733             : 
     734        1270 :     if (H5Gget_objinfo(hGroup, pszObjName, FALSE, &oStatbuf) < 0)
     735           0 :         return -1;
     736             : 
     737        1270 :     if (oStatbuf.type == H5G_GROUP)
     738             :     {
     739         485 :         if (self->m_oSetParentIds.find(
     740         485 :                 std::pair(oStatbuf.objno[0], oStatbuf.objno[1])) ==
     741         970 :             self->m_oSetParentIds.end())
     742             :         {
     743         485 :             self->m_osListSubGroups.push_back(pszObjName);
     744             :         }
     745             :         else
     746             :         {
     747           0 :             CPLDebug("HDF5",
     748             :                      "Group %s contains a link to group %s which is "
     749             :                      "itself, or one of its ancestor.",
     750           0 :                      self->GetFullName().c_str(), pszObjName);
     751             :         }
     752             :     }
     753        1270 :     return 0;
     754             : }
     755             : 
     756             : /************************************************************************/
     757             : /*                            GetGroupNames()                           */
     758             : /************************************************************************/
     759             : 
     760         430 : std::vector<std::string> HDF5Group::GetGroupNames(CSLConstList) const
     761             : {
     762             :     HDF5_GLOBAL_LOCK();
     763             : 
     764         430 :     m_osListSubGroups.clear();
     765         430 :     H5Giterate(m_poShared->GetHDF5(), GetFullName().c_str(), nullptr,
     766             :                GetGroupNamesCallback,
     767             :                const_cast<void *>(static_cast<const void *>(this)));
     768         430 :     return m_osListSubGroups;
     769             : }
     770             : 
     771             : /************************************************************************/
     772             : /*                             OpenGroup()                              */
     773             : /************************************************************************/
     774             : 
     775         555 : std::shared_ptr<GDALGroup> HDF5Group::OpenGroup(const std::string &osName,
     776             :                                                 CSLConstList) const
     777             : {
     778             :     HDF5_GLOBAL_LOCK();
     779             : 
     780         555 :     if (m_osListSubGroups.empty())
     781         410 :         GetGroupNames(nullptr);
     782         555 :     if (std::find(m_osListSubGroups.begin(), m_osListSubGroups.end(), osName) ==
     783        1110 :         m_osListSubGroups.end())
     784             :     {
     785         126 :         return nullptr;
     786             :     }
     787             : 
     788             :     H5G_stat_t oStatbuf;
     789         429 :     if (H5Gget_objinfo(m_hGroup, osName.c_str(), FALSE, &oStatbuf) < 0)
     790           0 :         return nullptr;
     791             : 
     792         429 :     auto hSubGroup = H5Gopen(m_hGroup, osName.c_str());
     793         429 :     if (hSubGroup < 0)
     794             :     {
     795           0 :         return nullptr;
     796             :     }
     797         858 :     return HDF5Group::Create(GetFullName(), osName, m_poShared, m_oSetParentIds,
     798         429 :                              hSubGroup, oStatbuf.objno);
     799             : }
     800             : 
     801             : /************************************************************************/
     802             : /*                          GetArrayNamesCallback()                     */
     803             : /************************************************************************/
     804             : 
     805         781 : herr_t HDF5Group::GetArrayNamesCallback(hid_t hGroup, const char *pszObjName,
     806             :                                         void *selfIn)
     807             : {
     808         781 :     HDF5Group *self = static_cast<HDF5Group *>(selfIn);
     809             :     H5G_stat_t oStatbuf;
     810             : 
     811         781 :     if (H5Gget_objinfo(hGroup, pszObjName, FALSE, &oStatbuf) < 0)
     812           0 :         return -1;
     813             : 
     814         781 :     if (oStatbuf.type == H5G_DATASET)
     815             :     {
     816         715 :         auto hArray = H5Dopen(hGroup, pszObjName);
     817         715 :         if (hArray >= 0)
     818             :         {
     819        1430 :             auto ar(HDF5Array::Create(std::string(), pszObjName,
     820        2145 :                                       self->m_poShared, hArray, self, true));
     821         715 :             if (ar)
     822             :             {
     823        1430 :                 auto attrNAME = ar->GetAttribute("NAME");
     824         758 :                 if (attrNAME && attrNAME->GetDimensionCount() == 0 &&
     825          43 :                     attrNAME->GetDataType().GetClass() == GEDTC_STRING)
     826             :                 {
     827          43 :                     const char *pszName = attrNAME->ReadAsString();
     828          43 :                     if (pszName &&
     829          43 :                         STARTS_WITH(pszName, "This is a netCDF dimension but "
     830             :                                              "not a netCDF variable"))
     831             :                     {
     832          24 :                         return 0;
     833             :                     }
     834             :                 }
     835             :             }
     836             :         }
     837         691 :         self->m_osListArrays.push_back(pszObjName);
     838             :     }
     839         757 :     return 0;
     840             : }
     841             : 
     842             : /************************************************************************/
     843             : /*                         GetMDArrayNames()                            */
     844             : /************************************************************************/
     845             : 
     846         172 : std::vector<std::string> HDF5Group::GetMDArrayNames(CSLConstList) const
     847             : {
     848             :     HDF5_GLOBAL_LOCK();
     849             : 
     850         172 :     m_osListArrays.clear();
     851         172 :     H5Giterate(m_poShared->GetHDF5(), GetFullName().c_str(), nullptr,
     852             :                GetArrayNamesCallback,
     853             :                const_cast<void *>(static_cast<const void *>(this)));
     854             : 
     855         172 :     if (m_poXIndexingArray)
     856           0 :         m_osListArrays.push_back(m_poXIndexingArray->GetName());
     857         172 :     if (m_poYIndexingArray)
     858           0 :         m_osListArrays.push_back(m_poYIndexingArray->GetName());
     859             : 
     860         172 :     return m_osListArrays;
     861             : }
     862             : 
     863             : /************************************************************************/
     864             : /*                           OpenMDArray()                              */
     865             : /************************************************************************/
     866             : 
     867         245 : std::shared_ptr<GDALMDArray> HDF5Group::OpenMDArray(const std::string &osName,
     868             :                                                     CSLConstList) const
     869             : {
     870             :     HDF5_GLOBAL_LOCK();
     871             : 
     872         245 :     if (m_osListArrays.empty())
     873         138 :         GetMDArrayNames(nullptr);
     874         245 :     if (std::find(m_osListArrays.begin(), m_osListArrays.end(), osName) ==
     875         490 :         m_osListArrays.end())
     876             :     {
     877           7 :         return nullptr;
     878             :     }
     879         238 :     if (m_poXIndexingArray && m_poXIndexingArray->GetName() == osName)
     880           0 :         return m_poXIndexingArray;
     881         238 :     if (m_poYIndexingArray && m_poYIndexingArray->GetName() == osName)
     882           0 :         return m_poYIndexingArray;
     883             : 
     884         238 :     auto hArray = H5Dopen(m_hGroup, osName.c_str());
     885         238 :     if (hArray < 0)
     886             :     {
     887           0 :         return nullptr;
     888             :     }
     889         476 :     return HDF5Array::Create(GetFullName(), osName, m_poShared, hArray, this,
     890         238 :                              false);
     891             : }
     892             : 
     893             : /************************************************************************/
     894             : /*                          GetAttributesCallback()                     */
     895             : /************************************************************************/
     896             : 
     897        8199 : herr_t HDF5Group::GetAttributesCallback(hid_t hGroup, const char *pszObjName,
     898             :                                         void *selfIn)
     899             : {
     900        8199 :     HDF5Group *self = static_cast<HDF5Group *>(selfIn);
     901        8199 :     if (self->m_bShowAllAttributes || (!EQUAL(pszObjName, "_Netcdf4Dimid") &&
     902        8199 :                                        !EQUAL(pszObjName, "_NCProperties")))
     903             :     {
     904        8198 :         hid_t hAttr = H5Aopen_name(hGroup, pszObjName);
     905        8198 :         if (hAttr > 0)
     906             :         {
     907             :             auto attr(HDF5Attribute::Create(self->GetFullName(),
     908             :                                             self->GetFullName(), pszObjName,
     909       24594 :                                             self->m_poShared, hAttr));
     910        8198 :             if (attr)
     911             :             {
     912        8198 :                 self->m_oListAttributes.emplace_back(attr);
     913             :             }
     914             :         }
     915             :     }
     916        8199 :     return 0;
     917             : }
     918             : 
     919             : /************************************************************************/
     920             : /*                           GetAttributes()                            */
     921             : /************************************************************************/
     922             : 
     923             : std::vector<std::shared_ptr<GDALAttribute>>
     924        1051 : HDF5Group::GetAttributes(CSLConstList papszOptions) const
     925             : {
     926             :     HDF5_GLOBAL_LOCK();
     927             : 
     928        1051 :     m_oListAttributes.clear();
     929        1051 :     m_bShowAllAttributes =
     930        1051 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SHOW_ALL", "NO"));
     931        1051 :     H5Aiterate(m_hGroup, nullptr, GetAttributesCallback,
     932             :                const_cast<void *>(static_cast<const void *>(this)));
     933        1051 :     return m_oListAttributes;
     934             : }
     935             : 
     936             : /************************************************************************/
     937             : /*                               ~HDF5Array()                           */
     938             : /************************************************************************/
     939             : 
     940        2224 : HDF5Array::~HDF5Array()
     941             : {
     942             :     HDF5_GLOBAL_LOCK();
     943             : 
     944        1112 :     if (m_hArray > 0)
     945        1112 :         H5Dclose(m_hArray);
     946        1112 :     if (m_hNativeDT > 0)
     947        1112 :         H5Tclose(m_hNativeDT);
     948        1112 :     if (m_hDataSpace > 0)
     949        1112 :         H5Sclose(m_hDataSpace);
     950        2224 : }
     951             : 
     952             : /************************************************************************/
     953             : /*                                HDF5Array()                           */
     954             : /************************************************************************/
     955             : 
     956        1112 : HDF5Array::HDF5Array(const std::string &osParentName, const std::string &osName,
     957             :                      const std::shared_ptr<HDF5SharedResources> &poShared,
     958             :                      hid_t hArray, const HDF5Group *poGroup,
     959        1112 :                      bool bSkipFullDimensionInstantiation)
     960             :     : GDALAbstractMDArray(osParentName, osName),
     961             :       GDALMDArray(osParentName, osName), m_osGroupFullname(osParentName),
     962             :       m_poShared(poShared), m_hArray(hArray),
     963        1112 :       m_hDataSpace(H5Dget_space(hArray)), m_nOffset(H5Dget_offset(hArray))
     964             : {
     965        1112 :     const hid_t hDataType = H5Dget_type(hArray);
     966        1112 :     m_hNativeDT = H5Tget_native_type(hDataType, H5T_DIR_ASCEND);
     967        1112 :     H5Tclose(hDataType);
     968             : 
     969        1112 :     std::vector<std::pair<std::string, hid_t>> oTypes;
     970        1112 :     if (!osParentName.empty() && H5Tget_class(m_hNativeDT) == H5T_COMPOUND)
     971             :     {
     972         193 :         GetDataTypesInGroup(m_poShared->GetHDF5(), osParentName, oTypes);
     973             :     }
     974             : 
     975        2224 :     m_dt = BuildDataType(m_hNativeDT, m_bHasString, m_bHasNonNativeDataType,
     976        1112 :                          oTypes);
     977        1382 :     for (auto &oPair : oTypes)
     978         270 :         H5Tclose(oPair.second);
     979             : 
     980        1626 :     if (m_dt.GetClass() == GEDTC_NUMERIC &&
     981         514 :         m_dt.GetNumericDataType() == GDT_Unknown)
     982             :     {
     983           0 :         CPLDebug("HDF5", "Cannot map data type of %s to a type handled by GDAL",
     984             :                  osName.c_str());
     985           0 :         return;
     986             :     }
     987             : 
     988        1112 :     HDF5Array::GetAttributes();
     989             : 
     990             :     // Special case for S102 nodata value that is typically at 1e6
     991        1112 :     if (GetFullName() ==
     992          19 :             "/BathymetryCoverage/BathymetryCoverage.01/Group_001/values" &&
     993          38 :         m_dt.GetClass() == GEDTC_COMPOUND &&
     994          37 :         (m_dt.GetComponents().size() == 1 ||
     995          18 :          m_dt.GetComponents().size() == 2) &&
     996          38 :         m_dt.GetSize() == m_dt.GetComponents().size() * sizeof(float) &&
     997          19 :         m_dt.GetComponents()[0]->GetType().GetNumericDataType() ==
     998        1149 :             GDT_Float32 &&
     999          37 :         (m_dt.GetComponents().size() == 1 ||
    1000          18 :          m_dt.GetComponents()[1]->GetType().GetNumericDataType() ==
    1001             :              GDT_Float32))
    1002             :     {
    1003          19 :         m_abyNoData.resize(m_dt.GetSize());
    1004          19 :         float afNoData[2] = {1e6f, 1e6f};
    1005             : 
    1006          38 :         if (auto poRootGroup = HDF5Array::GetRootGroup())
    1007             :         {
    1008          57 :             if (const auto poGroupF = poRootGroup->OpenGroup("Group_F"))
    1009             :             {
    1010             :                 const auto poGroupFArray =
    1011          57 :                     poGroupF->OpenMDArray("BathymetryCoverage");
    1012          19 :                 if (poGroupFArray &&
    1013          57 :                     poGroupFArray->GetDataType().GetClass() == GEDTC_COMPOUND &&
    1014          38 :                     poGroupFArray->GetDataType().GetComponents().size() == 8 &&
    1015          19 :                     poGroupFArray->GetDataType()
    1016          19 :                             .GetComponents()[0]
    1017          38 :                             ->GetName() == "code" &&
    1018          19 :                     poGroupFArray->GetDataType()
    1019          19 :                             .GetComponents()[3]
    1020          19 :                             ->GetName() == "fillValue" &&
    1021          57 :                     poGroupFArray->GetDimensionCount() == 1 &&
    1022          19 :                     poGroupFArray->GetDimensions()[0]->GetSize() ==
    1023          19 :                         m_dt.GetComponents().size())
    1024             :                 {
    1025             :                     auto poFillValue =
    1026          57 :                         poGroupFArray->GetView("[\"fillValue\"]");
    1027          19 :                     if (poFillValue)
    1028             :                     {
    1029          19 :                         char *pszVal0 = nullptr;
    1030          19 :                         char *pszVal1 = nullptr;
    1031          19 :                         const GUInt64 anArrayStartIdx0[] = {0};
    1032          19 :                         const GUInt64 anArrayStartIdx1[] = {1};
    1033          19 :                         const size_t anCount[] = {1};
    1034          19 :                         const GInt64 anArrayStep[] = {0};
    1035          19 :                         const GPtrDiff_t anBufferStride[] = {0};
    1036          38 :                         poFillValue->Read(anArrayStartIdx0, anCount,
    1037             :                                           anArrayStep, anBufferStride,
    1038          38 :                                           GDALExtendedDataType::CreateString(),
    1039             :                                           &pszVal0);
    1040          19 :                         if (poGroupFArray->GetDimensions()[0]->GetSize() == 2)
    1041             :                         {
    1042          36 :                             poFillValue->Read(
    1043             :                                 anArrayStartIdx1, anCount, anArrayStep,
    1044             :                                 anBufferStride,
    1045          36 :                                 GDALExtendedDataType::CreateString(), &pszVal1);
    1046             :                         }
    1047          19 :                         if (pszVal0)
    1048             :                         {
    1049          19 :                             afNoData[0] = static_cast<float>(CPLAtof(pszVal0));
    1050          19 :                             if (pszVal1)
    1051             :                             {
    1052          18 :                                 afNoData[1] =
    1053          18 :                                     static_cast<float>(CPLAtof(pszVal1));
    1054             :                             }
    1055             :                         }
    1056          19 :                         CPLFree(pszVal0);
    1057          19 :                         CPLFree(pszVal1);
    1058             :                     }
    1059             :                 }
    1060             :             }
    1061             :         }
    1062             : 
    1063          19 :         m_abyNoData.resize(m_dt.GetSize());
    1064          19 :         memcpy(m_abyNoData.data(), afNoData, m_abyNoData.size());
    1065             :     }
    1066             : 
    1067             :     // Special case for S102 QualityOfSurvey nodata value that is typically at 0
    1068             :     const bool bIsQualityOfSurvey =
    1069        1112 :         (GetFullName() ==
    1070             :          "/QualityOfSurvey/QualityOfSurvey.01/Group_001/values");
    1071             :     const bool bIsQualityOfBathymetryCoverage =
    1072        1112 :         (GetFullName() == "/QualityOfBathymetryCoverage/"
    1073             :                           "QualityOfBathymetryCoverage.01/Group_001/values");
    1074        1122 :     if ((bIsQualityOfSurvey || bIsQualityOfBathymetryCoverage) &&
    1075           8 :         ((m_dt.GetClass() == GEDTC_NUMERIC &&
    1076           5 :           m_dt.GetNumericDataType() == GDT_UInt32) ||
    1077           4 :          (m_dt.GetClass() == GEDTC_COMPOUND &&
    1078           4 :           m_dt.GetComponents().size() == 1 &&
    1079           4 :           m_dt.GetComponents()[0]->GetType().GetClass() == GEDTC_NUMERIC &&
    1080           2 :           m_dt.GetComponents()[0]->GetType().GetNumericDataType() ==
    1081             :               GDT_UInt32)))
    1082             :     {
    1083          10 :         if (auto poRootGroup = HDF5Array::GetRootGroup())
    1084             :         {
    1085          15 :             if (const auto poGroupF = poRootGroup->OpenGroup("Group_F"))
    1086             :             {
    1087           5 :                 const auto poGroupFArray = poGroupF->OpenMDArray(
    1088             :                     bIsQualityOfSurvey ? "QualityOfSurvey"
    1089          15 :                                        : "QualityOfBathymetryCoverage");
    1090           5 :                 if (poGroupFArray &&
    1091          15 :                     poGroupFArray->GetDataType().GetClass() == GEDTC_COMPOUND &&
    1092          10 :                     poGroupFArray->GetDataType().GetComponents().size() == 8 &&
    1093           5 :                     poGroupFArray->GetDataType()
    1094           5 :                             .GetComponents()[0]
    1095          10 :                             ->GetName() == "code" &&
    1096           5 :                     poGroupFArray->GetDataType()
    1097           5 :                             .GetComponents()[3]
    1098           5 :                             ->GetName() == "fillValue" &&
    1099          15 :                     poGroupFArray->GetDimensionCount() == 1 &&
    1100           5 :                     poGroupFArray->GetDimensions()[0]->GetSize() == 1)
    1101             :                 {
    1102             :                     auto poFillValue =
    1103          15 :                         poGroupFArray->GetView("[\"fillValue\"]");
    1104           5 :                     if (poFillValue)
    1105             :                     {
    1106           5 :                         char *pszVal0 = nullptr;
    1107           5 :                         const GUInt64 anArrayStartIdx0[] = {0};
    1108           5 :                         const size_t anCount[] = {1};
    1109           5 :                         const GInt64 anArrayStep[] = {0};
    1110           5 :                         const GPtrDiff_t anBufferStride[] = {0};
    1111          10 :                         poFillValue->Read(anArrayStartIdx0, anCount,
    1112             :                                           anArrayStep, anBufferStride,
    1113          10 :                                           GDALExtendedDataType::CreateString(),
    1114             :                                           &pszVal0);
    1115           5 :                         if (pszVal0)
    1116             :                         {
    1117           5 :                             const uint32_t nNoData = atoi(pszVal0);
    1118           5 :                             m_abyNoData.resize(m_dt.GetSize());
    1119           5 :                             memcpy(m_abyNoData.data(), &nNoData,
    1120             :                                    m_abyNoData.size());
    1121             :                         }
    1122           5 :                         CPLFree(pszVal0);
    1123             :                     }
    1124             :                 }
    1125             :             }
    1126             :         }
    1127             :     }
    1128             : 
    1129             :     // Special case for S104 nodata value that is typically -9999
    1130        1115 :     if (STARTS_WITH(GetFullName().c_str(), "/WaterLevel/WaterLevel.01/") &&
    1131           6 :         GetFullName().find("/values") != std::string::npos &&
    1132           9 :         m_dt.GetClass() == GEDTC_COMPOUND && m_dt.GetSize() == 8 &&
    1133           6 :         m_dt.GetComponents().size() == 2 &&
    1134           3 :         m_dt.GetComponents()[0]->GetType().GetNumericDataType() ==
    1135        1115 :             GDT_Float32 &&
    1136             :         // In theory should be Byte, but 104US00_ches_dcf2_20190606T12Z.h5 uses Int32
    1137           3 :         (m_dt.GetComponents()[1]->GetType().GetNumericDataType() == GDT_Byte ||
    1138           0 :          m_dt.GetComponents()[1]->GetType().GetNumericDataType() == GDT_Int32))
    1139             :     {
    1140           3 :         m_abyNoData.resize(m_dt.GetSize());
    1141           3 :         float fNoData = -9999.0f;
    1142             : 
    1143           6 :         if (auto poRootGroup = HDF5Array::GetRootGroup())
    1144             :         {
    1145           9 :             if (const auto poGroupF = poRootGroup->OpenGroup("Group_F"))
    1146             :             {
    1147           9 :                 const auto poGroupFArray = poGroupF->OpenMDArray("WaterLevel");
    1148           3 :                 if (poGroupFArray &&
    1149           9 :                     poGroupFArray->GetDataType().GetClass() == GEDTC_COMPOUND &&
    1150           6 :                     poGroupFArray->GetDataType().GetComponents().size() == 8 &&
    1151           3 :                     poGroupFArray->GetDataType()
    1152           3 :                             .GetComponents()[0]
    1153           6 :                             ->GetName() == "code" &&
    1154           3 :                     poGroupFArray->GetDataType()
    1155           3 :                             .GetComponents()[3]
    1156           3 :                             ->GetName() == "fillValue" &&
    1157           9 :                     poGroupFArray->GetDimensionCount() == 1 &&
    1158           3 :                     poGroupFArray->GetDimensions()[0]->GetSize() >= 2)
    1159             :                 {
    1160             :                     auto poFillValue =
    1161           9 :                         poGroupFArray->GetView("[\"fillValue\"]");
    1162           3 :                     if (poFillValue)
    1163             :                     {
    1164           3 :                         char *pszVal0 = nullptr;
    1165           3 :                         const GUInt64 anArrayStartIdx0[] = {0};
    1166           3 :                         const size_t anCount[] = {1};
    1167           3 :                         const GInt64 anArrayStep[] = {0};
    1168           3 :                         const GPtrDiff_t anBufferStride[] = {0};
    1169           6 :                         poFillValue->Read(anArrayStartIdx0, anCount,
    1170             :                                           anArrayStep, anBufferStride,
    1171           6 :                                           GDALExtendedDataType::CreateString(),
    1172             :                                           &pszVal0);
    1173           3 :                         if (pszVal0)
    1174             :                         {
    1175           3 :                             fNoData = static_cast<float>(CPLAtof(pszVal0));
    1176             :                         }
    1177           3 :                         CPLFree(pszVal0);
    1178             :                     }
    1179             :                 }
    1180             :             }
    1181             :         }
    1182             : 
    1183           3 :         memcpy(m_abyNoData.data(), &fNoData, sizeof(float));
    1184             :     }
    1185             : 
    1186             :     // Special case for S111 nodata value that is typically -9999
    1187        1112 :     if (STARTS_WITH(GetFullName().c_str(),
    1188           3 :                     "/SurfaceCurrent/SurfaceCurrent.01/") &&
    1189           6 :         GetFullName().find("/values") != std::string::npos &&
    1190           6 :         m_dt.GetClass() == GEDTC_COMPOUND &&
    1191           6 :         m_dt.GetSize() == 2 * sizeof(float) &&
    1192           6 :         m_dt.GetComponents().size() == 2 &&
    1193           3 :         m_dt.GetComponents()[0]->GetType().GetNumericDataType() ==
    1194        1115 :             GDT_Float32 &&
    1195           3 :         m_dt.GetComponents()[1]->GetType().GetNumericDataType() == GDT_Float32)
    1196             :     {
    1197           3 :         float afNoData[2] = {-9999.0f, -9999.0f};
    1198             : 
    1199           6 :         if (auto poRootGroup = HDF5Array::GetRootGroup())
    1200             :         {
    1201           9 :             if (const auto poGroupF = poRootGroup->OpenGroup("Group_F"))
    1202             :             {
    1203             :                 const auto poGroupFArray =
    1204           9 :                     poGroupF->OpenMDArray("SurfaceCurrent");
    1205           3 :                 if (poGroupFArray &&
    1206           9 :                     poGroupFArray->GetDataType().GetClass() == GEDTC_COMPOUND &&
    1207           6 :                     poGroupFArray->GetDataType().GetComponents().size() == 8 &&
    1208           3 :                     poGroupFArray->GetDataType()
    1209           3 :                             .GetComponents()[0]
    1210           6 :                             ->GetName() == "code" &&
    1211           3 :                     poGroupFArray->GetDataType()
    1212           3 :                             .GetComponents()[3]
    1213           3 :                             ->GetName() == "fillValue" &&
    1214           9 :                     poGroupFArray->GetDimensionCount() == 1 &&
    1215           3 :                     poGroupFArray->GetDimensions()[0]->GetSize() >= 2)
    1216             :                 {
    1217             :                     auto poFillValue =
    1218           9 :                         poGroupFArray->GetView("[\"fillValue\"]");
    1219           3 :                     if (poFillValue)
    1220             :                     {
    1221           3 :                         char *pszVal0 = nullptr;
    1222           3 :                         char *pszVal1 = nullptr;
    1223           3 :                         const GUInt64 anArrayStartIdx0[] = {0};
    1224           3 :                         const GUInt64 anArrayStartIdx1[] = {1};
    1225           3 :                         const size_t anCount[] = {1};
    1226           3 :                         const GInt64 anArrayStep[] = {0};
    1227           3 :                         const GPtrDiff_t anBufferStride[] = {0};
    1228           6 :                         poFillValue->Read(anArrayStartIdx0, anCount,
    1229             :                                           anArrayStep, anBufferStride,
    1230           6 :                                           GDALExtendedDataType::CreateString(),
    1231             :                                           &pszVal0);
    1232           6 :                         poFillValue->Read(anArrayStartIdx1, anCount,
    1233             :                                           anArrayStep, anBufferStride,
    1234           6 :                                           GDALExtendedDataType::CreateString(),
    1235             :                                           &pszVal1);
    1236           3 :                         if (pszVal0 && pszVal1)
    1237             :                         {
    1238           3 :                             afNoData[0] = static_cast<float>(CPLAtof(pszVal0));
    1239           3 :                             afNoData[1] = static_cast<float>(CPLAtof(pszVal1));
    1240             :                         }
    1241           3 :                         CPLFree(pszVal0);
    1242           3 :                         CPLFree(pszVal1);
    1243             :                     }
    1244             :                 }
    1245             :             }
    1246             :         }
    1247             : 
    1248           3 :         m_abyNoData.resize(m_dt.GetSize());
    1249           3 :         memcpy(m_abyNoData.data(), afNoData, m_abyNoData.size());
    1250             :     }
    1251             : 
    1252        1112 :     if (bSkipFullDimensionInstantiation)
    1253             :     {
    1254         862 :         const int nDims = H5Sget_simple_extent_ndims(m_hDataSpace);
    1255        1724 :         std::vector<hsize_t> anDimSizes(nDims);
    1256         862 :         if (nDims)
    1257             :         {
    1258         851 :             H5Sget_simple_extent_dims(m_hDataSpace, &anDimSizes[0], nullptr);
    1259        2266 :             for (int i = 0; i < nDims; ++i)
    1260             :             {
    1261        2830 :                 m_dims.emplace_back(std::make_shared<GDALDimension>(
    1262        2830 :                     std::string(), CPLSPrintf("dim%d", i), std::string(),
    1263        4245 :                     std::string(), anDimSizes[i]));
    1264             :             }
    1265             :         }
    1266             :     }
    1267             :     else
    1268             :     {
    1269         250 :         InstantiateDimensions(osParentName, poGroup);
    1270             :     }
    1271             : }
    1272             : 
    1273             : /************************************************************************/
    1274             : /*                        InstantiateDimensions()                       */
    1275             : /************************************************************************/
    1276             : 
    1277         250 : void HDF5Array::InstantiateDimensions(const std::string &osParentName,
    1278             :                                       const HDF5Group *poGroup)
    1279             : {
    1280         250 :     const int nDims = H5Sget_simple_extent_ndims(m_hDataSpace);
    1281         250 :     std::vector<hsize_t> anDimSizes(nDims);
    1282         250 :     if (nDims)
    1283             :     {
    1284         249 :         H5Sget_simple_extent_dims(m_hDataSpace, &anDimSizes[0], nullptr);
    1285             :     }
    1286             : 
    1287         250 :     if (nDims == 1)
    1288             :     {
    1289         320 :         auto attrCLASS = GetAttribute("CLASS");
    1290         174 :         if (attrCLASS && attrCLASS->GetDimensionCount() == 0 &&
    1291          14 :             attrCLASS->GetDataType().GetClass() == GEDTC_STRING)
    1292             :         {
    1293          14 :             const char *pszStr = attrCLASS->ReadAsString();
    1294          14 :             if (pszStr && EQUAL(pszStr, "DIMENSION_SCALE"))
    1295             :             {
    1296          42 :                 auto attrName = GetAttribute("NAME");
    1297          28 :                 if (attrName &&
    1298          28 :                     attrName->GetDataType().GetClass() == GEDTC_STRING)
    1299             :                 {
    1300          14 :                     const char *pszName = attrName->ReadAsString();
    1301          14 :                     if (pszName &&
    1302          14 :                         STARTS_WITH(pszName, "This is a netCDF dimension but "
    1303             :                                              "not a netCDF variable"))
    1304             :                     {
    1305           0 :                         m_dims.emplace_back(std::make_shared<GDALDimension>(
    1306           0 :                             std::string(), GetName(), std::string(),
    1307           0 :                             std::string(), anDimSizes[0]));
    1308           0 :                         return;
    1309             :                     }
    1310             :                 }
    1311             : 
    1312          28 :                 m_dims.emplace_back(std::make_shared<HDF5Dimension>(
    1313          28 :                     osParentName, GetName(), std::string(), std::string(),
    1314          28 :                     anDimSizes[0], m_poShared));
    1315          14 :                 return;
    1316             :             }
    1317             :         }
    1318             :     }
    1319             : 
    1320         236 :     std::map<size_t, std::string> mapDimIndexToDimFullName;
    1321             : 
    1322         236 :     if (m_bHasDimensionList)
    1323             :     {
    1324          27 :         hid_t hAttr = H5Aopen_name(m_hArray, "DIMENSION_LIST");
    1325          27 :         const hid_t hAttrDataType = H5Aget_type(hAttr);
    1326          27 :         const hid_t hAttrSpace = H5Aget_space(hAttr);
    1327          54 :         if (H5Tget_class(hAttrDataType) == H5T_VLEN &&
    1328          27 :             H5Sget_simple_extent_ndims(hAttrSpace) == 1)
    1329             :         {
    1330          27 :             const hid_t hBaseType = H5Tget_super(hAttrDataType);
    1331          27 :             if (H5Tget_class(hBaseType) == H5T_REFERENCE)
    1332             :             {
    1333          27 :                 hsize_t nSize = 0;
    1334          27 :                 H5Sget_simple_extent_dims(hAttrSpace, &nSize, nullptr);
    1335          27 :                 if (nSize == static_cast<hsize_t>(nDims))
    1336             :                 {
    1337          54 :                     std::vector<hvl_t> aHvl(static_cast<size_t>(nSize));
    1338          27 :                     H5Aread(hAttr, hAttrDataType, &aHvl[0]);
    1339          88 :                     for (size_t i = 0; i < nSize; i++)
    1340             :                     {
    1341         122 :                         if (aHvl[i].len == 1 &&
    1342          61 :                             H5Rget_obj_type(m_hArray, H5R_OBJECT, aHvl[i].p) ==
    1343             :                                 H5G_DATASET)
    1344             :                         {
    1345         122 :                             std::string referenceName;
    1346          61 :                             referenceName.resize(256);
    1347         122 :                             auto ret = H5Rget_name(
    1348          61 :                                 m_poShared->GetHDF5(), H5R_OBJECT, aHvl[i].p,
    1349          61 :                                 &referenceName[0], referenceName.size());
    1350          61 :                             if (ret > 0)
    1351             :                             {
    1352          61 :                                 referenceName.resize(ret);
    1353          61 :                                 mapDimIndexToDimFullName[i] =
    1354         122 :                                     std::move(referenceName);
    1355             :                             }
    1356             :                         }
    1357             :                     }
    1358          27 :                     H5Dvlen_reclaim(hAttrDataType, hAttrSpace, H5P_DEFAULT,
    1359          27 :                                     &aHvl[0]);
    1360             :                 }
    1361             :             }
    1362          27 :             H5Tclose(hBaseType);
    1363             :         }
    1364          27 :         H5Tclose(hAttrDataType);
    1365          27 :         H5Sclose(hAttrSpace);
    1366          27 :         H5Aclose(hAttr);
    1367             :     }
    1368         209 :     else if (m_bHasDimensionLabels)
    1369             :     {
    1370           2 :         hid_t hAttr = H5Aopen_name(m_hArray, "DIMENSION_LABELS");
    1371           2 :         auto attr(HDF5Attribute::Create(m_osGroupFullname, GetFullName(),
    1372           6 :                                         "DIMENSION_LABELS", m_poShared, hAttr));
    1373           4 :         if (attr && attr->GetDimensionCount() == 1 &&
    1374           2 :             attr->GetDataType().GetClass() == GEDTC_STRING)
    1375             :         {
    1376           4 :             auto aosList = attr->ReadAsStringArray();
    1377           2 :             if (aosList.size() == nDims)
    1378             :             {
    1379           8 :                 for (int i = 0; i < nDims; ++i)
    1380             :                 {
    1381           6 :                     if (aosList[i][0] != '\0')
    1382             :                     {
    1383           2 :                         mapDimIndexToDimFullName[i] = aosList[i];
    1384             :                     }
    1385             :                 }
    1386             :             }
    1387             :         }
    1388             :     }
    1389             :     else
    1390             :     {
    1391             :         // Use HDF-EOS5 metadata if available to create dimensions
    1392             : 
    1393         207 :         HDF5EOSParser::GridDataFieldMetadata oGridDataFieldMetadata;
    1394         207 :         HDF5EOSParser::SwathDataFieldMetadata oSwathDataFieldMetadata;
    1395             :         HDF5EOSParser::SwathGeolocationFieldMetadata
    1396         207 :             oSwathGeolocationFieldMetadata;
    1397         207 :         const auto poHDF5EOSParser = m_poShared->GetHDF5EOSParser();
    1398             :         // Build a "classic" subdataset name from group and array names
    1399             :         const std::string osSubdatasetName(
    1400         207 :             "/" +
    1401         207 :             CPLString(osParentName)
    1402         414 :                 .replaceAll("Data Fields", "Data_Fields")
    1403         621 :                 .replaceAll("Geolocation Fields", "Geolocation_Fields") +
    1404         414 :             "/" + GetName());
    1405         212 :         if (poHDF5EOSParser &&
    1406           5 :             poHDF5EOSParser->GetGridDataFieldMetadata(osSubdatasetName.c_str(),
    1407         212 :                                                       oGridDataFieldMetadata) &&
    1408           2 :             oGridDataFieldMetadata.aoDimensions.size() ==
    1409           2 :                 static_cast<size_t>(nDims))
    1410             :         {
    1411           4 :             std::map<std::string, std::shared_ptr<GDALDimension>> oMap;
    1412           2 :             const auto groupDims = m_poShared->GetEOSGridDimensions(
    1413           4 :                 oGridDataFieldMetadata.poGridMetadata->osGridName);
    1414           6 :             for (const auto &dim : groupDims)
    1415             :             {
    1416           4 :                 oMap[dim->GetName()] = dim;
    1417             :             }
    1418           2 :             int iDimX = 0;
    1419           2 :             int iDimY = 0;
    1420           2 :             int iCount = 1;
    1421           6 :             for (const auto &oDim : oGridDataFieldMetadata.aoDimensions)
    1422             :             {
    1423           4 :                 auto oIter = oMap.find(oDim.osName);
    1424             :                 // HDF5EOSParser guarantees that
    1425           4 :                 CPLAssert(oIter != oMap.end());
    1426           4 :                 const auto &poDim = oIter->second;
    1427           4 :                 if (poDim->GetType() == GDAL_DIM_TYPE_HORIZONTAL_X)
    1428           2 :                     iDimX = iCount;
    1429           2 :                 else if (poDim->GetType() == GDAL_DIM_TYPE_HORIZONTAL_Y)
    1430           2 :                     iDimY = iCount;
    1431           4 :                 ++iCount;
    1432           4 :                 m_dims.emplace_back(poDim);
    1433             :             }
    1434             : 
    1435           2 :             auto poSRS = oGridDataFieldMetadata.poGridMetadata->GetSRS();
    1436           2 :             if (poSRS)
    1437             :             {
    1438           2 :                 m_poSRS = std::shared_ptr<OGRSpatialReference>(poSRS->Clone());
    1439           2 :                 if (iDimX > 0 && iDimY > 0)
    1440             :                 {
    1441           2 :                     if (m_poSRS->GetDataAxisToSRSAxisMapping() ==
    1442           4 :                         std::vector<int>{2, 1})
    1443           1 :                         m_poSRS->SetDataAxisToSRSAxisMapping({iDimY, iDimX});
    1444             :                     else
    1445           1 :                         m_poSRS->SetDataAxisToSRSAxisMapping({iDimX, iDimY});
    1446             :                 }
    1447             :             }
    1448             : 
    1449           2 :             return;
    1450             :         }
    1451         208 :         else if (poHDF5EOSParser &&
    1452           3 :                  poHDF5EOSParser->GetSwathDataFieldMetadata(
    1453         208 :                      osSubdatasetName.c_str(), oSwathDataFieldMetadata) &&
    1454           1 :                  oSwathDataFieldMetadata.aoDimensions.size() ==
    1455           1 :                      static_cast<size_t>(nDims))
    1456             :         {
    1457           2 :             std::map<std::string, std::shared_ptr<GDALDimension>> oMap;
    1458           1 :             const auto groupDims = m_poShared->GetEOSSwathDimensions(
    1459           1 :                 oSwathDataFieldMetadata.poSwathMetadata->osSwathName);
    1460           4 :             for (const auto &dim : groupDims)
    1461             :             {
    1462           3 :                 oMap[dim->GetName()] = dim;
    1463             :             }
    1464           4 :             for (const auto &oDim : oSwathDataFieldMetadata.aoDimensions)
    1465             :             {
    1466           3 :                 auto oIter = oMap.find(oDim.osName);
    1467             :                 // HDF5EOSParser guarantees that
    1468           3 :                 CPLAssert(oIter != oMap.end());
    1469           3 :                 const auto &poDim = oIter->second;
    1470           3 :                 m_dims.emplace_back(poDim);
    1471             :             }
    1472             : 
    1473           1 :             return;
    1474             :         }
    1475         206 :         else if (poHDF5EOSParser &&
    1476           2 :                  poHDF5EOSParser->GetSwathGeolocationFieldMetadata(
    1477             :                      osSubdatasetName.c_str(),
    1478         206 :                      oSwathGeolocationFieldMetadata) &&
    1479           2 :                  oSwathGeolocationFieldMetadata.aoDimensions.size() ==
    1480           2 :                      static_cast<size_t>(nDims))
    1481             :         {
    1482           4 :             std::map<std::string, std::shared_ptr<GDALDimension>> oMap;
    1483           2 :             const auto groupDims = m_poShared->GetEOSSwathDimensions(
    1484           2 :                 oSwathGeolocationFieldMetadata.poSwathMetadata->osSwathName);
    1485           8 :             for (const auto &dim : groupDims)
    1486             :             {
    1487           6 :                 oMap[dim->GetName()] = dim;
    1488             :             }
    1489           6 :             for (const auto &oDim : oSwathGeolocationFieldMetadata.aoDimensions)
    1490             :             {
    1491           4 :                 auto oIter = oMap.find(oDim.osName);
    1492             :                 // HDF5EOSParser guarantees that
    1493           4 :                 CPLAssert(oIter != oMap.end());
    1494           4 :                 const auto &poDim = oIter->second;
    1495           4 :                 m_dims.emplace_back(poDim);
    1496             :             }
    1497           2 :             return;
    1498             :         }
    1499             : 
    1500             :         // Special case for S100-family of products (S102, S104, S111)
    1501          27 :         const auto SpecialCaseS100 = [&](const std::string &osCoverageName)
    1502             :         {
    1503          54 :             auto poRootGroup = m_poShared->GetRootGroup();
    1504          27 :             if (poRootGroup)
    1505             :             {
    1506          27 :                 m_poSRS = std::make_shared<OGRSpatialReference>();
    1507          27 :                 if (S100ReadSRS(poRootGroup.get(), *(m_poSRS.get())))
    1508             :                 {
    1509          27 :                     if (m_poSRS->GetDataAxisToSRSAxisMapping() ==
    1510          54 :                         std::vector<int>{2, 1})
    1511          27 :                         m_poSRS->SetDataAxisToSRSAxisMapping({1, 2});
    1512             :                     else
    1513           0 :                         m_poSRS->SetDataAxisToSRSAxisMapping({2, 1});
    1514             :                 }
    1515             :                 else
    1516             :                 {
    1517           0 :                     m_poSRS.reset();
    1518             :                 }
    1519             : 
    1520             :                 auto poCoverage =
    1521          27 :                     poRootGroup->OpenGroupFromFullname(osCoverageName);
    1522          27 :                 if (poCoverage)
    1523             :                 {
    1524          27 :                     std::vector<std::shared_ptr<GDALMDArray>> apoIndexingVars;
    1525          27 :                     if (S100GetDimensions(poCoverage.get(), m_dims,
    1526          27 :                                           apoIndexingVars) &&
    1527          27 :                         m_dims.size() == 2 &&
    1528          81 :                         m_dims[0]->GetSize() == anDimSizes[0] &&
    1529          27 :                         m_dims[1]->GetSize() == anDimSizes[1])
    1530             :                     {
    1531          81 :                         for (const auto &poIndexingVar : apoIndexingVars)
    1532          54 :                             m_poShared->KeepRef(poIndexingVar);
    1533          27 :                         return true;
    1534             :                     }
    1535             :                     else
    1536             :                     {
    1537           0 :                         m_dims.clear();
    1538             :                     }
    1539             :                 }
    1540             :             }
    1541           0 :             return false;
    1542         202 :         };
    1543             : 
    1544         254 :         if (nDims == 2 &&
    1545          52 :             GetFullName() ==
    1546             :                 "/BathymetryCoverage/BathymetryCoverage.01/Group_001/values")
    1547             :         {
    1548             :             // S102
    1549          18 :             if (SpecialCaseS100("/BathymetryCoverage/BathymetryCoverage.01"))
    1550          18 :                 return;
    1551             :         }
    1552         218 :         else if (nDims == 2 &&
    1553          34 :                  GetFullName() ==
    1554             :                      "/QualityOfSurvey/QualityOfSurvey.01/Group_001/values")
    1555             :         {
    1556             :             // S102
    1557           3 :             if (SpecialCaseS100("/QualityOfSurvey/QualityOfSurvey.01"))
    1558           3 :                 return;
    1559             :         }
    1560         212 :         else if (nDims == 2 &&
    1561          31 :                  STARTS_WITH(GetFullName().c_str(),
    1562         212 :                              "/WaterLevel/WaterLevel.01/") &&
    1563           3 :                  GetFullName().find("/values"))
    1564             :         {
    1565             :             // S104
    1566           3 :             if (SpecialCaseS100("/WaterLevel/WaterLevel.01"))
    1567           3 :                 return;
    1568             :         }
    1569         206 :         else if (nDims == 2 &&
    1570          28 :                  STARTS_WITH(GetFullName().c_str(),
    1571         206 :                              "/SurfaceCurrent/SurfaceCurrent.01/") &&
    1572           3 :                  GetFullName().find("/values"))
    1573             :         {
    1574             :             // S111
    1575           3 :             if (SpecialCaseS100("/SurfaceCurrent/SurfaceCurrent.01"))
    1576           3 :                 return;
    1577             :         }
    1578             :     }
    1579             : 
    1580         408 :     std::map<std::string, std::shared_ptr<GDALDimension>> oMapFullNameToDim;
    1581             :     // cppcheck-suppress knownConditionTrueFalse
    1582         204 :     if (poGroup && !mapDimIndexToDimFullName.empty())
    1583             :     {
    1584          58 :         auto groupDims = poGroup->GetDimensions();
    1585         174 :         for (const auto &dim : groupDims)
    1586             :         {
    1587         145 :             oMapFullNameToDim[dim->GetFullName()] = dim;
    1588             :         }
    1589             :     }
    1590             : 
    1591         478 :     for (int i = 0; i < nDims; ++i)
    1592             :     {
    1593         274 :         auto oIter = mapDimIndexToDimFullName.find(static_cast<size_t>(i));
    1594         274 :         if (oIter != mapDimIndexToDimFullName.end())
    1595             :         {
    1596          63 :             auto oIter2 = oMapFullNameToDim.find(oIter->second);
    1597          63 :             if (oIter2 != oMapFullNameToDim.end())
    1598             :             {
    1599          60 :                 m_dims.emplace_back(oIter2->second);
    1600          60 :                 continue;
    1601             :             }
    1602             : 
    1603           6 :             std::string osDimName(oIter->second);
    1604           3 :             auto nPos = osDimName.rfind('/');
    1605           3 :             if (nPos != std::string::npos)
    1606             :             {
    1607           1 :                 const std::string osDimParentName(osDimName.substr(0, nPos));
    1608           1 :                 osDimName = osDimName.substr(nPos + 1);
    1609             : 
    1610           2 :                 m_dims.emplace_back(std::make_shared<HDF5Dimension>(
    1611           2 :                     osDimParentName.empty() ? "/" : osDimParentName, osDimName,
    1612           3 :                     std::string(), std::string(), anDimSizes[i], m_poShared));
    1613             :             }
    1614             :             else
    1615             :             {
    1616           4 :                 m_dims.emplace_back(std::make_shared<GDALDimension>(
    1617           4 :                     std::string(), osDimName, std::string(), std::string(),
    1618           4 :                     anDimSizes[i]));
    1619             :             }
    1620             :         }
    1621             :         else
    1622             :         {
    1623         422 :             m_dims.emplace_back(std::make_shared<GDALDimension>(
    1624         422 :                 std::string(), CPLSPrintf("dim%d", i), std::string(),
    1625         633 :                 std::string(), anDimSizes[i]));
    1626             :         }
    1627             :     }
    1628             : }
    1629             : 
    1630             : /************************************************************************/
    1631             : /*                      GetCoordinateVariables()                        */
    1632             : /************************************************************************/
    1633             : 
    1634             : std::vector<std::shared_ptr<GDALMDArray>>
    1635           3 : HDF5Array::GetCoordinateVariables() const
    1636             : {
    1637           3 :     std::vector<std::shared_ptr<GDALMDArray>> ret;
    1638             : 
    1639           6 :     HDF5EOSParser::SwathDataFieldMetadata oSwathDataFieldMetadata;
    1640           3 :     const auto poHDF5EOSParser = m_poShared->GetHDF5EOSParser();
    1641             :     // Build a "classic" subdataset name from group and array names
    1642             :     const std::string osSubdatasetName(
    1643             :         "/" +
    1644           9 :         CPLString(GetFullName()).replaceAll("Data Fields", "Data_Fields"));
    1645           6 :     if (poHDF5EOSParser &&
    1646           3 :         poHDF5EOSParser->GetSwathDataFieldMetadata(osSubdatasetName.c_str(),
    1647           6 :                                                    oSwathDataFieldMetadata) &&
    1648           1 :         oSwathDataFieldMetadata.aoDimensions.size() == GetDimensionCount())
    1649             :     {
    1650           1 :         if (!oSwathDataFieldMetadata.osLongitudeSubdataset.empty() &&
    1651           1 :             oSwathDataFieldMetadata.nPixelOffset == 0 &&
    1652           1 :             oSwathDataFieldMetadata.nLineOffset == 0 &&
    1653           3 :             oSwathDataFieldMetadata.nPixelStep == 1 &&
    1654           1 :             oSwathDataFieldMetadata.nLineStep == 1)
    1655             :         {
    1656           2 :             auto poRootGroup = m_poShared->GetRootGroup();
    1657           1 :             if (poRootGroup)
    1658             :             {
    1659           1 :                 auto poLongitude = poRootGroup->OpenMDArrayFromFullname(
    1660           2 :                     CPLString(
    1661           0 :                         oSwathDataFieldMetadata.osLongitudeSubdataset.substr(1))
    1662             :                         .replaceAll("Geolocation_Fields",
    1663           4 :                                     "Geolocation Fields"));
    1664           1 :                 auto poLatitude = poRootGroup->OpenMDArrayFromFullname(
    1665           2 :                     CPLString(
    1666           0 :                         oSwathDataFieldMetadata.osLatitudeSubdataset.substr(1))
    1667             :                         .replaceAll("Geolocation_Fields",
    1668           4 :                                     "Geolocation Fields"));
    1669           1 :                 if (poLongitude && poLatitude)
    1670             :                 {
    1671           1 :                     ret.push_back(std::move(poLongitude));
    1672           1 :                     ret.push_back(std::move(poLatitude));
    1673             :                 }
    1674             :             }
    1675             :         }
    1676             :     }
    1677             : 
    1678           6 :     return ret;
    1679             : }
    1680             : 
    1681             : /************************************************************************/
    1682             : /*                          GetAttributesCallback()                     */
    1683             : /************************************************************************/
    1684             : 
    1685        4553 : herr_t HDF5Array::GetAttributesCallback(hid_t hArray, const char *pszObjName,
    1686             :                                         void *selfIn)
    1687             : {
    1688        4553 :     HDF5Array *self = static_cast<HDF5Array *>(selfIn);
    1689        4553 :     if (self->m_bShowAllAttributes ||
    1690        2593 :         (strcmp(pszObjName, "_Netcdf4Dimid") != 0 &&
    1691        2284 :          strcmp(pszObjName, "_Netcdf4Coordinates") != 0 &&
    1692        2281 :          strcmp(pszObjName, "CLASS") != 0 && strcmp(pszObjName, "NAME") != 0))
    1693             :     {
    1694        4053 :         if (EQUAL(pszObjName, "DIMENSION_LIST"))
    1695             :         {
    1696         384 :             self->m_bHasDimensionList = true;
    1697         384 :             if (!self->m_bShowAllAttributes)
    1698         254 :                 return 0;
    1699             :         }
    1700        3799 :         if (EQUAL(pszObjName, "DIMENSION_LABELS"))
    1701             :         {
    1702           9 :             self->m_bHasDimensionLabels = true;
    1703           9 :             if (!self->m_bShowAllAttributes)
    1704           6 :                 return 0;
    1705             :         }
    1706             : 
    1707        3793 :         hid_t hAttr = H5Aopen_name(hArray, pszObjName);
    1708        3793 :         if (hAttr > 0)
    1709             :         {
    1710        3793 :             auto attr(HDF5Attribute::Create(self->m_osGroupFullname,
    1711             :                                             self->GetFullName(), pszObjName,
    1712        7586 :                                             self->m_poShared, hAttr));
    1713        3793 :             if (attr)
    1714             :             {
    1715             :                 // Used by HDF5-EOS products
    1716          24 :                 if (EQUAL(pszObjName, "_FillValue") &&
    1717          48 :                     self->GetDataType().GetClass() == GEDTC_NUMERIC &&
    1718        3523 :                     attr->GetDataType().GetClass() == GEDTC_NUMERIC &&
    1719          24 :                     attr->GetDimensionCount() == 0)
    1720             :                 {
    1721          24 :                     auto oRawResult(attr->ReadAsRaw());
    1722          24 :                     if (oRawResult.data())
    1723             :                     {
    1724             :                         // Round-trip attribute value to target data type and back
    1725             :                         // to attribute data type to ensure there is no loss
    1726             :                         // Normally _FillValue data type should be the same
    1727             :                         // as the array one, but this is not always the case.
    1728             :                         // For example NASA GEDI L2B products have Float64
    1729             :                         // _FillValue for Float32 variables.
    1730          24 :                         self->m_abyNoData.resize(self->GetDataType().GetSize());
    1731          72 :                         GDALExtendedDataType::CopyValue(
    1732          24 :                             oRawResult.data(), attr->GetDataType(),
    1733          24 :                             self->m_abyNoData.data(), self->GetDataType());
    1734             :                         std::vector<GByte> abyTmp(
    1735          24 :                             attr->GetDataType().GetSize());
    1736          72 :                         GDALExtendedDataType::CopyValue(
    1737          24 :                             self->m_abyNoData.data(), self->GetDataType(),
    1738          24 :                             abyTmp.data(), attr->GetDataType());
    1739          24 :                         std::vector<GByte> abyOri;
    1740          24 :                         abyOri.assign(oRawResult.data(),
    1741          24 :                                       oRawResult.data() + oRawResult.size());
    1742          24 :                         if (abyOri == abyTmp)
    1743             :                         {
    1744          20 :                             if (!self->m_bShowAllAttributes)
    1745          14 :                                 return 0;
    1746             :                         }
    1747             :                         else
    1748             :                         {
    1749           4 :                             self->m_abyNoData.clear();
    1750           4 :                             if (!self->m_bWarnedNoData)
    1751             :                             {
    1752           2 :                                 self->m_bWarnedNoData = true;
    1753           2 :                                 char *pszVal = nullptr;
    1754           4 :                                 GDALExtendedDataType::CopyValue(
    1755           2 :                                     oRawResult.data(), attr->GetDataType(),
    1756             :                                     &pszVal,
    1757           4 :                                     GDALExtendedDataType::CreateString());
    1758           6 :                                 CPLError(CE_Warning, CPLE_AppDefined,
    1759             :                                          "Array %s: %s attribute value (%s) is "
    1760             :                                          "not in "
    1761             :                                          "the range of the "
    1762             :                                          "array data type (%s)",
    1763           2 :                                          self->GetName().c_str(), pszObjName,
    1764           2 :                                          pszVal ? pszVal : "(null)",
    1765             :                                          GDALGetDataTypeName(
    1766           2 :                                              self->GetDataType()
    1767             :                                                  .GetNumericDataType()));
    1768           2 :                                 CPLFree(pszVal);
    1769             :                             }
    1770             :                         }
    1771             :                     }
    1772             :                 }
    1773             : 
    1774          54 :                 if (EQUAL(pszObjName, "units") &&
    1775        3515 :                     attr->GetDataType().GetClass() == GEDTC_STRING &&
    1776          54 :                     attr->GetDimensionCount() == 0)
    1777             :                 {
    1778          54 :                     const char *pszStr = attr->ReadAsString();
    1779          54 :                     if (pszStr)
    1780             :                     {
    1781          54 :                         self->m_osUnit = pszStr;
    1782          54 :                         if (!self->m_bShowAllAttributes)
    1783          27 :                             return 0;
    1784             :                     }
    1785             :                 }
    1786             : 
    1787        3434 :                 self->m_oListAttributes.emplace_back(attr);
    1788             :             }
    1789             :         }
    1790             :     }
    1791        4252 :     return 0;
    1792             : }
    1793             : 
    1794             : /************************************************************************/
    1795             : /*                       GetAttributeFromAttributes()                   */
    1796             : /************************************************************************/
    1797             : 
    1798             : /** Possible fallback implementation for GetAttribute() using GetAttributes().
    1799             :  */
    1800             : std::shared_ptr<GDALAttribute>
    1801         994 : HDF5Array::GetAttribute(const std::string &osName) const
    1802             : {
    1803         994 :     const char *const apszOptions[] = {"SHOW_ALL=YES", nullptr};
    1804         994 :     if (!m_bShowAllAttributes)
    1805         921 :         GetAttributes(apszOptions);
    1806        2521 :     for (const auto &attr : m_oListAttributes)
    1807             :     {
    1808        1687 :         if (attr->GetName() == osName)
    1809         160 :             return attr;
    1810             :     }
    1811         834 :     return nullptr;
    1812             : }
    1813             : 
    1814             : /************************************************************************/
    1815             : /*                           GetAttributes()                            */
    1816             : /************************************************************************/
    1817             : 
    1818             : std::vector<std::shared_ptr<GDALAttribute>>
    1819        2042 : HDF5Array::GetAttributes(CSLConstList papszOptions) const
    1820             : {
    1821             :     HDF5_GLOBAL_LOCK();
    1822             : 
    1823        2042 :     m_oListAttributes.clear();
    1824        2042 :     m_bShowAllAttributes =
    1825        2042 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "SHOW_ALL", "NO"));
    1826        2042 :     H5Aiterate(m_hArray, nullptr, GetAttributesCallback,
    1827             :                const_cast<void *>(static_cast<const void *>(this)));
    1828        2042 :     return m_oListAttributes;
    1829             : }
    1830             : 
    1831             : /************************************************************************/
    1832             : /*                           GetBlockSize()                             */
    1833             : /************************************************************************/
    1834             : 
    1835          61 : std::vector<GUInt64> HDF5Array::GetBlockSize() const
    1836             : {
    1837             :     HDF5_GLOBAL_LOCK();
    1838             : 
    1839          61 :     const auto nDimCount = GetDimensionCount();
    1840          61 :     std::vector<GUInt64> res(nDimCount);
    1841          61 :     if (res.empty())
    1842           0 :         return res;
    1843             : 
    1844          61 :     const hid_t nListId = H5Dget_create_plist(m_hArray);
    1845          61 :     if (nListId > 0)
    1846             :     {
    1847          61 :         if (H5Pget_layout(nListId) == H5D_CHUNKED)
    1848             :         {
    1849           4 :             std::vector<hsize_t> anChunkDims(nDimCount);
    1850           2 :             const int nDimSize = H5Pget_chunk(
    1851           2 :                 nListId, static_cast<int>(nDimCount), &anChunkDims[0]);
    1852           2 :             if (static_cast<size_t>(nDimSize) == nDimCount)
    1853             :             {
    1854           6 :                 for (size_t i = 0; i < nDimCount; ++i)
    1855             :                 {
    1856           4 :                     res[i] = anChunkDims[i];
    1857             :                 }
    1858             :             }
    1859             :         }
    1860             : 
    1861          61 :         H5Pclose(nListId);
    1862             :     }
    1863             : 
    1864          61 :     return res;
    1865             : }
    1866             : 
    1867             : /************************************************************************/
    1868             : /*                         GetStructuralInfo()                          */
    1869             : /************************************************************************/
    1870             : 
    1871           3 : CSLConstList HDF5Array::GetStructuralInfo() const
    1872             : {
    1873           3 :     if (m_aosStructuralInfo.empty())
    1874             :     {
    1875             :         HDF5_GLOBAL_LOCK();
    1876           3 :         const hid_t nListId = H5Dget_create_plist(m_hArray);
    1877           3 :         if (nListId > 0)
    1878             :         {
    1879           3 :             const int nFilters = H5Pget_nfilters(nListId);
    1880           5 :             for (int i = 0; i < nFilters; ++i)
    1881             :             {
    1882           2 :                 unsigned int flags = 0;
    1883           2 :                 size_t cd_nelmts = 0;
    1884           2 :                 char szName[64 + 1] = {0};
    1885           2 :                 const auto eFilter = H5Pget_filter(
    1886             :                     nListId, i, &flags, &cd_nelmts, nullptr, 64, szName);
    1887           2 :                 if (eFilter == H5Z_FILTER_DEFLATE)
    1888             :                 {
    1889           1 :                     m_aosStructuralInfo.SetNameValue("COMPRESSION", "DEFLATE");
    1890             :                 }
    1891           1 :                 else if (eFilter == H5Z_FILTER_SZIP)
    1892             :                 {
    1893           0 :                     m_aosStructuralInfo.SetNameValue("COMPRESSION", "SZIP");
    1894             :                 }
    1895           1 :                 else if (eFilter == H5Z_FILTER_SHUFFLE)
    1896             :                 {
    1897           1 :                     m_aosStructuralInfo.SetNameValue("FILTER", "SHUFFLE");
    1898             :                 }
    1899             :                 else
    1900             :                 {
    1901           0 :                     CPLDebug("HDF5", "Filter used: %s", szName);
    1902             :                 }
    1903             :             }
    1904           3 :             H5Pclose(nListId);
    1905             :         }
    1906             :     }
    1907           3 :     return m_aosStructuralInfo.List();
    1908             : }
    1909             : 
    1910             : /************************************************************************/
    1911             : /*                           CopyBuffer()                               */
    1912             : /************************************************************************/
    1913             : 
    1914          23 : static void CopyBuffer(size_t nDims, const size_t *count,
    1915             :                        const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    1916             :                        const GDALExtendedDataType &bufferDataType,
    1917             :                        GByte *pabySrc, void *pDstBuffer)
    1918             : {
    1919          23 :     const size_t nBufferDataTypeSize(bufferDataType.GetSize());
    1920          46 :     std::vector<size_t> anStackCount(nDims);
    1921          46 :     std::vector<GByte *> pabySrcBufferStack(nDims + 1);
    1922          46 :     std::vector<GByte *> pabyDstBufferStack(nDims + 1);
    1923          46 :     std::vector<GPtrDiff_t> anSrcStride(nDims);
    1924          46 :     std::vector<size_t> anSrcOffset(nDims + 1);
    1925          23 :     size_t nCurStride = nBufferDataTypeSize;
    1926          70 :     for (size_t i = nDims; i > 0;)
    1927             :     {
    1928          47 :         --i;
    1929          47 :         anSrcStride[i] = arrayStep[i] > 0
    1930          47 :                              ? nCurStride
    1931          33 :                              : -static_cast<GPtrDiff_t>(nCurStride);
    1932          47 :         anSrcOffset[i] = arrayStep[i] > 0 ? 0 : (count[i] - 1) * nCurStride;
    1933          47 :         nCurStride *= count[i];
    1934             :     }
    1935          23 :     pabySrcBufferStack[0] = pabySrc + anSrcOffset[0];
    1936          23 :     pabyDstBufferStack[0] = static_cast<GByte *>(pDstBuffer);
    1937          23 :     size_t iDim = 0;
    1938         168 : lbl_next_depth:
    1939         168 :     if (iDim == nDims)
    1940             :     {
    1941         104 :         memcpy(pabyDstBufferStack[nDims], pabySrcBufferStack[nDims],
    1942             :                nBufferDataTypeSize);
    1943             :     }
    1944             :     else
    1945             :     {
    1946          64 :         anStackCount[iDim] = count[iDim];
    1947             :         while (true)
    1948             :         {
    1949         145 :             ++iDim;
    1950         290 :             pabySrcBufferStack[iDim] =
    1951         145 :                 pabySrcBufferStack[iDim - 1] + anSrcOffset[iDim];
    1952         145 :             pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
    1953         145 :             goto lbl_next_depth;
    1954         145 :         lbl_return_to_caller_in_loop:
    1955         145 :             --iDim;
    1956         145 :             --anStackCount[iDim];
    1957         145 :             if (anStackCount[iDim] == 0)
    1958          64 :                 break;
    1959          81 :             pabyDstBufferStack[iDim] +=
    1960          81 :                 bufferStride[iDim] * nBufferDataTypeSize;
    1961          81 :             pabySrcBufferStack[iDim] += anSrcStride[iDim];
    1962             :         }
    1963             :     }
    1964         168 :     if (iDim > 0)
    1965         145 :         goto lbl_return_to_caller_in_loop;
    1966          23 : }
    1967             : 
    1968             : /************************************************************************/
    1969             : /*                             ReadSlow()                               */
    1970             : /************************************************************************/
    1971             : 
    1972          28 : bool HDF5Array::ReadSlow(const GUInt64 *arrayStartIdx, const size_t *count,
    1973             :                          const GInt64 *arrayStep,
    1974             :                          const GPtrDiff_t *bufferStride,
    1975             :                          const GDALExtendedDataType &bufferDataType,
    1976             :                          void *pDstBuffer) const
    1977             : {
    1978          28 :     const size_t nBufferDataTypeSize(bufferDataType.GetSize());
    1979          28 :     if (nBufferDataTypeSize == 0)
    1980           0 :         return false;
    1981          28 :     const size_t nDims(m_dims.size());
    1982          28 :     size_t nEltCount = 1;
    1983          85 :     for (size_t i = 0; i < nDims; ++i)
    1984             :     {
    1985          57 :         nEltCount *= count[i];
    1986             :     }
    1987             : 
    1988             :     // Only for testing
    1989             :     const char *pszThreshold =
    1990          28 :         CPLGetConfigOption("GDAL_HDF5_TEMP_ARRAY_ALLOC_SIZE", "16777216");
    1991             :     const GUIntBig nThreshold =
    1992          28 :         CPLScanUIntBig(pszThreshold, static_cast<int>(strlen(pszThreshold)));
    1993          28 :     if (nEltCount == 1 || nEltCount <= nThreshold / nBufferDataTypeSize)
    1994             :     {
    1995          23 :         CPLDebug("HDF5", "Using slow path");
    1996          46 :         std::vector<GByte> abyTemp;
    1997             :         try
    1998             :         {
    1999          23 :             abyTemp.resize(nEltCount * nBufferDataTypeSize);
    2000             :         }
    2001           0 :         catch (const std::exception &e)
    2002             :         {
    2003           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
    2004           0 :             return false;
    2005             :         }
    2006          46 :         std::vector<GUInt64> anStart(nDims);
    2007          46 :         std::vector<GInt64> anStep(nDims);
    2008          70 :         for (size_t i = 0; i < nDims; i++)
    2009             :         {
    2010          47 :             if (arrayStep[i] >= 0)
    2011             :             {
    2012          15 :                 anStart[i] = arrayStartIdx[i];
    2013          15 :                 anStep[i] = arrayStep[i];
    2014             :             }
    2015             :             else
    2016             :             {
    2017             :                 // Use double negation so that operations occur only on
    2018             :                 // positive quantities to avoid an artificial negative signed
    2019             :                 // integer to unsigned conversion.
    2020          64 :                 anStart[i] =
    2021          32 :                     arrayStartIdx[i] - ((-arrayStep[i]) * (count[i] - 1));
    2022          32 :                 anStep[i] = -arrayStep[i];
    2023             :             }
    2024             :         }
    2025          46 :         std::vector<GPtrDiff_t> anStride(nDims);
    2026          23 :         size_t nCurStride = 1;
    2027          70 :         for (size_t i = nDims; i > 0;)
    2028             :         {
    2029          47 :             --i;
    2030          47 :             anStride[i] = nCurStride;
    2031          47 :             nCurStride *= count[i];
    2032             :         }
    2033          23 :         if (!IRead(anStart.data(), count, anStep.data(), anStride.data(),
    2034          23 :                    bufferDataType, &abyTemp[0]))
    2035             :         {
    2036           0 :             return false;
    2037             :         }
    2038          23 :         CopyBuffer(nDims, count, arrayStep, bufferStride, bufferDataType,
    2039          23 :                    &abyTemp[0], pDstBuffer);
    2040          23 :         return true;
    2041             :     }
    2042             : 
    2043          10 :     std::vector<GUInt64> arrayStartIdxHalf;
    2044          10 :     std::vector<size_t> countHalf;
    2045           5 :     size_t iDimToSplit = nDims;
    2046             :     // Find the first dimension that has at least 2 elements, to split along
    2047             :     // it
    2048          15 :     for (size_t i = 0; i < nDims; ++i)
    2049             :     {
    2050          10 :         arrayStartIdxHalf.push_back(arrayStartIdx[i]);
    2051          10 :         countHalf.push_back(count[i]);
    2052          10 :         if (count[i] >= 2 && iDimToSplit == nDims)
    2053             :         {
    2054           5 :             iDimToSplit = i;
    2055             :         }
    2056             :     }
    2057             : 
    2058           5 :     CPLAssert(iDimToSplit != nDims);
    2059             : 
    2060           5 :     countHalf[iDimToSplit] /= 2;
    2061           5 :     if (!ReadSlow(arrayStartIdxHalf.data(), countHalf.data(), arrayStep,
    2062             :                   bufferStride, bufferDataType, pDstBuffer))
    2063             :     {
    2064           0 :         return false;
    2065             :     }
    2066           5 :     arrayStartIdxHalf[iDimToSplit] = static_cast<GUInt64>(
    2067           5 :         arrayStep[iDimToSplit] > 0
    2068           0 :             ? arrayStartIdx[iDimToSplit] +
    2069           0 :                   arrayStep[iDimToSplit] * countHalf[iDimToSplit]
    2070           5 :             : arrayStartIdx[iDimToSplit] -
    2071           5 :                   (-arrayStep[iDimToSplit]) * countHalf[iDimToSplit]);
    2072             :     GByte *pOtherHalfDstBuffer =
    2073          10 :         static_cast<GByte *>(pDstBuffer) + bufferStride[iDimToSplit] *
    2074           5 :                                                countHalf[iDimToSplit] *
    2075           5 :                                                nBufferDataTypeSize;
    2076           5 :     countHalf[iDimToSplit] = count[iDimToSplit] - countHalf[iDimToSplit];
    2077           5 :     return ReadSlow(arrayStartIdxHalf.data(), countHalf.data(), arrayStep,
    2078           5 :                     bufferStride, bufferDataType, pOtherHalfDstBuffer);
    2079             : }
    2080             : 
    2081             : /************************************************************************/
    2082             : /*                       IngestVariableStrings()                        */
    2083             : /************************************************************************/
    2084             : 
    2085           1 : static void IngestVariableStrings(void *pDstBuffer, hid_t hBufferType,
    2086             :                                   size_t nDims, const size_t *count,
    2087             :                                   const GPtrDiff_t *bufferStride)
    2088             : {
    2089           2 :     std::vector<hsize_t> anCountOne(nDims, 1);
    2090             :     const hid_t hMemSpaceOne =
    2091           1 :         nDims == 0 ? H5Screate(H5S_SCALAR)
    2092           1 :                    : H5Screate_simple(static_cast<int>(nDims),
    2093           1 :                                       anCountOne.data(), nullptr);
    2094           2 :     std::vector<size_t> anStackCount(nDims);
    2095           2 :     std::vector<GByte *> pabyDstBufferStack(nDims + 1);
    2096           1 :     pabyDstBufferStack[0] = static_cast<GByte *>(pDstBuffer);
    2097           1 :     size_t iDim = 0;
    2098           4 : lbl_next_depth:
    2099           4 :     if (iDim == nDims)
    2100             :     {
    2101           2 :         void *old_ptr = pabyDstBufferStack[nDims];
    2102           2 :         const char *pszSrcStr = *static_cast<char **>(old_ptr);
    2103           2 :         char *pszNewStr = pszSrcStr ? VSIStrdup(pszSrcStr) : nullptr;
    2104           2 :         H5Dvlen_reclaim(hBufferType, hMemSpaceOne, H5P_DEFAULT, old_ptr);
    2105           2 :         *static_cast<char **>(old_ptr) = pszNewStr;
    2106             :     }
    2107             :     else
    2108             :     {
    2109           2 :         anStackCount[iDim] = count[iDim];
    2110             :         while (true)
    2111             :         {
    2112           3 :             ++iDim;
    2113           3 :             pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
    2114           3 :             goto lbl_next_depth;
    2115           3 :         lbl_return_to_caller_in_loop:
    2116           3 :             --iDim;
    2117           3 :             --anStackCount[iDim];
    2118           3 :             if (anStackCount[iDim] == 0)
    2119           2 :                 break;
    2120           1 :             pabyDstBufferStack[iDim] += bufferStride[iDim] * sizeof(char *);
    2121             :         }
    2122             :     }
    2123           4 :     if (iDim > 0)
    2124           3 :         goto lbl_return_to_caller_in_loop;
    2125           1 :     H5Sclose(hMemSpaceOne);
    2126           1 : }
    2127             : 
    2128             : /************************************************************************/
    2129             : /*                    IngestFixedLengthStrings()                        */
    2130             : /************************************************************************/
    2131             : 
    2132           0 : static void IngestFixedLengthStrings(void *pDstBuffer, const void *pTemp,
    2133             :                                      hid_t hBufferType, size_t nDims,
    2134             :                                      const size_t *count,
    2135             :                                      const GPtrDiff_t *bufferStride)
    2136             : {
    2137           0 :     const size_t nStringSize = H5Tget_size(hBufferType);
    2138           0 :     std::vector<size_t> anStackCount(nDims);
    2139           0 :     std::vector<GByte *> pabyDstBufferStack(nDims + 1);
    2140           0 :     const GByte *pabySrcBuffer = static_cast<const GByte *>(pTemp);
    2141           0 :     pabyDstBufferStack[0] = static_cast<GByte *>(pDstBuffer);
    2142           0 :     size_t iDim = 0;
    2143           0 :     const bool bSpacePad = H5Tget_strpad(hBufferType) == H5T_STR_SPACEPAD;
    2144           0 : lbl_next_depth:
    2145           0 :     if (iDim == nDims)
    2146             :     {
    2147           0 :         char *pszStr = static_cast<char *>(VSIMalloc(nStringSize + 1));
    2148           0 :         if (pszStr)
    2149             :         {
    2150           0 :             memcpy(pszStr, pabySrcBuffer, nStringSize);
    2151           0 :             size_t nIter = nStringSize;
    2152           0 :             if (bSpacePad)
    2153             :             {
    2154           0 :                 while (nIter >= 1 && pszStr[nIter - 1] == ' ')
    2155             :                 {
    2156           0 :                     nIter--;
    2157             :                 }
    2158             :             }
    2159           0 :             pszStr[nIter] = 0;
    2160             :         }
    2161           0 :         void *ptr = pabyDstBufferStack[nDims];
    2162           0 :         *static_cast<char **>(ptr) = pszStr;
    2163             :     }
    2164             :     else
    2165             :     {
    2166           0 :         anStackCount[iDim] = count[iDim];
    2167             :         while (true)
    2168             :         {
    2169           0 :             ++iDim;
    2170           0 :             pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
    2171           0 :             goto lbl_next_depth;
    2172           0 :         lbl_return_to_caller_in_loop:
    2173           0 :             --iDim;
    2174           0 :             --anStackCount[iDim];
    2175           0 :             if (anStackCount[iDim] == 0)
    2176           0 :                 break;
    2177           0 :             pabyDstBufferStack[iDim] += bufferStride[iDim] * sizeof(char *);
    2178           0 :             pabySrcBuffer += nStringSize;
    2179             :         }
    2180             :     }
    2181           0 :     if (iDim > 0)
    2182           0 :         goto lbl_return_to_caller_in_loop;
    2183           0 : }
    2184             : 
    2185             : /************************************************************************/
    2186             : /*                   GetHDF5DataTypeFromGDALDataType()                  */
    2187             : /************************************************************************/
    2188             : 
    2189             : static hid_t
    2190         583 : GetHDF5DataTypeFromGDALDataType(const GDALExtendedDataType &dt, hid_t hNativeDT,
    2191             :                                 const GDALExtendedDataType &bufferDataType)
    2192             : {
    2193         583 :     hid_t hBufferType = H5I_INVALID_HID;
    2194         583 :     switch (bufferDataType.GetNumericDataType())
    2195             :     {
    2196          17 :         case GDT_Byte:
    2197          17 :             hBufferType = H5Tcopy(H5T_NATIVE_UCHAR);
    2198          17 :             break;
    2199           0 :         case GDT_Int8:
    2200           0 :             hBufferType = H5Tcopy(H5T_NATIVE_SCHAR);
    2201           0 :             break;
    2202          17 :         case GDT_UInt16:
    2203          17 :             hBufferType = H5Tcopy(H5T_NATIVE_USHORT);
    2204          17 :             break;
    2205           2 :         case GDT_Int16:
    2206           2 :             hBufferType = H5Tcopy(H5T_NATIVE_SHORT);
    2207           2 :             break;
    2208          13 :         case GDT_UInt32:
    2209          13 :             hBufferType = H5Tcopy(H5T_NATIVE_UINT);
    2210          13 :             break;
    2211         211 :         case GDT_Int32:
    2212         211 :             hBufferType = H5Tcopy(H5T_NATIVE_INT);
    2213         211 :             break;
    2214           1 :         case GDT_UInt64:
    2215           1 :             hBufferType = H5Tcopy(H5T_NATIVE_UINT64);
    2216           1 :             break;
    2217           2 :         case GDT_Int64:
    2218           2 :             hBufferType = H5Tcopy(H5T_NATIVE_INT64);
    2219           2 :             break;
    2220           0 :         case GDT_Float16:
    2221             : #ifdef HDF5_HAVE_FLOAT16
    2222             :             hBufferType = H5Tcopy(H5T_NATIVE_FLOAT16);
    2223             :             break;
    2224             : #else
    2225           0 :             return H5I_INVALID_HID;
    2226             : #endif
    2227          19 :         case GDT_Float32:
    2228          19 :             hBufferType = H5Tcopy(H5T_NATIVE_FLOAT);
    2229          19 :             break;
    2230         301 :         case GDT_Float64:
    2231         301 :             hBufferType = H5Tcopy(H5T_NATIVE_DOUBLE);
    2232         301 :             break;
    2233           0 :         case GDT_CInt16:
    2234             :         case GDT_CInt32:
    2235             :         case GDT_CFloat16:
    2236             :         case GDT_CFloat32:
    2237             :         case GDT_CFloat64:
    2238           0 :             if (bufferDataType != dt)
    2239             :             {
    2240           0 :                 return H5I_INVALID_HID;
    2241             :             }
    2242             :             else
    2243             :             {
    2244           0 :                 hBufferType = H5Tcopy(hNativeDT);
    2245           0 :                 break;
    2246             :             }
    2247           0 :         case GDT_Unknown:
    2248             :         case GDT_TypeCount:
    2249           0 :             return H5I_INVALID_HID;
    2250             :     }
    2251         583 :     return hBufferType;
    2252             : }
    2253             : 
    2254             : /************************************************************************/
    2255             : /*                        FreeDynamicMemory()                           */
    2256             : /************************************************************************/
    2257             : 
    2258         635 : static void FreeDynamicMemory(GByte *pabyPtr, hid_t hDataType)
    2259             : {
    2260         635 :     const auto klass = H5Tget_class(hDataType);
    2261         635 :     if (klass == H5T_STRING && H5Tis_variable_str(hDataType))
    2262             :     {
    2263           0 :         auto hDataSpace = H5Screate(H5S_SCALAR);
    2264           0 :         H5Dvlen_reclaim(hDataType, hDataSpace, H5P_DEFAULT, pabyPtr);
    2265           0 :         H5Sclose(hDataSpace);
    2266             :     }
    2267         635 :     else if (klass == H5T_COMPOUND)
    2268             :     {
    2269          95 :         const unsigned nMembers = H5Tget_nmembers(hDataType);
    2270         635 :         for (unsigned i = 0; i < nMembers; i++)
    2271             :         {
    2272         540 :             const auto nOffset = H5Tget_member_offset(hDataType, i);
    2273         540 :             auto hMemberType = H5Tget_member_type(hDataType, i);
    2274         540 :             if (hMemberType < 0)
    2275           0 :                 continue;
    2276         540 :             FreeDynamicMemory(pabyPtr + nOffset, hMemberType);
    2277         540 :             H5Tclose(hMemberType);
    2278             :         }
    2279             :     }
    2280         635 : }
    2281             : 
    2282             : /************************************************************************/
    2283             : /*                   CreateMapTargetComponentsToSrc()                   */
    2284             : /************************************************************************/
    2285             : 
    2286             : static std::vector<unsigned>
    2287         121 : CreateMapTargetComponentsToSrc(hid_t hSrcDataType,
    2288             :                                const GDALExtendedDataType &dstDataType)
    2289             : {
    2290         121 :     CPLAssert(H5Tget_class(hSrcDataType) == H5T_COMPOUND);
    2291         121 :     CPLAssert(dstDataType.GetClass() == GEDTC_COMPOUND);
    2292             : 
    2293         121 :     const unsigned nMembers = H5Tget_nmembers(hSrcDataType);
    2294         242 :     std::map<std::string, unsigned> oMapSrcCompNameToIdx;
    2295         710 :     for (unsigned i = 0; i < nMembers; i++)
    2296             :     {
    2297         589 :         char *pszName = H5Tget_member_name(hSrcDataType, i);
    2298         589 :         if (pszName)
    2299             :         {
    2300         589 :             oMapSrcCompNameToIdx[pszName] = i;
    2301         589 :             H5free_memory(pszName);
    2302             :         }
    2303             :     }
    2304             : 
    2305         121 :     std::vector<unsigned> ret;
    2306         121 :     const auto &comps = dstDataType.GetComponents();
    2307         121 :     ret.reserve(comps.size());
    2308         688 :     for (const auto &comp : comps)
    2309             :     {
    2310         567 :         auto oIter = oMapSrcCompNameToIdx.find(comp->GetName());
    2311         567 :         CPLAssert(oIter != oMapSrcCompNameToIdx.end());
    2312         567 :         ret.emplace_back(oIter->second);
    2313             :     }
    2314         242 :     return ret;
    2315             : }
    2316             : 
    2317             : /************************************************************************/
    2318             : /*                            CopyValue()                               */
    2319             : /************************************************************************/
    2320             : 
    2321        1676 : static void CopyValue(const GByte *pabySrcBuffer, hid_t hSrcDataType,
    2322             :                       GByte *pabyDstBuffer,
    2323             :                       const GDALExtendedDataType &dstDataType,
    2324             :                       const std::vector<unsigned> &mapDstCompsToSrcComps)
    2325             : {
    2326        1676 :     const auto klass = H5Tget_class(hSrcDataType);
    2327        1676 :     if (klass == H5T_STRING)
    2328             :     {
    2329         859 :         if (H5Tis_variable_str(hSrcDataType))
    2330             :         {
    2331         191 :             GDALExtendedDataType::CopyValue(
    2332         382 :                 pabySrcBuffer, GDALExtendedDataType::CreateString(),
    2333             :                 pabyDstBuffer, dstDataType);
    2334             :         }
    2335             :         else
    2336             :         {
    2337         668 :             size_t nStringSize = H5Tget_size(hSrcDataType);
    2338         668 :             char *pszStr = static_cast<char *>(VSIMalloc(nStringSize + 1));
    2339         668 :             if (pszStr)
    2340             :             {
    2341         668 :                 memcpy(pszStr, pabySrcBuffer, nStringSize);
    2342         668 :                 pszStr[nStringSize] = 0;
    2343             :             }
    2344         668 :             GDALExtendedDataType::CopyValue(
    2345        1336 :                 &pszStr, GDALExtendedDataType::CreateString(), pabyDstBuffer,
    2346             :                 dstDataType);
    2347         668 :             CPLFree(pszStr);
    2348             :         }
    2349             :     }
    2350         817 :     else if (klass == H5T_COMPOUND)
    2351             :     {
    2352          99 :         if (dstDataType.GetClass() != GEDTC_COMPOUND)
    2353             :         {
    2354           3 :             const auto eSrcDataType = ::HDF5Dataset::GetDataType(hSrcDataType);
    2355             :             // Typically source is complex data type
    2356             : #ifdef HDF5_HAVE_FLOAT16
    2357             :             if (eSrcDataType == GDT_CFloat32 &&
    2358             :                 ::HDF5Dataset::IsNativeCFloat16(hSrcDataType))
    2359             :             {
    2360             :                 if (dstDataType.GetNumericDataType() == GDT_CFloat32)
    2361             :                 {
    2362             :                     for (int j = 0; j <= 1; ++j)
    2363             :                     {
    2364             :                         uint16_t nVal16;
    2365             :                         memcpy(&nVal16, pabySrcBuffer + j * sizeof(nVal16),
    2366             :                                sizeof(nVal16));
    2367             :                         const uint32_t nVal32 = CPLHalfToFloat(nVal16);
    2368             :                         memcpy(pabyDstBuffer + j * sizeof(float), &nVal32,
    2369             :                                sizeof(nVal32));
    2370             :                     }
    2371             :                 }
    2372             :                 else if (dstDataType.GetNumericDataType() == GDT_CFloat64)
    2373             :                 {
    2374             :                     for (int j = 0; j <= 1; ++j)
    2375             :                     {
    2376             :                         uint16_t nVal16;
    2377             :                         memcpy(&nVal16, pabySrcBuffer + j * sizeof(nVal16),
    2378             :                                sizeof(nVal16));
    2379             :                         const uint32_t nVal32 = CPLHalfToFloat(nVal16);
    2380             :                         float fVal;
    2381             :                         memcpy(&fVal, &nVal32, sizeof(fVal));
    2382             :                         double dfVal = fVal;
    2383             :                         memcpy(pabyDstBuffer + j * sizeof(double), &dfVal,
    2384             :                                sizeof(dfVal));
    2385             :                     }
    2386             :                 }
    2387             :                 return;
    2388             :             }
    2389             : 
    2390             : #endif
    2391           6 :             auto srcDataType(GDALExtendedDataType::Create(eSrcDataType));
    2392           6 :             if (srcDataType.GetClass() == GEDTC_NUMERIC &&
    2393           3 :                 srcDataType.GetNumericDataType() != GDT_Unknown)
    2394             :             {
    2395           3 :                 GDALExtendedDataType::CopyValue(pabySrcBuffer, srcDataType,
    2396             :                                                 pabyDstBuffer, dstDataType);
    2397             :             }
    2398             :         }
    2399             :         else
    2400             :         {
    2401          96 :             const auto &comps = dstDataType.GetComponents();
    2402          96 :             CPLAssert(comps.size() == mapDstCompsToSrcComps.size());
    2403         638 :             for (size_t iDst = 0; iDst < comps.size(); ++iDst)
    2404             :             {
    2405         542 :                 const unsigned iSrc = mapDstCompsToSrcComps[iDst];
    2406         542 :                 auto hMemberType = H5Tget_member_type(hSrcDataType, iSrc);
    2407             :                 const std::vector<unsigned> mapDstSubCompsToSrcSubComps(
    2408         542 :                     (H5Tget_class(hMemberType) == H5T_COMPOUND &&
    2409           0 :                      comps[iDst]->GetType().GetClass() == GEDTC_COMPOUND)
    2410         542 :                         ? CreateMapTargetComponentsToSrc(hMemberType,
    2411           0 :                                                          comps[iDst]->GetType())
    2412        1084 :                         : std::vector<unsigned>());
    2413         542 :                 CopyValue(pabySrcBuffer +
    2414         542 :                               H5Tget_member_offset(hSrcDataType, iSrc),
    2415         542 :                           hMemberType, pabyDstBuffer + comps[iDst]->GetOffset(),
    2416         542 :                           comps[iDst]->GetType(), mapDstSubCompsToSrcSubComps);
    2417         542 :                 H5Tclose(hMemberType);
    2418             :             }
    2419             :         }
    2420             :     }
    2421         718 :     else if (klass == H5T_ENUM)
    2422             :     {
    2423           2 :         auto hParent = H5Tget_super(hSrcDataType);
    2424           2 :         CopyValue(pabySrcBuffer, hParent, pabyDstBuffer, dstDataType, {});
    2425           2 :         H5Tclose(hParent);
    2426             :     }
    2427             : #ifdef HDF5_HAVE_FLOAT16
    2428             :     else if (H5Tequal(hSrcDataType, H5T_NATIVE_FLOAT16))
    2429             :     {
    2430             :         uint16_t nVal16;
    2431             :         memcpy(&nVal16, pabySrcBuffer, sizeof(nVal16));
    2432             :         const uint32_t nVal32 = CPLHalfToFloat(nVal16);
    2433             :         float fVal;
    2434             :         memcpy(&fVal, &nVal32, sizeof(fVal));
    2435             :         GDALExtendedDataType::CopyValue(
    2436             :             &fVal, GDALExtendedDataType::Create(GDT_Float32), pabyDstBuffer,
    2437             :             dstDataType);
    2438             :     }
    2439             : #endif
    2440             :     else
    2441             :     {
    2442         716 :         GDALDataType eDT = ::HDF5Dataset::GetDataType(hSrcDataType);
    2443         716 :         GDALExtendedDataType::CopyValue(pabySrcBuffer,
    2444        1432 :                                         GDALExtendedDataType::Create(eDT),
    2445             :                                         pabyDstBuffer, dstDataType);
    2446             :     }
    2447        1676 : }
    2448             : 
    2449             : /************************************************************************/
    2450             : /*                        CopyToFinalBuffer()                           */
    2451             : /************************************************************************/
    2452             : 
    2453         120 : static void CopyToFinalBuffer(void *pDstBuffer, const void *pTemp, size_t nDims,
    2454             :                               const size_t *count,
    2455             :                               const GPtrDiff_t *bufferStride,
    2456             :                               hid_t hSrcDataType,
    2457             :                               const GDALExtendedDataType &bufferDataType)
    2458             : {
    2459         120 :     const size_t nSrcDataTypeSize(H5Tget_size(hSrcDataType));
    2460         240 :     std::vector<size_t> anStackCount(nDims);
    2461         240 :     std::vector<GByte *> pabyDstBufferStack(nDims + 1);
    2462         120 :     const GByte *pabySrcBuffer = static_cast<const GByte *>(pTemp);
    2463         120 :     pabyDstBufferStack[0] = static_cast<GByte *>(pDstBuffer);
    2464         120 :     size_t iDim = 0;
    2465             :     const std::vector<unsigned> mapDstCompsToSrcComps(
    2466         240 :         (H5Tget_class(hSrcDataType) == H5T_COMPOUND &&
    2467         120 :          bufferDataType.GetClass() == GEDTC_COMPOUND)
    2468         120 :             ? CreateMapTargetComponentsToSrc(hSrcDataType, bufferDataType)
    2469         240 :             : std::vector<unsigned>());
    2470             : 
    2471         120 :     bool bFastCopyOfCompoundToSingleComponentCompound = false;
    2472         120 :     GDALDataType eSrcTypeComp = GDT_Unknown;
    2473         120 :     size_t nSrcOffset = 0;
    2474         120 :     GDALDataType eDstTypeComp = GDT_Unknown;
    2475         120 :     int bufferStrideLastDim = 0;
    2476         145 :     if (nDims > 0 && mapDstCompsToSrcComps.size() == 1 &&
    2477          25 :         bufferDataType.GetComponents()[0]->GetType().GetClass() ==
    2478             :             GEDTC_NUMERIC)
    2479             :     {
    2480             :         auto hMemberType =
    2481          25 :             H5Tget_member_type(hSrcDataType, mapDstCompsToSrcComps[0]);
    2482          25 :         eSrcTypeComp = HDF5Dataset::GetDataType(hMemberType);
    2483          25 :         if (eSrcTypeComp != GDT_Unknown)
    2484             :         {
    2485             :             nSrcOffset =
    2486          25 :                 H5Tget_member_offset(hSrcDataType, mapDstCompsToSrcComps[0]);
    2487          25 :             eDstTypeComp = bufferDataType.GetComponents()[0]
    2488          25 :                                ->GetType()
    2489          25 :                                .GetNumericDataType();
    2490          50 :             bufferStrideLastDim = static_cast<int>(bufferStride[nDims - 1] *
    2491          25 :                                                    bufferDataType.GetSize());
    2492          25 :             bFastCopyOfCompoundToSingleComponentCompound = true;
    2493             :         }
    2494             :     }
    2495             : 
    2496          95 : lbl_next_depth:
    2497         259 :     if (bFastCopyOfCompoundToSingleComponentCompound && iDim == nDims - 1)
    2498             :     {
    2499          44 :         GDALCopyWords64(pabySrcBuffer + nSrcOffset, eSrcTypeComp,
    2500             :                         static_cast<int>(nSrcDataTypeSize),
    2501          44 :                         pabyDstBufferStack[iDim], eDstTypeComp,
    2502          44 :                         static_cast<int>(bufferStrideLastDim), count[iDim]);
    2503          44 :         pabySrcBuffer += count[iDim] * nSrcDataTypeSize;
    2504             :     }
    2505         215 :     else if (iDim == nDims)
    2506             :     {
    2507          95 :         CopyValue(pabySrcBuffer, hSrcDataType, pabyDstBufferStack[nDims],
    2508             :                   bufferDataType, mapDstCompsToSrcComps);
    2509          95 :         pabySrcBuffer += nSrcDataTypeSize;
    2510             :     }
    2511             :     else
    2512             :     {
    2513         120 :         anStackCount[iDim] = count[iDim];
    2514             :         while (true)
    2515             :         {
    2516         139 :             ++iDim;
    2517         139 :             pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
    2518         139 :             goto lbl_next_depth;
    2519         139 :         lbl_return_to_caller_in_loop:
    2520         139 :             --iDim;
    2521         139 :             --anStackCount[iDim];
    2522         139 :             if (anStackCount[iDim] == 0)
    2523         120 :                 break;
    2524          19 :             pabyDstBufferStack[iDim] +=
    2525          19 :                 bufferStride[iDim] * bufferDataType.GetSize();
    2526             :         }
    2527             :     }
    2528         259 :     if (iDim > 0)
    2529         139 :         goto lbl_return_to_caller_in_loop;
    2530         120 : }
    2531             : 
    2532             : /************************************************************************/
    2533             : /*                               IRead()                                */
    2534             : /************************************************************************/
    2535             : 
    2536         300 : bool HDF5Array::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
    2537             :                       const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    2538             :                       const GDALExtendedDataType &bufferDataType,
    2539             :                       void *pDstBuffer) const
    2540             : {
    2541             :     HDF5_GLOBAL_LOCK();
    2542             : 
    2543         300 :     const size_t nDims(m_dims.size());
    2544         600 :     std::vector<H5OFFSET_TYPE> anOffset(nDims);
    2545         600 :     std::vector<hsize_t> anCount(nDims);
    2546         600 :     std::vector<hsize_t> anStep(nDims);
    2547             : 
    2548         300 :     size_t nEltCount = 1;
    2549         677 :     for (size_t i = 0; i < nDims; ++i)
    2550             :     {
    2551         395 :         if (count[i] != 1 && (arrayStep[i] < 0 || bufferStride[i] < 0))
    2552             :         {
    2553          18 :             return ReadSlow(arrayStartIdx, count, arrayStep, bufferStride,
    2554          18 :                             bufferDataType, pDstBuffer);
    2555             :         }
    2556         377 :         anOffset[i] = static_cast<hsize_t>(arrayStartIdx[i]);
    2557         377 :         anCount[i] = static_cast<hsize_t>(count[i]);
    2558         377 :         anStep[i] = static_cast<hsize_t>(count[i] == 1 ? 1 : arrayStep[i]);
    2559         377 :         nEltCount *= count[i];
    2560             :     }
    2561             : 
    2562         282 :     if (IsTransposedRequest(count, bufferStride))
    2563             :     {
    2564         101 :         return ReadForTransposedRequest(arrayStartIdx, count, arrayStep,
    2565             :                                         bufferStride, bufferDataType,
    2566         101 :                                         pDstBuffer);
    2567             :     }
    2568             : 
    2569         181 :     hid_t hBufferType = H5I_INVALID_HID;
    2570         181 :     GByte *pabyTemp = nullptr;
    2571         181 :     if (m_dt.GetClass() == GEDTC_STRING)
    2572             :     {
    2573           1 :         if (bufferDataType.GetClass() != GEDTC_STRING)
    2574             :         {
    2575           0 :             return false;
    2576             :         }
    2577           1 :         hBufferType = H5Tcopy(m_hNativeDT);
    2578           1 :         if (!H5Tis_variable_str(m_hNativeDT))
    2579             :         {
    2580           0 :             const size_t nStringSize = H5Tget_size(m_hNativeDT);
    2581             :             pabyTemp = static_cast<GByte *>(
    2582           0 :                 VSI_MALLOC2_VERBOSE(nStringSize, nEltCount));
    2583           0 :             if (pabyTemp == nullptr)
    2584           0 :                 return false;
    2585             :         }
    2586             :     }
    2587         234 :     else if (bufferDataType.GetClass() == GEDTC_NUMERIC &&
    2588          54 :              m_dt.GetClass() == GEDTC_NUMERIC &&
    2589         283 :              !GDALDataTypeIsComplex(m_dt.GetNumericDataType()) &&
    2590          49 :              !GDALDataTypeIsComplex(bufferDataType.GetNumericDataType()))
    2591             :     {
    2592             :         // Compatibility with older libhdf5 that doesn't like requesting
    2593             :         // an enum to an integer
    2594          49 :         if (H5Tget_class(m_hNativeDT) == H5T_ENUM)
    2595             :         {
    2596           0 :             auto hParent = H5Tget_super(m_hNativeDT);
    2597           0 :             if (H5Tequal(hParent, H5T_NATIVE_UCHAR) ||
    2598           0 :                 H5Tequal(hParent, H5T_NATIVE_SCHAR) ||
    2599           0 :                 H5Tequal(hParent, H5T_NATIVE_USHORT) ||
    2600           0 :                 H5Tequal(hParent, H5T_NATIVE_SHORT) ||
    2601           0 :                 H5Tequal(hParent, H5T_NATIVE_UINT) ||
    2602           0 :                 H5Tequal(hParent, H5T_NATIVE_INT) ||
    2603           0 :                 H5Tequal(hParent, H5T_NATIVE_UINT64) ||
    2604           0 :                 H5Tequal(hParent, H5T_NATIVE_INT64))
    2605             :             {
    2606           0 :                 hBufferType = H5Tcopy(m_hNativeDT);
    2607           0 :                 if (m_dt != bufferDataType)
    2608             :                 {
    2609           0 :                     const size_t nDataTypeSize = H5Tget_size(m_hNativeDT);
    2610             :                     pabyTemp = static_cast<GByte *>(
    2611           0 :                         VSI_MALLOC2_VERBOSE(nDataTypeSize, nEltCount));
    2612           0 :                     if (pabyTemp == nullptr)
    2613             :                     {
    2614           0 :                         H5Tclose(hBufferType);
    2615           0 :                         return false;
    2616             :                     }
    2617             :                 }
    2618             :             }
    2619           0 :             H5Tclose(hParent);
    2620             :         }
    2621          49 :         if (hBufferType == H5I_INVALID_HID)
    2622             :         {
    2623          49 :             hBufferType = GetHDF5DataTypeFromGDALDataType(m_dt, m_hNativeDT,
    2624             :                                                           bufferDataType);
    2625          49 :             if (hBufferType == H5I_INVALID_HID)
    2626             :             {
    2627           0 :                 VSIFree(pabyTemp);
    2628           0 :                 return false;
    2629             :             }
    2630             :         }
    2631             :     }
    2632             :     else
    2633             :     {
    2634         131 :         hBufferType = H5Tcopy(m_hNativeDT);
    2635         131 :         if (m_dt != bufferDataType || m_bHasString || m_bHasNonNativeDataType)
    2636             :         {
    2637         120 :             const size_t nDataTypeSize = H5Tget_size(m_hNativeDT);
    2638             :             pabyTemp = static_cast<GByte *>(
    2639         120 :                 VSI_MALLOC2_VERBOSE(nDataTypeSize, nEltCount));
    2640         120 :             if (pabyTemp == nullptr)
    2641             :             {
    2642           0 :                 H5Tclose(hBufferType);
    2643           0 :                 return false;
    2644             :             }
    2645             :         }
    2646             :     }
    2647             : 
    2648             :     // Select block from file space.
    2649             :     herr_t status;
    2650         181 :     if (nDims)
    2651             :     {
    2652             :         status =
    2653         179 :             H5Sselect_hyperslab(m_hDataSpace, H5S_SELECT_SET, anOffset.data(),
    2654         179 :                                 anStep.data(), anCount.data(), nullptr);
    2655         179 :         if (status < 0)
    2656             :         {
    2657           0 :             H5Tclose(hBufferType);
    2658           0 :             VSIFree(pabyTemp);
    2659           0 :             return false;
    2660             :         }
    2661             :     }
    2662             : 
    2663             :     // Create memory data space
    2664             :     const hid_t hMemSpace = nDims == 0
    2665         181 :                                 ? H5Screate(H5S_SCALAR)
    2666         179 :                                 : H5Screate_simple(static_cast<int>(nDims),
    2667         179 :                                                    anCount.data(), nullptr);
    2668         181 :     if (nDims)
    2669             :     {
    2670         179 :         std::vector<H5OFFSET_TYPE> anMemOffset(nDims);
    2671             :         status =
    2672         179 :             H5Sselect_hyperslab(hMemSpace, H5S_SELECT_SET, anMemOffset.data(),
    2673         179 :                                 nullptr, anCount.data(), nullptr);
    2674         179 :         if (status < 0)
    2675             :         {
    2676           0 :             H5Tclose(hBufferType);
    2677           0 :             H5Sclose(hMemSpace);
    2678           0 :             VSIFree(pabyTemp);
    2679           0 :             return false;
    2680             :         }
    2681             :     }
    2682             : 
    2683         181 :     status = H5Dread(m_hArray, hBufferType, hMemSpace, m_hDataSpace,
    2684             :                      H5P_DEFAULT, pabyTemp ? pabyTemp : pDstBuffer);
    2685             : 
    2686         181 :     if (status >= 0)
    2687             :     {
    2688         181 :         if (H5Tis_variable_str(hBufferType))
    2689             :         {
    2690           1 :             IngestVariableStrings(pDstBuffer, hBufferType, nDims, count,
    2691             :                                   bufferStride);
    2692             :         }
    2693         180 :         else if (pabyTemp && bufferDataType.GetClass() == GEDTC_STRING)
    2694             :         {
    2695           0 :             IngestFixedLengthStrings(pDstBuffer, pabyTemp, hBufferType, nDims,
    2696             :                                      count, bufferStride);
    2697             :         }
    2698         180 :         else if (pabyTemp)
    2699             :         {
    2700         120 :             CopyToFinalBuffer(pDstBuffer, pabyTemp, nDims, count, bufferStride,
    2701         120 :                               m_hNativeDT, bufferDataType);
    2702             : 
    2703         120 :             if (m_bHasString)
    2704             :             {
    2705          95 :                 const size_t nBufferTypeSize = H5Tget_size(hBufferType);
    2706          95 :                 GByte *pabyPtr = pabyTemp;
    2707         190 :                 for (size_t i = 0; i < nEltCount; ++i)
    2708             :                 {
    2709          95 :                     FreeDynamicMemory(pabyPtr, hBufferType);
    2710          95 :                     pabyPtr += nBufferTypeSize;
    2711             :                 }
    2712             :             }
    2713             :         }
    2714             :     }
    2715             : 
    2716         181 :     H5Tclose(hBufferType);
    2717         181 :     H5Sclose(hMemSpace);
    2718         181 :     VSIFree(pabyTemp);
    2719             : 
    2720         181 :     return status >= 0;
    2721             : }
    2722             : 
    2723             : /************************************************************************/
    2724             : /*                           ~HDF5Attribute()                           */
    2725             : /************************************************************************/
    2726             : 
    2727       23986 : HDF5Attribute::~HDF5Attribute()
    2728             : {
    2729             :     HDF5_GLOBAL_LOCK();
    2730             : 
    2731       11993 :     if (m_hAttribute > 0)
    2732       11993 :         H5Aclose(m_hAttribute);
    2733       11993 :     if (m_hNativeDT > 0)
    2734       11993 :         H5Tclose(m_hNativeDT);
    2735       11993 :     if (m_hDataSpace > 0)
    2736       11993 :         H5Sclose(m_hDataSpace);
    2737       23986 : }
    2738             : 
    2739             : /************************************************************************/
    2740             : /*                       CopyAllAttrValuesInto()                        */
    2741             : /************************************************************************/
    2742             : 
    2743        1011 : static void CopyAllAttrValuesInto(size_t nDims, const GUInt64 *arrayStartIdx,
    2744             :                                   const size_t *count, const GInt64 *arrayStep,
    2745             :                                   const GPtrDiff_t *bufferStride,
    2746             :                                   const GDALExtendedDataType &bufferDataType,
    2747             :                                   void *pDstBuffer, hid_t hSrcBufferType,
    2748             :                                   const void *pabySrcBuffer)
    2749             : {
    2750        1011 :     const size_t nBufferDataTypeSize(bufferDataType.GetSize());
    2751        1011 :     const size_t nSrcDataTypeSize(H5Tget_size(hSrcBufferType));
    2752        2022 :     std::vector<size_t> anStackCount(nDims);
    2753        2022 :     std::vector<const GByte *> pabySrcBufferStack(nDims + 1);
    2754        2022 :     std::vector<GByte *> pabyDstBufferStack(nDims + 1);
    2755             :     const std::vector<unsigned> mapDstCompsToSrcComps(
    2756        1015 :         (H5Tget_class(hSrcBufferType) == H5T_COMPOUND &&
    2757           4 :          bufferDataType.GetClass() == GEDTC_COMPOUND)
    2758        1011 :             ? CreateMapTargetComponentsToSrc(hSrcBufferType, bufferDataType)
    2759        2022 :             : std::vector<unsigned>());
    2760             : 
    2761        1011 :     pabySrcBufferStack[0] = static_cast<const GByte *>(pabySrcBuffer);
    2762        1011 :     if (nDims > 0)
    2763          25 :         pabySrcBufferStack[0] += arrayStartIdx[0] * nSrcDataTypeSize;
    2764        1011 :     pabyDstBufferStack[0] = static_cast<GByte *>(pDstBuffer);
    2765        1011 :     size_t iDim = 0;
    2766        1062 : lbl_next_depth:
    2767        1062 :     if (iDim == nDims)
    2768             :     {
    2769        1037 :         CopyValue(pabySrcBufferStack[nDims], hSrcBufferType,
    2770        1037 :                   pabyDstBufferStack[nDims], bufferDataType,
    2771             :                   mapDstCompsToSrcComps);
    2772             :     }
    2773             :     else
    2774             :     {
    2775          25 :         anStackCount[iDim] = count[iDim];
    2776             :         while (true)
    2777             :         {
    2778          51 :             ++iDim;
    2779          51 :             pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
    2780          51 :             pabySrcBufferStack[iDim] = pabySrcBufferStack[iDim - 1];
    2781          51 :             if (iDim < nDims)
    2782             :             {
    2783           0 :                 pabySrcBufferStack[iDim] +=
    2784           0 :                     arrayStartIdx[iDim] * nSrcDataTypeSize;
    2785             :             }
    2786          51 :             goto lbl_next_depth;
    2787          51 :         lbl_return_to_caller_in_loop:
    2788          51 :             --iDim;
    2789          51 :             --anStackCount[iDim];
    2790          51 :             if (anStackCount[iDim] == 0)
    2791          25 :                 break;
    2792          26 :             pabyDstBufferStack[iDim] +=
    2793          26 :                 bufferStride[iDim] * nBufferDataTypeSize;
    2794          26 :             pabySrcBufferStack[iDim] += arrayStep[iDim] * nSrcDataTypeSize;
    2795             :         }
    2796             :     }
    2797        1062 :     if (iDim > 0)
    2798          51 :         goto lbl_return_to_caller_in_loop;
    2799        1011 : }
    2800             : 
    2801             : /************************************************************************/
    2802             : /*                               IRead()                                */
    2803             : /************************************************************************/
    2804             : 
    2805        1011 : bool HDF5Attribute::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
    2806             :                           const GInt64 *arrayStep,
    2807             :                           const GPtrDiff_t *bufferStride,
    2808             :                           const GDALExtendedDataType &bufferDataType,
    2809             :                           void *pDstBuffer) const
    2810             : {
    2811             :     HDF5_GLOBAL_LOCK();
    2812             : 
    2813        1011 :     const size_t nDims(m_dims.size());
    2814        1011 :     if (m_dt.GetClass() == GEDTC_STRING)
    2815             :     {
    2816         400 :         if (bufferDataType.GetClass() != GEDTC_STRING)
    2817             :         {
    2818           0 :             return false;
    2819             :         }
    2820             : 
    2821         400 :         if (!H5Tis_variable_str(m_hNativeDT))
    2822             :         {
    2823         216 :             const size_t nStringSize = H5Tget_size(m_hNativeDT);
    2824             :             GByte *pabyTemp = static_cast<GByte *>(
    2825         216 :                 VSI_CALLOC_VERBOSE(nStringSize, m_nElements));
    2826         216 :             if (pabyTemp == nullptr)
    2827           0 :                 return false;
    2828         432 :             if (H5Sget_simple_extent_type(m_hDataSpace) != H5S_NULL &&
    2829         216 :                 H5Aread(m_hAttribute, m_hNativeDT, pabyTemp) < 0)
    2830             :             {
    2831           0 :                 VSIFree(pabyTemp);
    2832           0 :                 return false;
    2833             :             }
    2834         216 :             CopyAllAttrValuesInto(nDims, arrayStartIdx, count, arrayStep,
    2835             :                                   bufferStride, bufferDataType, pDstBuffer,
    2836         216 :                                   m_hNativeDT, pabyTemp);
    2837         216 :             VSIFree(pabyTemp);
    2838             :         }
    2839             :         else
    2840             :         {
    2841         184 :             void *pabyTemp = VSI_CALLOC_VERBOSE(sizeof(char *), m_nElements);
    2842         184 :             if (pabyTemp == nullptr)
    2843           0 :                 return false;
    2844         368 :             if (H5Sget_simple_extent_type(m_hDataSpace) != H5S_NULL &&
    2845         184 :                 H5Aread(m_hAttribute, m_hNativeDT, pabyTemp) < 0)
    2846             :             {
    2847           0 :                 VSIFree(pabyTemp);
    2848           0 :                 return false;
    2849             :             }
    2850         184 :             CopyAllAttrValuesInto(nDims, arrayStartIdx, count, arrayStep,
    2851             :                                   bufferStride, bufferDataType, pDstBuffer,
    2852         184 :                                   m_hNativeDT, pabyTemp);
    2853         184 :             H5Dvlen_reclaim(m_hNativeDT, m_hDataSpace, H5P_DEFAULT, pabyTemp);
    2854         184 :             VSIFree(pabyTemp);
    2855             :         }
    2856         400 :         return true;
    2857             :     }
    2858             : 
    2859         611 :     hid_t hBufferType = H5I_INVALID_HID;
    2860        1221 :     if (m_dt.GetClass() == GEDTC_NUMERIC &&
    2861         610 :         bufferDataType.GetClass() == GEDTC_NUMERIC &&
    2862        1757 :         !GDALDataTypeIsComplex(m_dt.GetNumericDataType()) &&
    2863         536 :         !GDALDataTypeIsComplex(bufferDataType.GetNumericDataType()))
    2864             :     {
    2865             :         // Compatibility with older libhdf5 that doesn't like requesting
    2866             :         // an enum to an integer
    2867         536 :         if (H5Tget_class(m_hNativeDT) == H5T_ENUM)
    2868             :         {
    2869           2 :             auto hParent = H5Tget_super(m_hNativeDT);
    2870           2 :             if (H5Tequal(hParent, H5T_NATIVE_UCHAR) ||
    2871           1 :                 H5Tequal(hParent, H5T_NATIVE_SCHAR) ||
    2872           1 :                 H5Tequal(hParent, H5T_NATIVE_USHORT) ||
    2873           1 :                 H5Tequal(hParent, H5T_NATIVE_SHORT) ||
    2874           1 :                 H5Tequal(hParent, H5T_NATIVE_UINT) ||
    2875           1 :                 H5Tequal(hParent, H5T_NATIVE_INT) ||
    2876           3 :                 H5Tequal(hParent, H5T_NATIVE_UINT64) ||
    2877           0 :                 H5Tequal(hParent, H5T_NATIVE_INT64))
    2878             :             {
    2879           2 :                 hBufferType = H5Tcopy(m_hNativeDT);
    2880             :             }
    2881           2 :             H5Tclose(hParent);
    2882             :         }
    2883         536 :         if (hBufferType == H5I_INVALID_HID)
    2884             :         {
    2885         534 :             hBufferType = GetHDF5DataTypeFromGDALDataType(m_dt, m_hNativeDT,
    2886             :                                                           bufferDataType);
    2887             :         }
    2888             :     }
    2889             :     else
    2890             :     {
    2891          75 :         hBufferType = H5Tcopy(m_hNativeDT);
    2892             :     }
    2893             : 
    2894         611 :     if (hBufferType == H5I_INVALID_HID)
    2895           0 :         return false;
    2896             : 
    2897         611 :     const size_t nBufferTypeSize(H5Tget_size(hBufferType));
    2898             :     GByte *pabyTemp =
    2899         611 :         static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBufferTypeSize, m_nElements));
    2900         611 :     if (pabyTemp == nullptr)
    2901             :     {
    2902           0 :         H5Tclose(hBufferType);
    2903           0 :         return false;
    2904             :     }
    2905         611 :     if (H5Aread(m_hAttribute, hBufferType, pabyTemp) < 0)
    2906             :     {
    2907           0 :         VSIFree(pabyTemp);
    2908           0 :         return false;
    2909             :     }
    2910         611 :     CopyAllAttrValuesInto(nDims, arrayStartIdx, count, arrayStep, bufferStride,
    2911             :                           bufferDataType, pDstBuffer, hBufferType, pabyTemp);
    2912         611 :     if (bufferDataType.GetClass() == GEDTC_COMPOUND && m_bHasString)
    2913             :     {
    2914           0 :         GByte *pabyPtr = pabyTemp;
    2915           0 :         for (size_t i = 0; i < m_nElements; ++i)
    2916             :         {
    2917           0 :             FreeDynamicMemory(pabyPtr, hBufferType);
    2918           0 :             pabyPtr += nBufferTypeSize;
    2919             :         }
    2920             :     }
    2921         611 :     VSIFree(pabyTemp);
    2922         611 :     H5Tclose(hBufferType);
    2923         611 :     return true;
    2924             : }
    2925             : 
    2926             : /************************************************************************/
    2927             : /*                         GetIndexingVariable()                        */
    2928             : /************************************************************************/
    2929             : 
    2930          12 : std::shared_ptr<GDALMDArray> HDF5Dimension::GetIndexingVariable() const
    2931             : {
    2932             :     HDF5_GLOBAL_LOCK();
    2933             : 
    2934          12 :     auto hGroup = H5Gopen(m_poShared->GetHDF5(), m_osGroupFullname.c_str());
    2935          12 :     if (hGroup >= 0)
    2936             :     {
    2937          12 :         auto hArray = H5Dopen(hGroup, GetName().c_str());
    2938          12 :         H5Gclose(hGroup);
    2939          12 :         if (hArray >= 0)
    2940             :         {
    2941          24 :             auto ar(HDF5Array::Create(m_osGroupFullname, GetName(), m_poShared,
    2942          24 :                                       hArray, nullptr, false));
    2943          36 :             auto attrName = ar->GetAttribute("NAME");
    2944          12 :             if (attrName && attrName->GetDataType().GetClass() == GEDTC_STRING)
    2945             :             {
    2946          12 :                 const char *pszName = attrName->ReadAsString();
    2947          12 :                 if (pszName &&
    2948          12 :                     STARTS_WITH(
    2949             :                         pszName,
    2950             :                         "This is a netCDF dimension but not a netCDF variable"))
    2951             :                 {
    2952           0 :                     return nullptr;
    2953             :                 }
    2954             :             }
    2955          12 :             return ar;
    2956             :         }
    2957             :     }
    2958           0 :     return nullptr;
    2959             : }
    2960             : 
    2961             : }  // namespace GDAL
    2962             : 
    2963             : /************************************************************************/
    2964             : /*                           OpenMultiDim()                             */
    2965             : /************************************************************************/
    2966             : 
    2967          28 : GDALDataset *HDF5Dataset::OpenMultiDim(GDALOpenInfo *poOpenInfo)
    2968             : {
    2969             :     HDF5_GLOBAL_LOCK();
    2970             : 
    2971          28 :     const char *pszFilename = STARTS_WITH(poOpenInfo->pszFilename, "HDF5:")
    2972           7 :                                   ? poOpenInfo->pszFilename + strlen("HDF5:")
    2973             :                                   : poOpenInfo->pszFilename;
    2974             : 
    2975             :     // Try opening the dataset.
    2976          28 :     auto hHDF5 = GDAL_HDF5Open(pszFilename);
    2977          28 :     if (hHDF5 < 0)
    2978             :     {
    2979           1 :         return nullptr;
    2980             :     }
    2981             : 
    2982          81 :     auto poSharedResources = GDAL::HDF5SharedResources::Create(pszFilename);
    2983          27 :     poSharedResources->m_hHDF5 = hHDF5;
    2984             : 
    2985          54 :     auto poGroup(OpenGroup(poSharedResources));
    2986          27 :     if (poGroup == nullptr)
    2987             :     {
    2988           0 :         return nullptr;
    2989             :     }
    2990             : 
    2991          27 :     auto poDS(new HDF5Dataset());
    2992          27 :     poDS->m_poRootGroup = std::move(poGroup);
    2993             : 
    2994          27 :     poDS->SetDescription(poOpenInfo->pszFilename);
    2995             : 
    2996             :     // Setup/check for pam .aux.xml.
    2997          27 :     poDS->TryLoadXML();
    2998             : 
    2999          27 :     return poDS;
    3000             : }
    3001             : 
    3002             : /************************************************************************/
    3003             : /*                            OpenGroup()                               */
    3004             : /************************************************************************/
    3005             : 
    3006         146 : std::shared_ptr<GDALGroup> HDF5Dataset::OpenGroup(
    3007             :     const std::shared_ptr<GDAL::HDF5SharedResources> &poSharedResources)
    3008             : {
    3009             :     HDF5_GLOBAL_LOCK();
    3010             : 
    3011         292 :     auto poGroup = poSharedResources->GetRootGroup();
    3012         146 :     if (!poGroup)
    3013           0 :         return nullptr;
    3014             : 
    3015         146 :     if (HDF5EOSParser::HasHDFEOS(poGroup->GetID()))
    3016             :     {
    3017           3 :         poSharedResources->m_poHDF5EOSParser =
    3018           6 :             std::make_unique<HDF5EOSParser>();
    3019           3 :         if (poSharedResources->m_poHDF5EOSParser->Parse(poGroup->GetID()))
    3020             :         {
    3021           3 :             CPLDebug("HDF5", "Successfully parsed HDFEOS metadata");
    3022             :         }
    3023             :         else
    3024             :         {
    3025           0 :             poSharedResources->m_poHDF5EOSParser.reset();
    3026             :         }
    3027             :     }
    3028             : 
    3029         146 :     return poGroup;
    3030             : }

Generated by: LCOV version 1.14