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

Generated by: LCOV version 1.14