LCOV - code coverage report
Current view: top level - frmts/hdf4 - hdf4multidim.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 739 1314 56.2 %
Date: 2024-11-21 22:18:42 Functions: 69 139 49.6 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  HDF4 read Driver
       4             :  * Author:   Even Rouault <even.rouault at spatialys.com>
       5             :  *
       6             :  ******************************************************************************
       7             :  * Copyright (c) 2019, Even Rouault <even.rouault at spatialys.com>
       8             :  *
       9             :  * SPDX-License-Identifier: MIT
      10             :  ****************************************************************************/
      11             : 
      12             : #include "hdf4dataset.h"
      13             : 
      14             : #include "hdf.h"
      15             : #include "mfhdf.h"
      16             : 
      17             : #include "HdfEosDef.h"
      18             : 
      19             : #include "cpl_string.h"
      20             : 
      21             : #include <algorithm>
      22             : #include <map>
      23             : #include <set>
      24             : 
      25             : #if defined(__clang__) || defined(_MSC_VER)
      26             : #define COMPILER_WARNS_ABOUT_ABSTRACT_VBASE_INIT
      27             : #endif
      28             : 
      29             : extern CPLMutex *hHDF4Mutex;
      30             : extern const char *const pszGDALSignature;
      31             : 
      32             : /************************************************************************/
      33             : /*                         HDF4SharedResources                          */
      34             : /************************************************************************/
      35             : 
      36             : class HDF4SharedResources
      37             : {
      38             :     friend class ::HDF4Dataset;
      39             :     int32 m_hSD = -1;
      40             :     std::string m_osFilename;
      41             :     CPLStringList m_aosOpenOptions;
      42             :     std::shared_ptr<GDALPamMultiDim> m_poPAM{};
      43             : 
      44             :   public:
      45             :     explicit HDF4SharedResources(const std::string &osFilename);
      46             :     ~HDF4SharedResources();
      47             : 
      48          65 :     int32 GetSDHandle() const
      49             :     {
      50          65 :         return m_hSD;
      51             :     }
      52             : 
      53          40 :     const std::string &GetFilename() const
      54             :     {
      55          40 :         return m_osFilename;
      56             :     }
      57             : 
      58           4 :     const char *FetchOpenOption(const char *pszName,
      59             :                                 const char *pszDefault) const
      60             :     {
      61           4 :         return m_aosOpenOptions.FetchNameValueDef(pszName, pszDefault);
      62             :     }
      63             : 
      64          10 :     const std::shared_ptr<GDALPamMultiDim> &GetPAM()
      65             :     {
      66          10 :         return m_poPAM;
      67             :     }
      68             : };
      69             : 
      70             : /************************************************************************/
      71             : /*                               HDF4Group                              */
      72             : /************************************************************************/
      73             : 
      74             : class HDF4SDSGroup;
      75             : 
      76             : class HDF4Group final : public GDALGroup
      77             : {
      78             :     std::shared_ptr<HDF4SharedResources> m_poShared;
      79             :     std::shared_ptr<HDF4SDSGroup> m_poGDALGroup{};
      80             : 
      81             :   protected:
      82             :     HDF4Group(const std::string &osParentName, const std::string &osName,
      83             :               const std::shared_ptr<HDF4SharedResources> &poShared);
      84             : 
      85             :   public:
      86             :     static std::shared_ptr<HDF4Group>
      87           6 :     Create(const std::string &osParentName, const std::string &osName,
      88             :            const std::shared_ptr<HDF4SharedResources> &poShared)
      89             :     {
      90             :         auto poGroup = std::shared_ptr<HDF4Group>(
      91           6 :             new HDF4Group(osParentName, osName, poShared));
      92           6 :         poGroup->SetSelf(poGroup);
      93           6 :         return poGroup;
      94             :     }
      95             : 
      96             :     std::vector<std::shared_ptr<GDALAttribute>>
      97             :     GetAttributes(CSLConstList papszOptions = nullptr) const override;
      98             : 
      99             :     std::vector<std::string>
     100             :     GetGroupNames(CSLConstList papszOptions) const override;
     101             :     std::shared_ptr<GDALGroup> OpenGroup(const std::string &osName,
     102             :                                          CSLConstList) const override;
     103             : 
     104             :     std::vector<std::shared_ptr<GDALDimension>>
     105             :     GetDimensions(CSLConstList papszOptions = nullptr) const override;
     106             : 
     107             :     std::vector<std::string>
     108             :     GetMDArrayNames(CSLConstList papszOptions) const override;
     109             :     std::shared_ptr<GDALMDArray>
     110             :     OpenMDArray(const std::string &osName,
     111             :                 CSLConstList papszOptions) const override;
     112             : };
     113             : 
     114             : /************************************************************************/
     115             : /*                         HDF4AbstractAttribute                        */
     116             : /************************************************************************/
     117             : 
     118             : class HDF4AbstractAttribute : public GDALAttribute
     119             : {
     120             :     std::shared_ptr<HDF4SharedResources> m_poShared;
     121             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
     122             :     GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_Unknown);
     123             :     int32 m_nValues = 0;
     124             : 
     125             :   protected:
     126             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
     127             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
     128             :                const GDALExtendedDataType &bufferDataType,
     129             :                void *pDstBuffer) const override;
     130             : 
     131             :   public:
     132             :     HDF4AbstractAttribute(const std::string &osParentName,
     133             :                           const std::string &osName,
     134             :                           const std::shared_ptr<HDF4SharedResources> &poShared,
     135             :                           int32 iNumType, int32 nValues);
     136             : 
     137             :     const std::vector<std::shared_ptr<GDALDimension>> &
     138          35 :     GetDimensions() const override
     139             :     {
     140          35 :         return m_dims;
     141             :     }
     142             : 
     143          26 :     const GDALExtendedDataType &GetDataType() const override
     144             :     {
     145          26 :         return m_dt;
     146             :     }
     147             : 
     148             :     virtual void ReadData(void *pDstBuffer) const = 0;
     149             : };
     150             : 
     151             : /************************************************************************/
     152             : /*                            HDF4SwathsHandle                          */
     153             : /************************************************************************/
     154             : 
     155             : struct HDF4SwathsHandle
     156             : {
     157             :     int32 m_handle;
     158             : 
     159           0 :     explicit HDF4SwathsHandle(int32 handle) : m_handle(handle)
     160             :     {
     161           0 :     }
     162             : 
     163           0 :     ~HDF4SwathsHandle()
     164           0 :     {
     165           0 :         CPLMutexHolderD(&hHDF4Mutex);
     166           0 :         SWclose(m_handle);
     167           0 :     }
     168             : };
     169             : 
     170             : /************************************************************************/
     171             : /*                            HDF4SwathHandle                           */
     172             : /************************************************************************/
     173             : 
     174             : struct HDF4SwathHandle
     175             : {
     176             :     std::shared_ptr<HDF4SwathsHandle> m_poSwathsHandle;
     177             :     int32 m_handle;
     178             : 
     179           0 :     explicit HDF4SwathHandle(
     180             :         const std::shared_ptr<HDF4SwathsHandle> &poSwathsHandle, int32 handle)
     181           0 :         : m_poSwathsHandle(poSwathsHandle), m_handle(handle)
     182             :     {
     183           0 :     }
     184             : 
     185           0 :     ~HDF4SwathHandle()
     186           0 :     {
     187           0 :         CPLMutexHolderD(&hHDF4Mutex);
     188           0 :         SWdetach(m_handle);
     189           0 :     }
     190             : };
     191             : 
     192             : /************************************************************************/
     193             : /*                            HDF4SwathsGroup                           */
     194             : /************************************************************************/
     195             : 
     196             : class HDF4SwathsGroup final : public GDALGroup
     197             : {
     198             :     std::shared_ptr<HDF4SharedResources> m_poShared;
     199             :     std::shared_ptr<HDF4SwathsHandle> m_poSwathsHandle;
     200             : 
     201             :   public:
     202           0 :     HDF4SwathsGroup(const std::string &osParentName, const std::string &osName,
     203             :                     const std::shared_ptr<HDF4SharedResources> &poShared,
     204             :                     const std::shared_ptr<HDF4SwathsHandle> &poSwathsHandle)
     205           0 :         : GDALGroup(osParentName, osName), m_poShared(poShared),
     206           0 :           m_poSwathsHandle(poSwathsHandle)
     207             :     {
     208           0 :     }
     209             : 
     210             :     std::vector<std::string>
     211             :     GetGroupNames(CSLConstList papszOptions) const override;
     212             :     std::shared_ptr<GDALGroup> OpenGroup(const std::string &osName,
     213             :                                          CSLConstList) const override;
     214             : };
     215             : 
     216             : /************************************************************************/
     217             : /*                            HDF4SwathGroup                            */
     218             : /************************************************************************/
     219             : 
     220             : class HDF4SwathGroup final : public GDALGroup
     221             : {
     222             :     std::shared_ptr<HDF4SharedResources> m_poShared;
     223             :     std::shared_ptr<HDF4SwathHandle> m_poSwathHandle;
     224             :     mutable std::vector<std::shared_ptr<GDALDimension>> m_dims{};
     225             : 
     226             :   public:
     227           0 :     HDF4SwathGroup(const std::string &osParentName, const std::string &osName,
     228             :                    const std::shared_ptr<HDF4SharedResources> &poShared,
     229             :                    const std::shared_ptr<HDF4SwathHandle> &poSwathHandle)
     230           0 :         : GDALGroup(osParentName, osName), m_poShared(poShared),
     231           0 :           m_poSwathHandle(poSwathHandle)
     232             :     {
     233           0 :     }
     234             : 
     235             :     std::vector<std::shared_ptr<GDALDimension>>
     236             :     GetDimensions(CSLConstList papszOptions = nullptr) const override;
     237             : 
     238             :     std::vector<std::shared_ptr<GDALAttribute>>
     239             :     GetAttributes(CSLConstList papszOptions = nullptr) const override;
     240             : 
     241             :     std::vector<std::string>
     242             :     GetGroupNames(CSLConstList papszOptions) const override;
     243             :     std::shared_ptr<GDALGroup> OpenGroup(const std::string &osName,
     244             :                                          CSLConstList) const override;
     245             : };
     246             : 
     247             : /************************************************************************/
     248             : /*                         HDF4SwathSubGroup                            */
     249             : /************************************************************************/
     250             : 
     251             : class HDF4SwathSubGroup final : public GDALGroup
     252             : {
     253             :     std::shared_ptr<HDF4SharedResources> m_poShared;
     254             :     std::shared_ptr<HDF4SwathHandle> m_poSwathHandle;
     255             :     int32 m_entryType;
     256             :     std::vector<std::shared_ptr<GDALDimension>> m_groupDims{};
     257             : 
     258             :   public:
     259           0 :     HDF4SwathSubGroup(
     260             :         const std::string &osParentName, const std::string &osName,
     261             :         const std::shared_ptr<HDF4SharedResources> &poShared,
     262             :         const std::shared_ptr<HDF4SwathHandle> &poSwathHandle, int32 entryType,
     263             :         const std::vector<std::shared_ptr<GDALDimension>> &groupDims)
     264           0 :         : GDALGroup(osParentName, osName), m_poShared(poShared),
     265             :           m_poSwathHandle(poSwathHandle), m_entryType(entryType),
     266           0 :           m_groupDims(groupDims)
     267             :     {
     268           0 :     }
     269             : 
     270             :     std::vector<std::string>
     271             :     GetMDArrayNames(CSLConstList papszOptions) const override;
     272             :     std::shared_ptr<GDALMDArray>
     273             :     OpenMDArray(const std::string &osName,
     274             :                 CSLConstList papszOptions) const override;
     275             : };
     276             : 
     277             : /************************************************************************/
     278             : /*                            HDF4SwathArray                            */
     279             : /************************************************************************/
     280             : 
     281             : class HDF4SwathArray final : public GDALPamMDArray
     282             : {
     283             :     std::shared_ptr<HDF4SharedResources> m_poShared;
     284             :     std::shared_ptr<HDF4SwathHandle> m_poSwathHandle;
     285             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
     286             :     GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_Unknown);
     287             :     mutable std::vector<GByte> m_abyNoData{};
     288             : 
     289             :   protected:
     290             :     HDF4SwathArray(
     291             :         const std::string &osParentName, const std::string &osName,
     292             :         const std::shared_ptr<HDF4SharedResources> &poShared,
     293             :         const std::shared_ptr<HDF4SwathHandle> &poSwathHandle,
     294             :         const std::vector<int32> &aiDimSizes, const std::string &dimNames,
     295             :         int32 iNumType,
     296             :         const std::vector<std::shared_ptr<GDALDimension>> &groupDims);
     297             : 
     298             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
     299             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
     300             :                const GDALExtendedDataType &bufferDataType,
     301             :                void *pDstBuffer) const override;
     302             : 
     303             :   public:
     304             :     static std::shared_ptr<HDF4SwathArray>
     305           0 :     Create(const std::string &osParentName, const std::string &osName,
     306             :            const std::shared_ptr<HDF4SharedResources> &poShared,
     307             :            const std::shared_ptr<HDF4SwathHandle> &poSwathHandle,
     308             :            const std::vector<int32> &aiDimSizes, const std::string &dimNames,
     309             :            int32 iNumType,
     310             :            const std::vector<std::shared_ptr<GDALDimension>> &groupDims)
     311             :     {
     312             :         auto ar(std::shared_ptr<HDF4SwathArray>(
     313             :             new HDF4SwathArray(osParentName, osName, poShared, poSwathHandle,
     314           0 :                                aiDimSizes, dimNames, iNumType, groupDims)));
     315           0 :         ar->SetSelf(ar);
     316           0 :         return ar;
     317             :     }
     318             : 
     319           0 :     bool IsWritable() const override
     320             :     {
     321           0 :         return false;
     322             :     }
     323             : 
     324           0 :     const std::string &GetFilename() const override
     325             :     {
     326           0 :         return m_poShared->GetFilename();
     327             :     }
     328             : 
     329             :     const std::vector<std::shared_ptr<GDALDimension>> &
     330           0 :     GetDimensions() const override
     331             :     {
     332           0 :         return m_dims;
     333             :     }
     334             : 
     335           0 :     const GDALExtendedDataType &GetDataType() const override
     336             :     {
     337           0 :         return m_dt;
     338             :     }
     339             : 
     340             :     std::vector<std::shared_ptr<GDALAttribute>>
     341             :     GetAttributes(CSLConstList papszOptions = nullptr) const override;
     342             : 
     343             :     const void *GetRawNoDataValue() const override;
     344             : };
     345             : 
     346             : /************************************************************************/
     347             : /*                            HDF4SDAttribute                             */
     348             : /************************************************************************/
     349             : 
     350             : class HDF4SwathAttribute final : public HDF4AbstractAttribute
     351             : {
     352             :     std::shared_ptr<HDF4SwathHandle> m_poSwathHandle;
     353             : 
     354             :   public:
     355           0 :     HDF4SwathAttribute(const std::string &osParentName,
     356             :                        const std::string &osName,
     357             :                        const std::shared_ptr<HDF4SharedResources> &poShared,
     358             :                        const std::shared_ptr<HDF4SwathHandle> &poSwathHandle,
     359             :                        int32 iNumType, int32 nValues)
     360           0 :         : GDALAbstractMDArray(osParentName, osName),
     361             :           HDF4AbstractAttribute(osParentName, osName, poShared, iNumType,
     362             :                                 nValues),
     363           0 :           m_poSwathHandle(poSwathHandle)
     364             :     {
     365           0 :     }
     366             : 
     367           0 :     void ReadData(void *pDstBuffer) const override
     368             :     {
     369           0 :         SWreadattr(m_poSwathHandle->m_handle, GetName().c_str(), pDstBuffer);
     370           0 :     }
     371             : };
     372             : 
     373             : /************************************************************************/
     374             : /*                             HDF4GDsHandle                             */
     375             : /************************************************************************/
     376             : 
     377             : struct HDF4GDsHandle
     378             : {
     379             :     int32 m_handle;
     380             : 
     381           0 :     explicit HDF4GDsHandle(int32 handle) : m_handle(handle)
     382             :     {
     383           0 :     }
     384             : 
     385           0 :     ~HDF4GDsHandle()
     386           0 :     {
     387           0 :         CPLMutexHolderD(&hHDF4Mutex);
     388           0 :         GDclose(m_handle);
     389           0 :     }
     390             : };
     391             : 
     392             : /************************************************************************/
     393             : /*                             HDF4GDHandle                             */
     394             : /************************************************************************/
     395             : 
     396             : struct HDF4GDHandle
     397             : {
     398             :     std::shared_ptr<HDF4GDsHandle> m_poGDsHandle;
     399             :     int32 m_handle;
     400             : 
     401           0 :     explicit HDF4GDHandle(const std::shared_ptr<HDF4GDsHandle> &poGDsHandle,
     402             :                           int32 handle)
     403           0 :         : m_poGDsHandle(poGDsHandle), m_handle(handle)
     404             :     {
     405           0 :     }
     406             : 
     407           0 :     ~HDF4GDHandle()
     408           0 :     {
     409           0 :         CPLMutexHolderD(&hHDF4Mutex);
     410           0 :         GDdetach(m_handle);
     411           0 :     }
     412             : };
     413             : 
     414             : /************************************************************************/
     415             : /*                          HDF4EOSGridsGroup                           */
     416             : /************************************************************************/
     417             : 
     418             : class HDF4EOSGridsGroup final : public GDALGroup
     419             : {
     420             :     std::shared_ptr<HDF4SharedResources> m_poShared;
     421             :     std::shared_ptr<HDF4GDsHandle> m_poGDsHandle;
     422             : 
     423             :   public:
     424           0 :     HDF4EOSGridsGroup(const std::string &osParentName,
     425             :                       const std::string &osName,
     426             :                       const std::shared_ptr<HDF4SharedResources> &poShared,
     427             :                       const std::shared_ptr<HDF4GDsHandle> &poGDsHandle)
     428           0 :         : GDALGroup(osParentName, osName), m_poShared(poShared),
     429           0 :           m_poGDsHandle(poGDsHandle)
     430             :     {
     431           0 :     }
     432             : 
     433             :     std::vector<std::string>
     434             :     GetGroupNames(CSLConstList papszOptions) const override;
     435             :     std::shared_ptr<GDALGroup> OpenGroup(const std::string &osName,
     436             :                                          CSLConstList) const override;
     437             : };
     438             : 
     439             : /************************************************************************/
     440             : /*                          HDF4EOSGridGroup                            */
     441             : /************************************************************************/
     442             : 
     443             : class HDF4EOSGridGroup final : public GDALGroup
     444             : {
     445             :     std::shared_ptr<HDF4SharedResources> m_poShared;
     446             :     std::shared_ptr<HDF4GDHandle> m_poGDHandle;
     447             :     mutable std::vector<std::shared_ptr<GDALDimension>> m_dims{};
     448             :     mutable std::shared_ptr<GDALMDArray> m_varX{};
     449             :     mutable std::shared_ptr<GDALMDArray> m_varY{};
     450             : 
     451             :   public:
     452           0 :     HDF4EOSGridGroup(const std::string &osParentName, const std::string &osName,
     453             :                      const std::shared_ptr<HDF4SharedResources> &poShared,
     454             :                      const std::shared_ptr<HDF4GDHandle> &poGDHandle)
     455           0 :         : GDALGroup(osParentName, osName), m_poShared(poShared),
     456           0 :           m_poGDHandle(poGDHandle)
     457             :     {
     458           0 :     }
     459             : 
     460             :     std::vector<std::shared_ptr<GDALDimension>>
     461             :     GetDimensions(CSLConstList papszOptions = nullptr) const override;
     462             : 
     463             :     std::vector<std::string>
     464             :     GetMDArrayNames(CSLConstList papszOptions) const override;
     465             :     std::shared_ptr<GDALMDArray>
     466             :     OpenMDArray(const std::string &osName,
     467             :                 CSLConstList papszOptions) const override;
     468             : 
     469             :     std::vector<std::string>
     470             :     GetGroupNames(CSLConstList papszOptions) const override;
     471             :     std::shared_ptr<GDALGroup> OpenGroup(const std::string &osName,
     472             :                                          CSLConstList) const override;
     473             : 
     474             :     std::vector<std::shared_ptr<GDALAttribute>>
     475             :     GetAttributes(CSLConstList papszOptions = nullptr) const override;
     476             : };
     477             : 
     478             : /************************************************************************/
     479             : /*                         HDF4EOSGridSubGroup                          */
     480             : /************************************************************************/
     481             : 
     482             : class HDF4EOSGridSubGroup final : public GDALGroup
     483             : {
     484             :     std::shared_ptr<HDF4SharedResources> m_poShared;
     485             :     std::shared_ptr<HDF4GDHandle> m_poGDHandle;
     486             :     int32 m_entryType;
     487             :     std::vector<std::shared_ptr<GDALDimension>> m_groupDims{};
     488             : 
     489             :   public:
     490           0 :     HDF4EOSGridSubGroup(
     491             :         const std::string &osParentName, const std::string &osName,
     492             :         const std::shared_ptr<HDF4SharedResources> &poShared,
     493             :         const std::shared_ptr<HDF4GDHandle> &poGDHandle, int32 entryType,
     494             :         const std::vector<std::shared_ptr<GDALDimension>> &groupDims)
     495           0 :         : GDALGroup(osParentName, osName), m_poShared(poShared),
     496             :           m_poGDHandle(poGDHandle), m_entryType(entryType),
     497           0 :           m_groupDims(groupDims)
     498             :     {
     499           0 :     }
     500             : 
     501             :     std::vector<std::string>
     502             :     GetMDArrayNames(CSLConstList papszOptions) const override;
     503             :     std::shared_ptr<GDALMDArray>
     504             :     OpenMDArray(const std::string &osName,
     505             :                 CSLConstList papszOptions) const override;
     506             : };
     507             : 
     508             : /************************************************************************/
     509             : /*                          HDF4EOSGridArray                            */
     510             : /************************************************************************/
     511             : 
     512             : class HDF4EOSGridArray final : public GDALPamMDArray
     513             : {
     514             :     std::shared_ptr<HDF4SharedResources> m_poShared;
     515             :     std::shared_ptr<HDF4GDHandle> m_poGDHandle;
     516             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
     517             :     GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_Unknown);
     518             :     mutable std::vector<GByte> m_abyNoData{};
     519             :     mutable std::string m_osUnit{};
     520             : 
     521             :   protected:
     522             :     HDF4EOSGridArray(
     523             :         const std::string &osParentName, const std::string &osName,
     524             :         const std::shared_ptr<HDF4SharedResources> &poShared,
     525             :         const std::shared_ptr<HDF4GDHandle> &poGDHandle,
     526             :         const std::vector<int32> &aiDimSizes, const std::string &dimNames,
     527             :         int32 iNumType,
     528             :         const std::vector<std::shared_ptr<GDALDimension>> &groupDims);
     529             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
     530             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
     531             :                const GDALExtendedDataType &bufferDataType,
     532             :                void *pDstBuffer) const override;
     533             : 
     534             :   public:
     535             :     static std::shared_ptr<HDF4EOSGridArray>
     536           0 :     Create(const std::string &osParentName, const std::string &osName,
     537             :            const std::shared_ptr<HDF4SharedResources> &poShared,
     538             :            const std::shared_ptr<HDF4GDHandle> &poGDHandle,
     539             :            const std::vector<int32> &aiDimSizes, const std::string &dimNames,
     540             :            int32 iNumType,
     541             :            const std::vector<std::shared_ptr<GDALDimension>> &groupDims)
     542             :     {
     543             :         auto ar(std::shared_ptr<HDF4EOSGridArray>(
     544             :             new HDF4EOSGridArray(osParentName, osName, poShared, poGDHandle,
     545           0 :                                  aiDimSizes, dimNames, iNumType, groupDims)));
     546           0 :         ar->SetSelf(ar);
     547           0 :         return ar;
     548             :     }
     549             : 
     550           0 :     bool IsWritable() const override
     551             :     {
     552           0 :         return false;
     553             :     }
     554             : 
     555           0 :     const std::string &GetFilename() const override
     556             :     {
     557           0 :         return m_poShared->GetFilename();
     558             :     }
     559             : 
     560             :     const std::vector<std::shared_ptr<GDALDimension>> &
     561           0 :     GetDimensions() const override
     562             :     {
     563           0 :         return m_dims;
     564             :     }
     565             : 
     566           0 :     const GDALExtendedDataType &GetDataType() const override
     567             :     {
     568           0 :         return m_dt;
     569             :     }
     570             : 
     571             :     std::vector<std::shared_ptr<GDALAttribute>>
     572             :     GetAttributes(CSLConstList papszOptions = nullptr) const override;
     573             : 
     574             :     const void *GetRawNoDataValue() const override;
     575             : 
     576             :     double GetOffset(bool *pbHasOffset = nullptr,
     577             :                      GDALDataType *peStorageType = nullptr) const override;
     578             : 
     579             :     double GetScale(bool *pbHasScale = nullptr,
     580             :                     GDALDataType *peStorageType = nullptr) const override;
     581             : 
     582             :     const std::string &GetUnit() const override;
     583             : 
     584             :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override;
     585             : 
     586           0 :     std::shared_ptr<GDALGroup> GetRootGroup() const override
     587             :     {
     588           0 :         return HDF4Group::Create(std::string(), "/", m_poShared);
     589             :     }
     590             : };
     591             : 
     592             : /************************************************************************/
     593             : /*                      HDF4EOSGridAttribute                            */
     594             : /************************************************************************/
     595             : 
     596             : class HDF4EOSGridAttribute final : public HDF4AbstractAttribute
     597             : {
     598             :     std::shared_ptr<HDF4GDHandle> m_poGDHandle;
     599             : 
     600             :   public:
     601           0 :     HDF4EOSGridAttribute(const std::string &osParentName,
     602             :                          const std::string &osName,
     603             :                          const std::shared_ptr<HDF4SharedResources> &poShared,
     604             :                          const std::shared_ptr<HDF4GDHandle> &poGDHandle,
     605             :                          int32 iNumType, int32 nValues)
     606           0 :         : GDALAbstractMDArray(osParentName, osName),
     607             :           HDF4AbstractAttribute(osParentName, osName, poShared, iNumType,
     608             :                                 nValues),
     609           0 :           m_poGDHandle(poGDHandle)
     610             :     {
     611           0 :     }
     612             : 
     613           0 :     void ReadData(void *pDstBuffer) const override
     614             :     {
     615           0 :         GDreadattr(m_poGDHandle->m_handle, GetName().c_str(), pDstBuffer);
     616           0 :     }
     617             : };
     618             : 
     619             : /************************************************************************/
     620             : /*                             HDF4SDSGroup                             */
     621             : /************************************************************************/
     622             : 
     623             : class HDF4SDSGroup final : public GDALGroup
     624             : {
     625             :     std::shared_ptr<HDF4SharedResources> m_poShared;
     626             :     mutable std::map<std::string, int> m_oMapNameToSDSIdx{};
     627             :     mutable std::vector<std::shared_ptr<GDALDimension>> m_dims{};
     628             :     mutable std::vector<std::shared_ptr<GDALMDArray>> m_oSetIndexingVariables{};
     629             :     mutable bool m_bInGetDimensions = false;
     630             :     bool m_bIsGDALDataset = false;
     631             :     std::vector<std::shared_ptr<GDALAttribute>> m_oGlobalAttributes{};
     632             :     mutable std::shared_ptr<GDALMDArray> m_varX{};
     633             :     mutable std::shared_ptr<GDALMDArray> m_varY{};
     634             : 
     635             :   public:
     636           4 :     HDF4SDSGroup(const std::string &osParentName, const std::string &osName,
     637             :                  const std::shared_ptr<HDF4SharedResources> &poShared)
     638           4 :         : GDALGroup(osParentName, osName), m_poShared(poShared)
     639             :     {
     640           4 :     }
     641             : 
     642           2 :     void SetIsGDALDataset()
     643             :     {
     644           2 :         m_bIsGDALDataset = true;
     645           2 :     }
     646             : 
     647           2 :     void SetGlobalAttributes(
     648             :         const std::vector<std::shared_ptr<GDALAttribute>> &attrs)
     649             :     {
     650           2 :         m_oGlobalAttributes = attrs;
     651           2 :     }
     652             : 
     653             :     std::vector<std::shared_ptr<GDALDimension>>
     654             :     GetDimensions(CSLConstList papszOptions = nullptr) const override;
     655             : 
     656             :     std::vector<std::string>
     657             :     GetMDArrayNames(CSLConstList papszOptions) const override;
     658             :     std::shared_ptr<GDALMDArray>
     659             :     OpenMDArray(const std::string &osName,
     660             :                 CSLConstList papszOptions) const override;
     661             : };
     662             : 
     663             : /************************************************************************/
     664             : /*                            HDF4SDSArray                              */
     665             : /************************************************************************/
     666             : 
     667             : class HDF4SDSArray final : public GDALPamMDArray
     668             : {
     669             :     std::shared_ptr<HDF4SharedResources> m_poShared;
     670             :     int32 m_iSDS;
     671             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
     672             :     GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_Unknown);
     673             :     int32 m_nAttributes;
     674             :     mutable std::string m_osUnit{};
     675             :     std::vector<std::shared_ptr<GDALAttribute>> m_oGlobalAttributes{};
     676             :     bool m_bIsGDALDataset;
     677             :     mutable std::vector<GByte> m_abyNoData{};
     678             : 
     679             :   protected:
     680             :     HDF4SDSArray(const std::string &osParentName, const std::string &osName,
     681             :                  const std::shared_ptr<HDF4SharedResources> &poShared,
     682             :                  int32 iSDS, const std::vector<int32> &aiDimSizes,
     683             :                  const std::vector<std::shared_ptr<GDALDimension>> &groupDims,
     684             :                  int32 iNumType, int32 nAttrs, bool bIsGDALDS);
     685             : 
     686             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
     687             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
     688             :                const GDALExtendedDataType &bufferDataType,
     689             :                void *pDstBuffer) const override;
     690             : 
     691             :   public:
     692             :     static std::shared_ptr<HDF4SDSArray>
     693           8 :     Create(const std::string &osParentName, const std::string &osName,
     694             :            const std::shared_ptr<HDF4SharedResources> &poShared, int32 iSDS,
     695             :            const std::vector<int32> &aiDimSizes,
     696             :            const std::vector<std::shared_ptr<GDALDimension>> &groupDims,
     697             :            int32 iNumType, int32 nAttrs, bool bIsGDALDS)
     698             :     {
     699             :         auto ar(std::shared_ptr<HDF4SDSArray>(
     700             :             new HDF4SDSArray(osParentName, osName, poShared, iSDS, aiDimSizes,
     701           8 :                              groupDims, iNumType, nAttrs, bIsGDALDS)));
     702           8 :         ar->SetSelf(ar);
     703           8 :         return ar;
     704             :     }
     705             : 
     706             :     ~HDF4SDSArray();
     707             : 
     708           2 :     void SetGlobalAttributes(
     709             :         const std::vector<std::shared_ptr<GDALAttribute>> &attrs)
     710             :     {
     711           2 :         m_oGlobalAttributes = attrs;
     712           2 :     }
     713             : 
     714           0 :     bool IsWritable() const override
     715             :     {
     716           0 :         return false;
     717             :     }
     718             : 
     719           8 :     const std::string &GetFilename() const override
     720             :     {
     721           8 :         return m_poShared->GetFilename();
     722             :     }
     723             : 
     724             :     const std::vector<std::shared_ptr<GDALDimension>> &
     725          28 :     GetDimensions() const override
     726             :     {
     727          28 :         return m_dims;
     728             :     }
     729             : 
     730          17 :     const GDALExtendedDataType &GetDataType() const override
     731             :     {
     732          17 :         return m_dt;
     733             :     }
     734             : 
     735             :     std::vector<std::shared_ptr<GDALAttribute>>
     736             :     GetAttributes(CSLConstList papszOptions = nullptr) const override;
     737             : 
     738             :     const void *GetRawNoDataValue() const override;
     739             : 
     740             :     double GetOffset(bool *pbHasOffset = nullptr,
     741             :                      GDALDataType *peStorageType = nullptr) const override;
     742             : 
     743             :     double GetScale(bool *pbHasScale = nullptr,
     744             :                     GDALDataType *peStorageType = nullptr) const override;
     745             : 
     746             :     const std::string &GetUnit() const override;
     747             : 
     748             :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override;
     749             : 
     750           0 :     std::shared_ptr<GDALGroup> GetRootGroup() const override
     751             :     {
     752           0 :         return HDF4Group::Create(std::string(), "/", m_poShared);
     753             :     }
     754             : };
     755             : 
     756             : /************************************************************************/
     757             : /*                            HDF4GRsHandle                              */
     758             : /************************************************************************/
     759             : 
     760             : struct HDF4GRsHandle
     761             : {
     762             :     int32 m_hHandle;
     763             :     int32 m_grHandle;
     764             : 
     765           2 :     explicit HDF4GRsHandle(int32 hHandle, int32 grHandle)
     766           2 :         : m_hHandle(hHandle), m_grHandle(grHandle)
     767             :     {
     768           2 :     }
     769             : 
     770           2 :     ~HDF4GRsHandle()
     771           2 :     {
     772           4 :         CPLMutexHolderD(&hHDF4Mutex);
     773           2 :         GRend(m_grHandle);
     774           2 :         Hclose(m_hHandle);
     775           2 :     }
     776             : };
     777             : 
     778             : /************************************************************************/
     779             : /*                             HDF4GRHandle                             */
     780             : /************************************************************************/
     781             : 
     782             : struct HDF4GRHandle
     783             : {
     784             :     std::shared_ptr<HDF4GRsHandle> m_poGRsHandle;
     785             :     int32 m_iGR;
     786             : 
     787           2 :     explicit HDF4GRHandle(const std::shared_ptr<HDF4GRsHandle> &poGRsHandle,
     788             :                           int32 iGR)
     789           2 :         : m_poGRsHandle(poGRsHandle), m_iGR(iGR)
     790             :     {
     791           2 :     }
     792             : 
     793           2 :     ~HDF4GRHandle()
     794           2 :     {
     795           4 :         CPLMutexHolderD(&hHDF4Mutex);
     796           2 :         GRendaccess(m_iGR);
     797           2 :     }
     798             : };
     799             : 
     800             : /************************************************************************/
     801             : /*                            HDF4GRsGroup                              */
     802             : /************************************************************************/
     803             : 
     804             : class HDF4GRsGroup final : public GDALGroup
     805             : {
     806             :     std::shared_ptr<HDF4SharedResources> m_poShared;
     807             :     std::shared_ptr<HDF4GRsHandle> m_poGRsHandle;
     808             :     mutable std::map<std::string, int> m_oMapNameToGRIdx{};
     809             : 
     810             :   public:
     811           2 :     HDF4GRsGroup(const std::string &osParentName, const std::string &osName,
     812             :                  const std::shared_ptr<HDF4SharedResources> &poShared,
     813             :                  const std::shared_ptr<HDF4GRsHandle> &poGRsHandle)
     814           2 :         : GDALGroup(osParentName, osName), m_poShared(poShared),
     815           2 :           m_poGRsHandle(poGRsHandle)
     816             :     {
     817           2 :     }
     818             : 
     819             :     std::vector<std::string>
     820             :     GetMDArrayNames(CSLConstList papszOptions) const override;
     821             :     std::shared_ptr<GDALMDArray>
     822             :     OpenMDArray(const std::string &osName,
     823             :                 CSLConstList papszOptions) const override;
     824             : 
     825             :     std::vector<std::shared_ptr<GDALAttribute>>
     826             :     GetAttributes(CSLConstList papszOptions = nullptr) const override;
     827             : };
     828             : 
     829             : /************************************************************************/
     830             : /*                            HDF4GRArray                               */
     831             : /************************************************************************/
     832             : 
     833             : class HDF4GRArray final : public GDALPamMDArray
     834             : {
     835             :     std::shared_ptr<HDF4SharedResources> m_poShared;
     836             :     std::shared_ptr<HDF4GRHandle> m_poGRHandle;
     837             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
     838             :     GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_Unknown);
     839             :     int32 m_nAttributes;
     840             : 
     841             :   protected:
     842             :     HDF4GRArray(const std::string &osParentName, const std::string &osName,
     843             :                 const std::shared_ptr<HDF4SharedResources> &poShared,
     844             :                 const std::shared_ptr<HDF4GRHandle> &poGRHandle, int32 nBands,
     845             :                 const std::vector<int32> &aiDimSizes, int32 iNumType,
     846             :                 int32 nAttrs);
     847             : 
     848             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
     849             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
     850             :                const GDALExtendedDataType &bufferDataType,
     851             :                void *pDstBuffer) const override;
     852             : 
     853             :   public:
     854             :     static std::shared_ptr<HDF4GRArray>
     855           2 :     Create(const std::string &osParentName, const std::string &osName,
     856             :            const std::shared_ptr<HDF4SharedResources> &poShared,
     857             :            const std::shared_ptr<HDF4GRHandle> &poGRHandle, int32 nBands,
     858             :            const std::vector<int32> &aiDimSizes, int32 iNumType, int32 nAttrs)
     859             :     {
     860             :         auto ar(std::shared_ptr<HDF4GRArray>(
     861             :             new HDF4GRArray(osParentName, osName, poShared, poGRHandle, nBands,
     862           2 :                             aiDimSizes, iNumType, nAttrs)));
     863           2 :         ar->SetSelf(ar);
     864           2 :         return ar;
     865             :     }
     866             : 
     867           0 :     bool IsWritable() const override
     868             :     {
     869           0 :         return false;
     870             :     }
     871             : 
     872           2 :     const std::string &GetFilename() const override
     873             :     {
     874           2 :         return m_poShared->GetFilename();
     875             :     }
     876             : 
     877             :     const std::vector<std::shared_ptr<GDALDimension>> &
     878          20 :     GetDimensions() const override
     879             :     {
     880          20 :         return m_dims;
     881             :     }
     882             : 
     883          12 :     const GDALExtendedDataType &GetDataType() const override
     884             :     {
     885          12 :         return m_dt;
     886             :     }
     887             : 
     888             :     std::vector<std::shared_ptr<GDALAttribute>>
     889             :     GetAttributes(CSLConstList papszOptions = nullptr) const override;
     890             : 
     891           0 :     std::shared_ptr<GDALGroup> GetRootGroup() const override
     892             :     {
     893           0 :         return HDF4Group::Create(std::string(), "/", m_poShared);
     894             :     }
     895             : };
     896             : 
     897             : /************************************************************************/
     898             : /*                            HDF4SDAttribute                           */
     899             : /************************************************************************/
     900             : 
     901             : class HDF4SDAttribute final : public HDF4AbstractAttribute
     902             : {
     903             :     std::shared_ptr<HDF4SwathHandle> m_poSwathHandle;
     904             :     std::shared_ptr<HDF4GDHandle> m_poGDHandle;
     905             :     int32 m_sdHandle = 0;
     906             :     int32 m_iAttribute = 0;
     907             : 
     908             :   public:
     909          18 :     HDF4SDAttribute(const std::string &osParentName, const std::string &osName,
     910             :                     const std::shared_ptr<HDF4SharedResources> &poShared,
     911             :                     const std::shared_ptr<HDF4SwathHandle> &poSwathHandle,
     912             :                     const std::shared_ptr<HDF4GDHandle> &poGDHandle,
     913             :                     int32 sdHandle, int32 iAttribute, int32 iNumType,
     914             :                     int32 nValues)
     915          18 :         : GDALAbstractMDArray(osParentName, osName),
     916             :           HDF4AbstractAttribute(osParentName, osName, poShared, iNumType,
     917             :                                 nValues),
     918             :           m_poSwathHandle(poSwathHandle), m_poGDHandle(poGDHandle),
     919          18 :           m_sdHandle(sdHandle), m_iAttribute(iAttribute)
     920             :     {
     921          18 :     }
     922             : 
     923          10 :     void ReadData(void *pDstBuffer) const override
     924             :     {
     925          10 :         SDreadattr(m_sdHandle, m_iAttribute, pDstBuffer);
     926          10 :     }
     927             : };
     928             : 
     929             : /************************************************************************/
     930             : /*                           HDF4GRAttribute                            */
     931             : /************************************************************************/
     932             : 
     933             : class HDF4GRAttribute final : public HDF4AbstractAttribute
     934             : {
     935             :     std::shared_ptr<HDF4GRsHandle> m_poGRsHandle;
     936             :     std::shared_ptr<HDF4GRHandle> m_poGRHandle;
     937             :     int32 m_grHandle = 0;
     938             :     int32 m_iAttribute = 0;
     939             : 
     940             :   public:
     941          10 :     HDF4GRAttribute(const std::string &osParentName, const std::string &osName,
     942             :                     const std::shared_ptr<HDF4SharedResources> &poShared,
     943             :                     const std::shared_ptr<HDF4GRsHandle> &poGRsHandle,
     944             :                     const std::shared_ptr<HDF4GRHandle> &poGRHandle,
     945             :                     int32 iGRHandle, int32 iAttribute, int32 iNumType,
     946             :                     int32 nValues)
     947          10 :         : GDALAbstractMDArray(osParentName, osName),
     948             :           HDF4AbstractAttribute(osParentName, osName, poShared, iNumType,
     949             :                                 nValues),
     950             :           m_poGRsHandle(poGRsHandle), m_poGRHandle(poGRHandle),
     951          10 :           m_grHandle(iGRHandle), m_iAttribute(iAttribute)
     952             :     {
     953          10 :     }
     954             : 
     955           3 :     void ReadData(void *pDstBuffer) const override
     956             :     {
     957           3 :         GRgetattr(m_grHandle, m_iAttribute, pDstBuffer);
     958           3 :     }
     959             : };
     960             : 
     961             : /************************************************************************/
     962             : /*                         HDF4GRPalette                                */
     963             : /************************************************************************/
     964             : 
     965             : class HDF4GRPalette final : public GDALAttribute
     966             : {
     967             :     std::shared_ptr<HDF4SharedResources> m_poShared;
     968             :     std::shared_ptr<HDF4GRHandle> m_poGRHandle;
     969             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
     970             :     GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_Byte);
     971             :     int32 m_iPal = 0;
     972             :     int32 m_nValues = 0;
     973             : 
     974             :   protected:
     975             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
     976             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
     977             :                const GDALExtendedDataType &bufferDataType,
     978             :                void *pDstBuffer) const override;
     979             : 
     980             :   public:
     981             :     HDF4GRPalette(const std::string &osParentName, const std::string &osName,
     982             :                   const std::shared_ptr<HDF4SharedResources> &poShared,
     983             :                   const std::shared_ptr<HDF4GRHandle> &poGRHandle, int32 iPal,
     984             :                   int32 nValues);
     985             : 
     986             :     const std::vector<std::shared_ptr<GDALDimension>> &
     987           5 :     GetDimensions() const override
     988             :     {
     989           5 :         return m_dims;
     990             :     }
     991             : 
     992           2 :     const GDALExtendedDataType &GetDataType() const override
     993             :     {
     994           2 :         return m_dt;
     995             :     }
     996             : };
     997             : 
     998             : /************************************************************************/
     999             : /*                        HDF4SharedResources()                         */
    1000             : /************************************************************************/
    1001             : 
    1002           6 : HDF4SharedResources::HDF4SharedResources(const std::string &osFilename)
    1003             :     : m_osFilename(osFilename),
    1004           6 :       m_poPAM(std::make_shared<GDALPamMultiDim>(osFilename))
    1005             : {
    1006           6 : }
    1007             : 
    1008             : /************************************************************************/
    1009             : /*                        ~HDF4SharedResources()                        */
    1010             : /************************************************************************/
    1011             : 
    1012           6 : HDF4SharedResources::~HDF4SharedResources()
    1013             : {
    1014          12 :     CPLMutexHolderD(&hHDF4Mutex);
    1015             : 
    1016           6 :     if (m_hSD)
    1017           6 :         SDend(m_hSD);
    1018           6 : }
    1019             : 
    1020             : /************************************************************************/
    1021             : /*                               HDF4Group()                            */
    1022             : /************************************************************************/
    1023             : 
    1024           6 : HDF4Group::HDF4Group(const std::string &osParentName, const std::string &osName,
    1025           6 :                      const std::shared_ptr<HDF4SharedResources> &poShared)
    1026           6 :     : GDALGroup(osParentName, osName), m_poShared(poShared)
    1027             : {
    1028           6 :     bool bIsGDALDS = false;
    1029          18 :     auto poAttr = GetAttribute("Signature");
    1030           6 :     if (poAttr && poAttr->GetDataType().GetClass() == GEDTC_STRING)
    1031             :     {
    1032           2 :         const char *pszVal = poAttr->ReadAsString();
    1033           2 :         if (pszVal && EQUAL(pszVal, pszGDALSignature))
    1034             :         {
    1035           2 :             bIsGDALDS = true;
    1036             :         }
    1037             :     }
    1038           6 :     if (bIsGDALDS)
    1039             :     {
    1040             :         m_poGDALGroup =
    1041           2 :             std::make_shared<HDF4SDSGroup>(std::string(), "/", m_poShared);
    1042           2 :         m_poGDALGroup->SetIsGDALDataset();
    1043           2 :         m_poGDALGroup->SetGlobalAttributes(GetAttributes(nullptr));
    1044             :     }
    1045           6 : }
    1046             : 
    1047             : /************************************************************************/
    1048             : /*                           GetAttributes()                            */
    1049             : /************************************************************************/
    1050             : 
    1051             : std::vector<std::shared_ptr<GDALAttribute>>
    1052           9 : HDF4Group::GetAttributes(CSLConstList) const
    1053             : {
    1054          18 :     CPLMutexHolderD(&hHDF4Mutex);
    1055           9 :     std::vector<std::shared_ptr<GDALAttribute>> ret;
    1056           9 :     int32 nDatasets = 0;
    1057           9 :     int32 nAttributes = 0;
    1058           9 :     if (SDfileinfo(m_poShared->GetSDHandle(), &nDatasets, &nAttributes) != 0)
    1059           0 :         return ret;
    1060             : 
    1061          18 :     std::map<CPLString, std::shared_ptr<GDALAttribute>> oMapAttrs;
    1062             :     const auto AddAttribute =
    1063          56 :         [&ret, &oMapAttrs](const std::shared_ptr<GDALAttribute> &poNewAttr)
    1064             :     {
    1065          14 :         auto oIter = oMapAttrs.find(poNewAttr->GetName());
    1066          14 :         if (oIter != oMapAttrs.end())
    1067             :         {
    1068           0 :             const char *pszOldVal = oIter->second->ReadAsString();
    1069           0 :             const char *pszNewVal = poNewAttr->ReadAsString();
    1070             :             // As found in MOD35_L2.A2017161.1525.061.2017315035809.hdf
    1071             :             // product of https://github.com/OSGeo/gdal/issues/2848,
    1072             :             // the identifier_product_doi attribute is found in a
    1073             :             // HDF4EOS attribute bundle, as well as a standalone attribute
    1074           0 :             if (pszOldVal && pszNewVal && strcmp(pszOldVal, pszNewVal) == 0)
    1075           0 :                 return;
    1076             :             // TODO
    1077           0 :             CPLDebug("HDF4",
    1078             :                      "Attribute with same name (%s) found, but different value",
    1079           0 :                      poNewAttr->GetName().c_str());
    1080             :         }
    1081             :         // cppcheck-suppress unreadVariable
    1082          14 :         oMapAttrs[poNewAttr->GetName()] = poNewAttr;
    1083          14 :         ret.emplace_back(poNewAttr);
    1084           9 :     };
    1085             : 
    1086          23 :     for (int32 iAttribute = 0; iAttribute < nAttributes; iAttribute++)
    1087             :     {
    1088          14 :         int32 iNumType = 0;
    1089          14 :         int32 nValues = 0;
    1090             : 
    1091          14 :         std::string osAttrName;
    1092          14 :         osAttrName.resize(H4_MAX_NC_NAME);
    1093          14 :         SDattrinfo(m_poShared->GetSDHandle(), iAttribute, &osAttrName[0],
    1094             :                    &iNumType, &nValues);
    1095          14 :         osAttrName.resize(strlen(osAttrName.c_str()));
    1096             : 
    1097          14 :         if (STARTS_WITH_CI(osAttrName.c_str(), "coremetadata") ||
    1098          14 :             STARTS_WITH_CI(osAttrName.c_str(), "archivemetadata.") ||
    1099          14 :             STARTS_WITH_CI(osAttrName.c_str(), "productmetadata.") ||
    1100          14 :             STARTS_WITH_CI(osAttrName.c_str(), "badpixelinformation") ||
    1101          14 :             STARTS_WITH_CI(osAttrName.c_str(), "product_summary") ||
    1102          14 :             STARTS_WITH_CI(osAttrName.c_str(), "dem_specific") ||
    1103          14 :             STARTS_WITH_CI(osAttrName.c_str(), "bts_specific") ||
    1104          14 :             STARTS_WITH_CI(osAttrName.c_str(), "etse_specific") ||
    1105          14 :             STARTS_WITH_CI(osAttrName.c_str(), "dst_specific") ||
    1106          14 :             STARTS_WITH_CI(osAttrName.c_str(), "acv_specific") ||
    1107          14 :             STARTS_WITH_CI(osAttrName.c_str(), "act_specific") ||
    1108          42 :             STARTS_WITH_CI(osAttrName.c_str(), "etst_specific") ||
    1109          14 :             STARTS_WITH_CI(osAttrName.c_str(), "level_1_carryover"))
    1110             :         {
    1111           0 :             char **papszMD = HDF4Dataset::TranslateHDF4EOSAttributes(
    1112           0 :                 m_poShared->GetSDHandle(), iAttribute, nValues, nullptr);
    1113           0 :             for (char **iter = papszMD; iter && *iter; ++iter)
    1114             :             {
    1115           0 :                 char *pszKey = nullptr;
    1116           0 :                 const char *pszValue = CPLParseNameValue(*iter, &pszKey);
    1117           0 :                 if (pszKey && pszValue)
    1118             :                 {
    1119           0 :                     AddAttribute(std::make_shared<GDALAttributeString>(
    1120           0 :                         GetFullName(), pszKey, pszValue));
    1121             :                 }
    1122           0 :                 CPLFree(pszKey);
    1123             :             }
    1124           0 :             CSLDestroy(papszMD);
    1125             :         }
    1126             : 
    1127             :         // Skip "StructMetadata.N" records. We will fetch information
    1128             :         // from them using HDF-EOS API
    1129          14 :         else if (STARTS_WITH_CI(osAttrName.c_str(), "structmetadata."))
    1130             :         {
    1131           0 :             continue;
    1132             :         }
    1133             :         else
    1134             :         {
    1135          14 :             AddAttribute(std::make_shared<HDF4SDAttribute>(
    1136           0 :                 GetFullName(), osAttrName, m_poShared, nullptr, nullptr,
    1137          28 :                 m_poShared->GetSDHandle(), iAttribute, iNumType, nValues));
    1138             :         }
    1139             :     }
    1140           9 :     return ret;
    1141             : }
    1142             : 
    1143             : /************************************************************************/
    1144             : /*                            GetGroupNames()                           */
    1145             : /************************************************************************/
    1146             : 
    1147           6 : std::vector<std::string> HDF4Group::GetGroupNames(CSLConstList) const
    1148             : {
    1149           6 :     if (m_poGDALGroup)
    1150           2 :         return {};
    1151             : 
    1152           8 :     CPLMutexHolderD(&hHDF4Mutex);
    1153           8 :     std::vector<std::string> res;
    1154           4 :     auto sw_handle = SWopen(m_poShared->GetFilename().c_str(), DFACC_READ);
    1155           4 :     if (sw_handle >= 0)
    1156             :     {
    1157           4 :         int32 nStrBufSize = 0;
    1158           4 :         int32 nSubDatasets = SWinqswath(m_poShared->GetFilename().c_str(),
    1159             :                                         nullptr, &nStrBufSize);
    1160           4 :         if (nSubDatasets > 0)
    1161             :         {
    1162           0 :             res.emplace_back("swaths");
    1163             :         }
    1164           4 :         SWclose(sw_handle);
    1165             :     }
    1166             : 
    1167           4 :     auto gd_handle = GDopen(m_poShared->GetFilename().c_str(), DFACC_READ);
    1168           4 :     if (gd_handle >= 0)
    1169             :     {
    1170           4 :         int32 nStrBufSize = 0;
    1171             :         int32 nSubDatasets =
    1172           4 :             GDinqgrid(m_poShared->GetFilename().c_str(), nullptr, &nStrBufSize);
    1173           4 :         if (nSubDatasets > 0)
    1174             :         {
    1175           0 :             res.emplace_back("eos_grids");
    1176             :         }
    1177           4 :         GDclose(gd_handle);
    1178             :     }
    1179             : 
    1180           4 :     const char *pszListSDS = m_poShared->FetchOpenOption("LIST_SDS", "AUTO");
    1181           4 :     if ((res.empty() && EQUAL(pszListSDS, "AUTO")) ||
    1182           0 :         (!EQUAL(pszListSDS, "AUTO") && CPLTestBool(pszListSDS)))
    1183             :     {
    1184           4 :         int32 nDatasets = 0;
    1185           4 :         int32 nAttrs = 0;
    1186           8 :         if (SDfileinfo(m_poShared->GetSDHandle(), &nDatasets, &nAttrs) == 0 &&
    1187           4 :             nDatasets > 0)
    1188             :         {
    1189           2 :             res.emplace_back("scientific_datasets");
    1190             :         }
    1191             :     }
    1192             : 
    1193           4 :     auto hHandle = Hopen(m_poShared->GetFilename().c_str(), DFACC_READ, 0);
    1194           4 :     if (hHandle >= 0)
    1195             :     {
    1196           4 :         auto grHandle = GRstart(hHandle);
    1197           4 :         if (grHandle >= 0)
    1198             :         {
    1199           4 :             int32 nImages = 0;
    1200           4 :             int32 nAttrs = 0;
    1201           4 :             if (GRfileinfo(grHandle, &nImages, &nAttrs) == 0 && nImages > 0)
    1202             :             {
    1203           2 :                 res.emplace_back("general_rasters");
    1204             :             }
    1205           4 :             GRend(grHandle);
    1206             :         }
    1207           4 :         Hclose(hHandle);
    1208             :     }
    1209             : 
    1210           4 :     return res;
    1211             : }
    1212             : 
    1213             : /************************************************************************/
    1214             : /*                             OpenGroup()                              */
    1215             : /************************************************************************/
    1216             : 
    1217           7 : std::shared_ptr<GDALGroup> HDF4Group::OpenGroup(const std::string &osName,
    1218             :                                                 CSLConstList) const
    1219             : {
    1220           7 :     if (m_poGDALGroup)
    1221           2 :         return nullptr;
    1222             : 
    1223          10 :     CPLMutexHolderD(&hHDF4Mutex);
    1224           5 :     if (osName == "swaths")
    1225             :     {
    1226           0 :         auto handle = SWopen(m_poShared->GetFilename().c_str(), DFACC_READ);
    1227           0 :         if (handle >= 0)
    1228           0 :             return std::make_shared<HDF4SwathsGroup>(
    1229           0 :                 GetFullName(), osName, m_poShared,
    1230           0 :                 std::make_shared<HDF4SwathsHandle>(handle));
    1231             :     }
    1232           5 :     if (osName == "eos_grids")
    1233             :     {
    1234           0 :         auto handle = GDopen(m_poShared->GetFilename().c_str(), DFACC_READ);
    1235           0 :         if (handle >= 0)
    1236           0 :             return std::make_shared<HDF4EOSGridsGroup>(
    1237           0 :                 GetFullName(), osName, m_poShared,
    1238           0 :                 std::make_shared<HDF4GDsHandle>(handle));
    1239             :     }
    1240           5 :     if (osName == "scientific_datasets")
    1241             :     {
    1242           4 :         return std::make_shared<HDF4SDSGroup>(GetFullName(), osName,
    1243           4 :                                               m_poShared);
    1244             :     }
    1245           3 :     if (osName == "general_rasters")
    1246             :     {
    1247           2 :         auto hHandle = Hopen(m_poShared->GetFilename().c_str(), DFACC_READ, 0);
    1248           2 :         if (hHandle >= 0)
    1249             :         {
    1250           2 :             auto grHandle = GRstart(hHandle);
    1251           2 :             if (grHandle >= 0)
    1252             :             {
    1253           4 :                 return std::make_shared<HDF4GRsGroup>(
    1254           2 :                     GetFullName(), osName, m_poShared,
    1255           6 :                     std::make_shared<HDF4GRsHandle>(hHandle, grHandle));
    1256             :             }
    1257             :             else
    1258             :             {
    1259           0 :                 Hclose(hHandle);
    1260             :             }
    1261             :         }
    1262             :     }
    1263           1 :     return nullptr;
    1264             : }
    1265             : 
    1266             : /************************************************************************/
    1267             : /*                         GetMDArrayNames()                            */
    1268             : /************************************************************************/
    1269             : 
    1270           3 : std::vector<std::string> HDF4Group::GetMDArrayNames(CSLConstList) const
    1271             : {
    1272           3 :     if (m_poGDALGroup)
    1273           2 :         return m_poGDALGroup->GetMDArrayNames(nullptr);
    1274           1 :     return {};
    1275             : }
    1276             : 
    1277             : /************************************************************************/
    1278             : /*                           OpenMDArray()                              */
    1279             : /************************************************************************/
    1280             : 
    1281           5 : std::shared_ptr<GDALMDArray> HDF4Group::OpenMDArray(const std::string &osName,
    1282             :                                                     CSLConstList) const
    1283             : {
    1284           5 :     if (m_poGDALGroup)
    1285           4 :         return m_poGDALGroup->OpenMDArray(osName, nullptr);
    1286           1 :     return nullptr;
    1287             : }
    1288             : 
    1289             : /************************************************************************/
    1290             : /*                            GetDimensions()                           */
    1291             : /************************************************************************/
    1292             : 
    1293             : std::vector<std::shared_ptr<GDALDimension>>
    1294           2 : HDF4Group::GetDimensions(CSLConstList) const
    1295             : {
    1296           2 :     if (m_poGDALGroup)
    1297           2 :         return m_poGDALGroup->GetDimensions(nullptr);
    1298           0 :     return {};
    1299             : }
    1300             : 
    1301             : /************************************************************************/
    1302             : /*                            GetGroupNames()                           */
    1303             : /************************************************************************/
    1304             : 
    1305           0 : std::vector<std::string> HDF4SwathsGroup::GetGroupNames(CSLConstList) const
    1306             : {
    1307           0 :     CPLMutexHolderD(&hHDF4Mutex);
    1308           0 :     std::vector<std::string> res;
    1309             : 
    1310           0 :     int32 nStrBufSize = 0;
    1311           0 :     SWinqswath(m_poShared->GetFilename().c_str(), nullptr, &nStrBufSize);
    1312             : 
    1313           0 :     std::string osSwathList;
    1314           0 :     osSwathList.resize(nStrBufSize);
    1315           0 :     SWinqswath(m_poShared->GetFilename().c_str(), &osSwathList[0],
    1316             :                &nStrBufSize);
    1317             : 
    1318             :     CPLStringList aosSwaths(
    1319           0 :         CSLTokenizeString2(osSwathList.c_str(), ",", CSLT_HONOURSTRINGS));
    1320           0 :     for (int i = 0; i < aosSwaths.size(); i++)
    1321           0 :         res.push_back(aosSwaths[i]);
    1322             : 
    1323           0 :     return res;
    1324             : }
    1325             : 
    1326             : /************************************************************************/
    1327             : /*                             OpenGroup()                              */
    1328             : /************************************************************************/
    1329             : 
    1330           0 : std::shared_ptr<GDALGroup> HDF4SwathsGroup::OpenGroup(const std::string &osName,
    1331             :                                                       CSLConstList) const
    1332             : {
    1333           0 :     CPLMutexHolderD(&hHDF4Mutex);
    1334             : 
    1335           0 :     int32 swathHandle = SWattach(m_poSwathsHandle->m_handle, osName.c_str());
    1336           0 :     if (swathHandle < 0)
    1337             :     {
    1338           0 :         return nullptr;
    1339             :     }
    1340             : 
    1341           0 :     return std::make_shared<HDF4SwathGroup>(
    1342           0 :         GetFullName(), osName, m_poShared,
    1343           0 :         std::make_shared<HDF4SwathHandle>(m_poSwathsHandle, swathHandle));
    1344             : }
    1345             : 
    1346             : /************************************************************************/
    1347             : /*                         GetMDArrayNames()                            */
    1348             : /************************************************************************/
    1349             : 
    1350           0 : std::vector<std::string> HDF4SwathSubGroup::GetMDArrayNames(CSLConstList) const
    1351             : {
    1352           0 :     CPLMutexHolderD(&hHDF4Mutex);
    1353           0 :     std::vector<std::string> ret;
    1354             : 
    1355           0 :     int32 nStrBufSize = 0;
    1356             :     const int32 nFields =
    1357           0 :         SWnentries(m_poSwathHandle->m_handle, m_entryType, &nStrBufSize);
    1358           0 :     std::string osFieldList;
    1359           0 :     osFieldList.resize(nStrBufSize);
    1360           0 :     std::vector<int32> ranks(nFields);
    1361           0 :     std::vector<int32> numberTypes(nFields);
    1362             : 
    1363           0 :     if (m_entryType == HDFE_NENTDFLD)
    1364           0 :         SWinqdatafields(m_poSwathHandle->m_handle, &osFieldList[0], &ranks[0],
    1365           0 :                         &numberTypes[0]);
    1366             :     else
    1367           0 :         SWinqgeofields(m_poSwathHandle->m_handle, &osFieldList[0], &ranks[0],
    1368           0 :                        &numberTypes[0]);
    1369             : 
    1370             :     CPLStringList aosFields(
    1371           0 :         CSLTokenizeString2(osFieldList.c_str(), ",", CSLT_HONOURSTRINGS));
    1372           0 :     for (int i = 0; i < aosFields.size(); i++)
    1373           0 :         ret.push_back(aosFields[i]);
    1374             : 
    1375           0 :     return ret;
    1376             : }
    1377             : 
    1378             : /************************************************************************/
    1379             : /*                           OpenMDArray()                              */
    1380             : /************************************************************************/
    1381             : 
    1382             : std::shared_ptr<GDALMDArray>
    1383           0 : HDF4SwathSubGroup::OpenMDArray(const std::string &osName, CSLConstList) const
    1384             : {
    1385           0 :     CPLMutexHolderD(&hHDF4Mutex);
    1386             : 
    1387             :     int32 iRank;
    1388             :     int32 iNumType;
    1389           0 :     std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
    1390           0 :     std::string dimNames;
    1391             : 
    1392           0 :     int32 nStrBufSize = 0;
    1393           0 :     if (SWnentries(m_poSwathHandle->m_handle, HDFE_NENTDIM, &nStrBufSize) < 0 ||
    1394           0 :         nStrBufSize <= 0)
    1395             :     {
    1396           0 :         return nullptr;
    1397             :     }
    1398           0 :     dimNames.resize(nStrBufSize);
    1399           0 :     if (SWfieldinfo(m_poSwathHandle->m_handle, osName.c_str(), &iRank,
    1400           0 :                     &aiDimSizes[0], &iNumType, &dimNames[0]) < 0)
    1401             :     {
    1402           0 :         return nullptr;
    1403             :     }
    1404           0 :     aiDimSizes.resize(iRank);
    1405             : 
    1406           0 :     return HDF4SwathArray::Create(GetFullName(), osName, m_poShared,
    1407           0 :                                   m_poSwathHandle, aiDimSizes, dimNames,
    1408           0 :                                   iNumType, m_groupDims);
    1409             : }
    1410             : 
    1411             : /************************************************************************/
    1412             : /*                            GetGroupNames()                           */
    1413             : /************************************************************************/
    1414             : 
    1415           0 : std::vector<std::string> HDF4SwathGroup::GetGroupNames(CSLConstList) const
    1416             : {
    1417           0 :     std::vector<std::string> res;
    1418           0 :     res.push_back("Data Fields");
    1419           0 :     res.push_back("Geolocation Fields");
    1420           0 :     return res;
    1421             : }
    1422             : 
    1423             : /************************************************************************/
    1424             : /*                             OpenGroup()                              */
    1425             : /************************************************************************/
    1426             : 
    1427           0 : std::shared_ptr<GDALGroup> HDF4SwathGroup::OpenGroup(const std::string &osName,
    1428             :                                                      CSLConstList) const
    1429             : {
    1430           0 :     if (osName == "Data Fields")
    1431             :     {
    1432           0 :         return std::make_shared<HDF4SwathSubGroup>(
    1433           0 :             GetFullName(), osName, m_poShared, m_poSwathHandle, HDFE_NENTDFLD,
    1434           0 :             GetDimensions());
    1435             :     }
    1436           0 :     if (osName == "Geolocation Fields")
    1437             :     {
    1438           0 :         return std::make_shared<HDF4SwathSubGroup>(
    1439           0 :             GetFullName(), osName, m_poShared, m_poSwathHandle, HDFE_NENTGFLD,
    1440           0 :             GetDimensions());
    1441             :     }
    1442           0 :     return nullptr;
    1443             : }
    1444             : 
    1445             : /************************************************************************/
    1446             : /*                            GetDimensions()                           */
    1447             : /************************************************************************/
    1448             : 
    1449             : std::vector<std::shared_ptr<GDALDimension>>
    1450           0 : HDF4SwathGroup::GetDimensions(CSLConstList) const
    1451             : {
    1452           0 :     if (!m_dims.empty())
    1453           0 :         return m_dims;
    1454           0 :     std::string dimNames;
    1455           0 :     int32 nStrBufSize = 0;
    1456           0 :     if (SWnentries(m_poSwathHandle->m_handle, HDFE_NENTDIM, &nStrBufSize) < 0 ||
    1457           0 :         nStrBufSize <= 0)
    1458             :     {
    1459           0 :         return m_dims;
    1460             :     }
    1461           0 :     dimNames.resize(nStrBufSize);
    1462           0 :     int32 nDims = SWinqdims(m_poSwathHandle->m_handle, &dimNames[0], nullptr);
    1463           0 :     std::vector<int32> aiDimSizes(nDims);
    1464           0 :     SWinqdims(m_poSwathHandle->m_handle, &dimNames[0], &aiDimSizes[0]);
    1465             :     CPLStringList aosDimNames(
    1466           0 :         CSLTokenizeString2(dimNames.c_str(), ",", CSLT_HONOURSTRINGS));
    1467           0 :     if (static_cast<size_t>(aosDimNames.size()) == aiDimSizes.size())
    1468             :     {
    1469           0 :         for (int i = 0; i < aosDimNames.size(); i++)
    1470             :         {
    1471           0 :             m_dims.push_back(std::make_shared<GDALDimension>(
    1472           0 :                 GetFullName(), aosDimNames[i], std::string(), std::string(),
    1473           0 :                 aiDimSizes[i]));
    1474             :         }
    1475             :     }
    1476           0 :     return m_dims;
    1477             : }
    1478             : 
    1479             : /************************************************************************/
    1480             : /*                           GetAttributes()                            */
    1481             : /************************************************************************/
    1482             : 
    1483             : std::vector<std::shared_ptr<GDALAttribute>>
    1484           0 : HDF4SwathGroup::GetAttributes(CSLConstList) const
    1485             : {
    1486           0 :     CPLMutexHolderD(&hHDF4Mutex);
    1487           0 :     std::vector<std::shared_ptr<GDALAttribute>> ret;
    1488           0 :     int32 nStrBufSize = 0;
    1489           0 :     if (SWinqattrs(m_poSwathHandle->m_handle, nullptr, &nStrBufSize) <= 0 ||
    1490           0 :         nStrBufSize <= 0)
    1491             :     {
    1492           0 :         return ret;
    1493             :     }
    1494           0 :     std::string osAttrs;
    1495           0 :     osAttrs.resize(nStrBufSize);
    1496           0 :     SWinqattrs(m_poSwathHandle->m_handle, &osAttrs[0], &nStrBufSize);
    1497             : 
    1498             :     CPLStringList aosAttrs(
    1499           0 :         CSLTokenizeString2(osAttrs.c_str(), ",", CSLT_HONOURSTRINGS));
    1500           0 :     for (int i = 0; i < aosAttrs.size(); i++)
    1501             :     {
    1502           0 :         int32 iNumType = 0;
    1503           0 :         int32 nSize = 0;
    1504             : 
    1505           0 :         const auto &osAttrName = aosAttrs[i];
    1506           0 :         if (SWattrinfo(m_poSwathHandle->m_handle, osAttrName, &iNumType,
    1507           0 :                        &nSize) < 0)
    1508           0 :             continue;
    1509           0 :         const int nDataTypeSize = HDF4Dataset::GetDataTypeSize(iNumType);
    1510           0 :         if (nDataTypeSize == 0)
    1511           0 :             continue;
    1512             : 
    1513           0 :         ret.emplace_back(std::make_shared<HDF4SwathAttribute>(
    1514           0 :             GetFullName(), osAttrName, m_poShared, m_poSwathHandle, iNumType,
    1515           0 :             nSize / nDataTypeSize));
    1516             :     }
    1517           0 :     return ret;
    1518             : }
    1519             : 
    1520             : /************************************************************************/
    1521             : /*                          HDF4SwathArray()                            */
    1522             : /************************************************************************/
    1523             : 
    1524           0 : HDF4SwathArray::HDF4SwathArray(
    1525             :     const std::string &osParentName, const std::string &osName,
    1526             :     const std::shared_ptr<HDF4SharedResources> &poShared,
    1527             :     const std::shared_ptr<HDF4SwathHandle> &poSwathHandle,
    1528             :     const std::vector<int32> &aiDimSizes, const std::string &dimNames,
    1529             :     int32 iNumType,
    1530           0 :     const std::vector<std::shared_ptr<GDALDimension>> &groupDims)
    1531             :     : GDALAbstractMDArray(osParentName, osName),
    1532             :       GDALPamMDArray(osParentName, osName, poShared->GetPAM()),
    1533             :       m_poShared(poShared), m_poSwathHandle(poSwathHandle),
    1534             :       m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
    1535             :                                   : GDALExtendedDataType::Create(
    1536           0 :                                         HDF4Dataset::GetDataType(iNumType)))
    1537             : {
    1538             :     CPLStringList aosDimNames(
    1539           0 :         CSLTokenizeString2(dimNames.c_str(), ",", CSLT_HONOURSTRINGS));
    1540           0 :     if (static_cast<size_t>(aosDimNames.size()) == aiDimSizes.size())
    1541             :     {
    1542           0 :         for (int i = 0; i < aosDimNames.size(); i++)
    1543             :         {
    1544           0 :             bool bFound = false;
    1545           0 :             for (const auto &poDim : groupDims)
    1546             :             {
    1547           0 :                 if (poDim->GetName() == aosDimNames[i] &&
    1548           0 :                     poDim->GetSize() == static_cast<GUInt64>(aiDimSizes[i]))
    1549             :                 {
    1550           0 :                     bFound = true;
    1551           0 :                     m_dims.push_back(poDim);
    1552           0 :                     break;
    1553             :                 }
    1554             :             }
    1555           0 :             if (!bFound)
    1556             :             {
    1557           0 :                 m_dims.push_back(std::make_shared<GDALDimension>(
    1558           0 :                     std::string(), aosDimNames[i], std::string(), std::string(),
    1559           0 :                     aiDimSizes[i]));
    1560             :             }
    1561             :         }
    1562             :     }
    1563           0 : }
    1564             : 
    1565             : /************************************************************************/
    1566             : /*                           GetAttributes()                            */
    1567             : /************************************************************************/
    1568             : 
    1569             : std::vector<std::shared_ptr<GDALAttribute>>
    1570           0 : HDF4SwathArray::GetAttributes(CSLConstList) const
    1571             : {
    1572           0 :     CPLMutexHolderD(&hHDF4Mutex);
    1573           0 :     std::vector<std::shared_ptr<GDALAttribute>> ret;
    1574           0 :     int32 iSDS = 0;
    1575           0 :     if (SWsdid(m_poSwathHandle->m_handle, GetName().c_str(), &iSDS) != -1)
    1576             :     {
    1577           0 :         int32 iRank = 0;
    1578           0 :         int32 iNumType = 0;
    1579           0 :         int32 nAttrs = 0;
    1580           0 :         std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
    1581             : 
    1582           0 :         if (SDgetinfo(iSDS, nullptr, &iRank, &aiDimSizes[0], &iNumType,
    1583           0 :                       &nAttrs) == 0)
    1584             :         {
    1585           0 :             for (int32 iAttribute = 0; iAttribute < nAttrs; iAttribute++)
    1586             :             {
    1587           0 :                 std::string osAttrName;
    1588           0 :                 osAttrName.resize(H4_MAX_NC_NAME);
    1589           0 :                 iNumType = 0;
    1590           0 :                 int32 nValues = 0;
    1591           0 :                 SDattrinfo(iSDS, iAttribute, &osAttrName[0], &iNumType,
    1592             :                            &nValues);
    1593           0 :                 osAttrName.resize(strlen(osAttrName.c_str()));
    1594           0 :                 ret.emplace_back(std::make_shared<HDF4SDAttribute>(
    1595           0 :                     GetFullName(), osAttrName, m_poShared, m_poSwathHandle,
    1596           0 :                     nullptr, iSDS, iAttribute, iNumType, nValues));
    1597             :             }
    1598             :         }
    1599             :     }
    1600           0 :     return ret;
    1601             : }
    1602             : 
    1603             : /************************************************************************/
    1604             : /*                           ReadPixels()                               */
    1605             : /************************************************************************/
    1606             : 
    1607             : union ReadFunc
    1608             : {
    1609             :     intn (*pReadField)(int32, const char *, int32[], int32[], int32[], VOIDP);
    1610             :     intn (*pReadData)(int32, int32[], int32[], int32[], VOIDP);
    1611             : };
    1612             : 
    1613          24 : static inline void IncrPointer(GByte *&ptr, GPtrDiff_t nInc, size_t nIncSize)
    1614             : {
    1615          24 :     if (nInc < 0)
    1616           6 :         ptr -= (-nInc) * nIncSize;
    1617             :     else
    1618          18 :         ptr += nInc * nIncSize;
    1619          24 : }
    1620             : 
    1621           4 : static bool ReadPixels(const GUInt64 *arrayStartIdx, const size_t *count,
    1622             :                        const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    1623             :                        const GDALExtendedDataType &bufferDataType,
    1624             :                        void *pDstBuffer,
    1625             :                        const std::shared_ptr<HDF4SharedResources> &poShared,
    1626             :                        const GDALExtendedDataType &dt,
    1627             :                        const std::vector<std::shared_ptr<GDALDimension>> &dims,
    1628             :                        int32 handle, const char *pszFieldName,
    1629             :                        ReadFunc readFunc)
    1630             : {
    1631           8 :     CPLMutexHolderD(&hHDF4Mutex);
    1632             :     /* -------------------------------------------------------------------- */
    1633             :     /*      HDF files with external data files, such as some landsat        */
    1634             :     /*      products (eg. data/hdf/L1G) need to be told what directory      */
    1635             :     /*      to look in to find the external files.  Normally this is the    */
    1636             :     /*      directory holding the hdf file.                                 */
    1637             :     /* -------------------------------------------------------------------- */
    1638           4 :     HXsetdir(CPLGetPath(poShared->GetFilename().c_str()));
    1639             : 
    1640           4 :     const size_t nDims(dims.size());
    1641           8 :     std::vector<int32> sw_start(nDims);
    1642           8 :     std::vector<int32> sw_stride(nDims);
    1643           8 :     std::vector<int32> sw_edge(nDims);
    1644           8 :     std::vector<GPtrDiff_t> newBufferStride(nDims);
    1645           4 :     GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
    1646           4 :     const size_t nBufferDataTypeSize = bufferDataType.GetSize();
    1647          14 :     for (size_t i = 0; i < nDims; i++)
    1648             :     {
    1649          10 :         sw_start[i] = static_cast<int>(arrayStartIdx[i]);
    1650          10 :         sw_stride[i] = static_cast<int>(arrayStep[i]);
    1651          10 :         sw_edge[i] = static_cast<int>(count[i]);
    1652          10 :         newBufferStride[i] = bufferStride[i];
    1653          10 :         if (sw_stride[i] < 0)
    1654             :         {
    1655             :             // SWreadfield() doesn't like negative step / array stride, so
    1656             :             // transform the request to a classic "left-to-right" one
    1657           0 :             sw_start[i] += sw_stride[i] * (sw_edge[i] - 1);
    1658           0 :             sw_stride[i] = -sw_stride[i];
    1659           0 :             pabyDstBuffer +=
    1660           0 :                 (sw_edge[i] - 1) * newBufferStride[i] * nBufferDataTypeSize;
    1661           0 :             newBufferStride[i] = -newBufferStride[i];
    1662             :         }
    1663             :     }
    1664           4 :     size_t nExpectedStride = 1;
    1665           4 :     bool bContiguousStride = true;
    1666          14 :     for (size_t i = nDims; i > 0;)
    1667             :     {
    1668          10 :         --i;
    1669          10 :         if (newBufferStride[i] != static_cast<GPtrDiff_t>(nExpectedStride))
    1670             :         {
    1671           3 :             bContiguousStride = false;
    1672             :         }
    1673          10 :         nExpectedStride *= count[i];
    1674             :     }
    1675           4 :     if (bufferDataType == dt && bContiguousStride)
    1676             :     {
    1677             :         auto status =
    1678             :             pszFieldName
    1679           3 :                 ? readFunc.pReadField(handle, pszFieldName, &sw_start[0],
    1680           0 :                                       &sw_stride[0], &sw_edge[0], pabyDstBuffer)
    1681           3 :                 : readFunc.pReadData(handle, &sw_start[0], &sw_stride[0],
    1682           3 :                                      &sw_edge[0], pabyDstBuffer);
    1683           3 :         return status == 0;
    1684             :     }
    1685             :     auto pabyTemp = static_cast<GByte *>(
    1686           1 :         VSI_MALLOC2_VERBOSE(dt.GetSize(), nExpectedStride));
    1687           1 :     if (pabyTemp == nullptr)
    1688           0 :         return false;
    1689             :     auto status =
    1690           1 :         pszFieldName ? readFunc.pReadField(handle, pszFieldName, &sw_start[0],
    1691           0 :                                            &sw_stride[0], &sw_edge[0], pabyTemp)
    1692           1 :                      : readFunc.pReadData(handle, &sw_start[0], &sw_stride[0],
    1693           1 :                                           &sw_edge[0], pabyTemp);
    1694           1 :     if (status != 0)
    1695             :     {
    1696           0 :         VSIFree(pabyTemp);
    1697           0 :         return false;
    1698             :     }
    1699             : 
    1700           1 :     const size_t nSrcDataTypeSize = dt.GetSize();
    1701           2 :     std::vector<size_t> anStackCount(nDims);
    1702           1 :     GByte *pabySrc = pabyTemp;
    1703           1 :     std::vector<GByte *> pabyDstBufferStack(nDims + 1);
    1704           1 :     pabyDstBufferStack[0] = pabyDstBuffer;
    1705           1 :     size_t iDim = 0;
    1706          11 : lbl_next_depth:
    1707          11 :     if (iDim == nDims)
    1708             :     {
    1709           4 :         GDALExtendedDataType::CopyValue(pabySrc, dt, pabyDstBufferStack[nDims],
    1710             :                                         bufferDataType);
    1711           4 :         pabySrc += nSrcDataTypeSize;
    1712             :     }
    1713             :     else
    1714             :     {
    1715           7 :         anStackCount[iDim] = count[iDim];
    1716             :         while (true)
    1717             :         {
    1718          10 :             ++iDim;
    1719          10 :             pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
    1720          10 :             goto lbl_next_depth;
    1721          10 :         lbl_return_to_caller_in_loop:
    1722          10 :             --iDim;
    1723          10 :             --anStackCount[iDim];
    1724          10 :             if (anStackCount[iDim] == 0)
    1725           7 :                 break;
    1726           3 :             IncrPointer(pabyDstBufferStack[iDim], newBufferStride[iDim],
    1727             :                         nBufferDataTypeSize);
    1728             :         }
    1729             :     }
    1730          11 :     if (iDim > 0)
    1731          10 :         goto lbl_return_to_caller_in_loop;
    1732             : 
    1733           1 :     VSIFree(pabyTemp);
    1734           1 :     return true;
    1735             : }
    1736             : 
    1737             : /************************************************************************/
    1738             : /*                               IRead()                                */
    1739             : /************************************************************************/
    1740             : 
    1741           0 : bool HDF4SwathArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
    1742             :                            const GInt64 *arrayStep,
    1743             :                            const GPtrDiff_t *bufferStride,
    1744             :                            const GDALExtendedDataType &bufferDataType,
    1745             :                            void *pDstBuffer) const
    1746             : {
    1747             :     ReadFunc readFunc;
    1748           0 :     readFunc.pReadField = SWreadfield;
    1749           0 :     return ReadPixels(arrayStartIdx, count, arrayStep, bufferStride,
    1750           0 :                       bufferDataType, pDstBuffer, m_poShared, m_dt, m_dims,
    1751           0 :                       m_poSwathHandle->m_handle, GetName().c_str(), readFunc);
    1752             : }
    1753             : 
    1754             : /************************************************************************/
    1755             : /*                          GetRawNoDataValue()                         */
    1756             : /************************************************************************/
    1757             : 
    1758           0 : const void *HDF4SwathArray::GetRawNoDataValue() const
    1759             : {
    1760           0 :     if (!m_abyNoData.empty())
    1761           0 :         return m_abyNoData.data();
    1762           0 :     m_abyNoData.resize(GetDataType().GetSize());
    1763             : 
    1764           0 :     auto poAttr = GetAttribute("_FillValue");
    1765           0 :     if (poAttr)
    1766             :     {
    1767           0 :         const double dfVal = poAttr->ReadAsDouble();
    1768           0 :         GDALExtendedDataType::CopyValue(
    1769           0 :             &dfVal, GDALExtendedDataType::Create(GDT_Float64), &m_abyNoData[0],
    1770             :             GetDataType());
    1771           0 :         return m_abyNoData.data();
    1772             :     }
    1773             : 
    1774           0 :     CPLMutexHolderD(&hHDF4Mutex);
    1775           0 :     if (SWgetfillvalue(m_poSwathHandle->m_handle, GetName().c_str(),
    1776           0 :                        &m_abyNoData[0]) != -1)
    1777             :     {
    1778           0 :         return m_abyNoData.data();
    1779             :     }
    1780             : 
    1781           0 :     m_abyNoData.clear();
    1782           0 :     return nullptr;
    1783             : }
    1784             : 
    1785             : /************************************************************************/
    1786             : /*                      HDF4AbstractAttribute()                         */
    1787             : /************************************************************************/
    1788             : 
    1789          28 : HDF4AbstractAttribute::HDF4AbstractAttribute(
    1790             :     const std::string &osParentName, const std::string &osName,
    1791             :     const std::shared_ptr<HDF4SharedResources> &poShared, int32 iNumType,
    1792           0 :     int32 nValues)
    1793             :     :
    1794             : #if !defined(COMPILER_WARNS_ABOUT_ABSTRACT_VBASE_INIT)
    1795             :       GDALAbstractMDArray(osParentName, osName),
    1796             : #endif
    1797             :       GDALAttribute(osParentName, osName), m_poShared(poShared),
    1798             :       m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
    1799             :                                   : GDALExtendedDataType::Create(
    1800             :                                         HDF4Dataset::GetDataType(iNumType))),
    1801          28 :       m_nValues(nValues)
    1802             : {
    1803          28 :     if (m_dt.GetClass() != GEDTC_STRING && m_nValues > 1)
    1804             :     {
    1805          12 :         m_dims.emplace_back(std::make_shared<GDALDimension>(
    1806          18 :             std::string(), "dim", std::string(), std::string(), nValues));
    1807             :     }
    1808          28 : }
    1809             : 
    1810             : /************************************************************************/
    1811             : /*                               IRead()                                */
    1812             : /************************************************************************/
    1813             : 
    1814          13 : bool HDF4AbstractAttribute::IRead(const GUInt64 *arrayStartIdx,
    1815             :                                   const size_t *count, const GInt64 *arrayStep,
    1816             :                                   const GPtrDiff_t *bufferStride,
    1817             :                                   const GDALExtendedDataType &bufferDataType,
    1818             :                                   void *pDstBuffer) const
    1819             : {
    1820          26 :     CPLMutexHolderD(&hHDF4Mutex);
    1821          13 :     if (m_dt.GetClass() == GEDTC_STRING)
    1822             :     {
    1823          11 :         if (bufferDataType.GetClass() != GEDTC_STRING)
    1824           0 :             return false;
    1825          11 :         char *pszStr = static_cast<char *>(VSIMalloc(m_nValues + 1));
    1826          11 :         if (pszStr == nullptr)
    1827           0 :             return false;
    1828          11 :         ReadData(pszStr);
    1829          11 :         pszStr[m_nValues] = 0;
    1830          11 :         *static_cast<char **>(pDstBuffer) = pszStr;
    1831          11 :         return true;
    1832             :     }
    1833             : 
    1834           2 :     std::vector<GByte> abyTemp(m_nValues * m_dt.GetSize());
    1835           2 :     ReadData(&abyTemp[0]);
    1836           2 :     GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
    1837          10 :     for (size_t i = 0; i < (m_dims.empty() ? 1 : count[0]); ++i)
    1838             :     {
    1839             :         const size_t idx =
    1840           8 :             m_dims.empty()
    1841           8 :                 ? 0
    1842           8 :                 : static_cast<size_t>(arrayStartIdx[0] + i * arrayStep[0]);
    1843           8 :         GDALExtendedDataType::CopyValue(&abyTemp[0] + idx * m_dt.GetSize(),
    1844           8 :                                         m_dt, pabyDstBuffer, bufferDataType);
    1845           8 :         if (!m_dims.empty())
    1846           8 :             pabyDstBuffer += bufferStride[0] * bufferDataType.GetSize();
    1847             :     }
    1848             : 
    1849           2 :     return true;
    1850             : }
    1851             : 
    1852             : /************************************************************************/
    1853             : /*                            GetGroupNames()                           */
    1854             : /************************************************************************/
    1855             : 
    1856           0 : std::vector<std::string> HDF4EOSGridsGroup::GetGroupNames(CSLConstList) const
    1857             : {
    1858           0 :     CPLMutexHolderD(&hHDF4Mutex);
    1859           0 :     std::vector<std::string> res;
    1860             : 
    1861           0 :     int32 nStrBufSize = 0;
    1862           0 :     GDinqgrid(m_poShared->GetFilename().c_str(), nullptr, &nStrBufSize);
    1863             : 
    1864           0 :     std::string osGridList;
    1865           0 :     osGridList.resize(nStrBufSize);
    1866           0 :     GDinqgrid(m_poShared->GetFilename().c_str(), &osGridList[0], &nStrBufSize);
    1867             : 
    1868             :     CPLStringList aosGrids(
    1869           0 :         CSLTokenizeString2(osGridList.c_str(), ",", CSLT_HONOURSTRINGS));
    1870           0 :     for (int i = 0; i < aosGrids.size(); i++)
    1871           0 :         res.push_back(aosGrids[i]);
    1872             : 
    1873           0 :     return res;
    1874             : }
    1875             : 
    1876             : /************************************************************************/
    1877             : /*                             OpenGroup()                              */
    1878             : /************************************************************************/
    1879             : 
    1880             : std::shared_ptr<GDALGroup>
    1881           0 : HDF4EOSGridsGroup::OpenGroup(const std::string &osName, CSLConstList) const
    1882             : {
    1883           0 :     CPLMutexHolderD(&hHDF4Mutex);
    1884             : 
    1885           0 :     int32 gdHandle = GDattach(m_poGDsHandle->m_handle, osName.c_str());
    1886           0 :     if (gdHandle < 0)
    1887             :     {
    1888           0 :         return nullptr;
    1889             :     }
    1890             : 
    1891           0 :     return std::make_shared<HDF4EOSGridGroup>(
    1892           0 :         GetFullName(), osName, m_poShared,
    1893           0 :         std::make_shared<HDF4GDHandle>(m_poGDsHandle, gdHandle));
    1894             : }
    1895             : 
    1896             : /************************************************************************/
    1897             : /*                            GetDimensions()                           */
    1898             : /************************************************************************/
    1899             : 
    1900             : std::vector<std::shared_ptr<GDALDimension>>
    1901           0 : HDF4EOSGridGroup::GetDimensions(CSLConstList) const
    1902             : {
    1903           0 :     if (!m_dims.empty())
    1904           0 :         return m_dims;
    1905             : 
    1906           0 :     int32 iProjCode = 0;
    1907           0 :     int32 iZoneCode = 0;
    1908           0 :     int32 iSphereCode = 0;
    1909             :     double adfProjParams[15];
    1910             : 
    1911           0 :     GDprojinfo(m_poGDHandle->m_handle, &iProjCode, &iZoneCode, &iSphereCode,
    1912             :                adfProjParams);
    1913             : 
    1914           0 :     int32 nXSize = 0;
    1915           0 :     int32 nYSize = 0;
    1916             :     double adfUpLeft[2];
    1917             :     double adfLowRight[2];
    1918           0 :     const bool bGotGridInfo = GDgridinfo(m_poGDHandle->m_handle, &nXSize,
    1919           0 :                                          &nYSize, adfUpLeft, adfLowRight) >= 0;
    1920           0 :     if (bGotGridInfo)
    1921             :     {
    1922           0 :         m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
    1923           0 :                       GetFullName(), "YDim", GDAL_DIM_TYPE_HORIZONTAL_Y,
    1924             :                       "NORTH", nYSize),
    1925           0 :                   std::make_shared<GDALDimensionWeakIndexingVar>(
    1926           0 :                       GetFullName(), "XDim", GDAL_DIM_TYPE_HORIZONTAL_X, "EAST",
    1927           0 :                       nXSize)};
    1928             : 
    1929           0 :         if (iProjCode == 0)
    1930             :         {
    1931           0 :             adfLowRight[0] = CPLPackedDMSToDec(adfLowRight[0]);
    1932           0 :             adfLowRight[1] = CPLPackedDMSToDec(adfLowRight[1]);
    1933           0 :             adfUpLeft[0] = CPLPackedDMSToDec(adfUpLeft[0]);
    1934           0 :             adfUpLeft[1] = CPLPackedDMSToDec(adfUpLeft[1]);
    1935             :         }
    1936             : 
    1937           0 :         m_varX = GDALMDArrayRegularlySpaced::Create(
    1938           0 :             GetFullName(), m_dims[1]->GetName(), m_dims[1], adfUpLeft[0],
    1939           0 :             (adfLowRight[0] - adfUpLeft[0]) / nXSize, 0.5);
    1940           0 :         m_dims[1]->SetIndexingVariable(m_varX);
    1941             : 
    1942           0 :         m_varY = GDALMDArrayRegularlySpaced::Create(
    1943           0 :             GetFullName(), m_dims[0]->GetName(), m_dims[0], adfUpLeft[1],
    1944           0 :             (adfLowRight[1] - adfUpLeft[1]) / nYSize, 0.5);
    1945           0 :         m_dims[0]->SetIndexingVariable(m_varY);
    1946             :     }
    1947             : 
    1948             : #if 0
    1949             :     // Dimensions seem to be never defined properly on eos_grids datasets.
    1950             : 
    1951             :     std::string dimNames;
    1952             :     int32 nStrBufSize = 0;
    1953             :     if( GDnentries( m_poGDHandle->m_handle, HDFE_NENTDIM, &nStrBufSize ) < 0
    1954             :         || nStrBufSize <= 0 )
    1955             :     {
    1956             :         return m_dims;
    1957             :     }
    1958             :     dimNames.resize(nStrBufSize);
    1959             :     int32 nDims = GDinqdims(m_poGDHandle->m_handle, &dimNames[0], nullptr);
    1960             :     std::vector<int32> aiDimSizes(nDims);
    1961             :     GDinqdims(m_poGDHandle->m_handle, &dimNames[0], &aiDimSizes[0]);
    1962             :     CPLStringList aosDimNames(CSLTokenizeString2(
    1963             :         dimNames.c_str(), ",", CSLT_HONOURSTRINGS ));
    1964             :     if( static_cast<size_t>(aosDimNames.size()) == aiDimSizes.size() )
    1965             :     {
    1966             :         for( int i = 0; i < aosDimNames.size(); i++ )
    1967             :         {
    1968             :             m_dims.push_back(std::make_shared<GDALDimension>(GetFullName(),
    1969             :                                                              aosDimNames[i],
    1970             :                                                              std::string(),
    1971             :                                                              std::string(),
    1972             :                                                              aiDimSizes[i]));
    1973             :         }
    1974             :     }
    1975             : #endif
    1976           0 :     return m_dims;
    1977             : }
    1978             : 
    1979             : /************************************************************************/
    1980             : /*                         GetMDArrayNames()                            */
    1981             : /************************************************************************/
    1982             : 
    1983           0 : std::vector<std::string> HDF4EOSGridGroup::GetMDArrayNames(CSLConstList) const
    1984             : {
    1985           0 :     GetDimensions();
    1986           0 :     std::vector<std::string> ret;
    1987           0 :     if (m_varX && m_varY)
    1988             :     {
    1989           0 :         ret.push_back(m_varY->GetName());
    1990           0 :         ret.push_back(m_varX->GetName());
    1991             :     }
    1992           0 :     return ret;
    1993             : }
    1994             : 
    1995             : /************************************************************************/
    1996             : /*                           OpenMDArray()                              */
    1997             : /************************************************************************/
    1998             : 
    1999             : std::shared_ptr<GDALMDArray>
    2000           0 : HDF4EOSGridGroup::OpenMDArray(const std::string &osName, CSLConstList) const
    2001             : {
    2002           0 :     if (m_varX && osName == m_varX->GetName())
    2003           0 :         return m_varX;
    2004           0 :     if (m_varY && osName == m_varY->GetName())
    2005           0 :         return m_varY;
    2006           0 :     return nullptr;
    2007             : }
    2008             : 
    2009             : /************************************************************************/
    2010             : /*                            GetGroupNames()                           */
    2011             : /************************************************************************/
    2012             : 
    2013           0 : std::vector<std::string> HDF4EOSGridGroup::GetGroupNames(CSLConstList) const
    2014             : {
    2015           0 :     std::vector<std::string> res;
    2016           0 :     res.push_back("Data Fields");
    2017           0 :     return res;
    2018             : }
    2019             : 
    2020             : /************************************************************************/
    2021             : /*                             OpenGroup()                              */
    2022             : /************************************************************************/
    2023             : 
    2024             : std::shared_ptr<GDALGroup>
    2025           0 : HDF4EOSGridGroup::OpenGroup(const std::string &osName, CSLConstList) const
    2026             : {
    2027           0 :     if (osName == "Data Fields")
    2028             :     {
    2029           0 :         return std::make_shared<HDF4EOSGridSubGroup>(
    2030           0 :             GetFullName(), osName, m_poShared, m_poGDHandle, HDFE_NENTDFLD,
    2031           0 :             GetDimensions());
    2032             :     }
    2033           0 :     return nullptr;
    2034             : }
    2035             : 
    2036             : /************************************************************************/
    2037             : /*                           GetAttributes()                            */
    2038             : /************************************************************************/
    2039             : 
    2040             : std::vector<std::shared_ptr<GDALAttribute>>
    2041           0 : HDF4EOSGridGroup::GetAttributes(CSLConstList) const
    2042             : {
    2043           0 :     CPLMutexHolderD(&hHDF4Mutex);
    2044           0 :     std::vector<std::shared_ptr<GDALAttribute>> ret;
    2045           0 :     int32 nStrBufSize = 0;
    2046           0 :     if (GDinqattrs(m_poGDHandle->m_handle, nullptr, &nStrBufSize) <= 0 ||
    2047           0 :         nStrBufSize <= 0)
    2048             :     {
    2049           0 :         return ret;
    2050             :     }
    2051           0 :     std::string osAttrs;
    2052           0 :     osAttrs.resize(nStrBufSize);
    2053           0 :     GDinqattrs(m_poGDHandle->m_handle, &osAttrs[0], &nStrBufSize);
    2054             : 
    2055             :     CPLStringList aosAttrs(
    2056           0 :         CSLTokenizeString2(osAttrs.c_str(), ",", CSLT_HONOURSTRINGS));
    2057           0 :     for (int i = 0; i < aosAttrs.size(); i++)
    2058             :     {
    2059           0 :         int32 iNumType = 0;
    2060           0 :         int32 nSize = 0;
    2061             : 
    2062           0 :         if (GDattrinfo(m_poGDHandle->m_handle, aosAttrs[i], &iNumType, &nSize) <
    2063             :             0)
    2064           0 :             continue;
    2065           0 :         const int nDataTypeSize = HDF4Dataset::GetDataTypeSize(iNumType);
    2066           0 :         if (nDataTypeSize == 0)
    2067           0 :             continue;
    2068             : 
    2069           0 :         ret.emplace_back(std::make_shared<HDF4EOSGridAttribute>(
    2070           0 :             GetFullName(), aosAttrs[i], m_poShared, m_poGDHandle, iNumType,
    2071           0 :             nSize / nDataTypeSize));
    2072             :     }
    2073           0 :     return ret;
    2074             : }
    2075             : 
    2076             : /************************************************************************/
    2077             : /*                         GetMDArrayNames()                            */
    2078             : /************************************************************************/
    2079             : 
    2080             : std::vector<std::string>
    2081           0 : HDF4EOSGridSubGroup::GetMDArrayNames(CSLConstList) const
    2082             : {
    2083           0 :     std::vector<std::string> ret;
    2084             : 
    2085           0 :     int32 nStrBufSize = 0;
    2086             :     const int32 nFields =
    2087           0 :         GDnentries(m_poGDHandle->m_handle, m_entryType, &nStrBufSize);
    2088           0 :     std::string osFieldList;
    2089           0 :     osFieldList.resize(nStrBufSize);
    2090           0 :     std::vector<int32> ranks(nFields);
    2091           0 :     std::vector<int32> numberTypes(nFields);
    2092             : 
    2093           0 :     CPLAssert(m_entryType == HDFE_NENTDFLD);
    2094           0 :     GDinqfields(m_poGDHandle->m_handle, &osFieldList[0], &ranks[0],
    2095           0 :                 &numberTypes[0]);
    2096             : 
    2097             :     CPLStringList aosFields(
    2098           0 :         CSLTokenizeString2(osFieldList.c_str(), ",", CSLT_HONOURSTRINGS));
    2099           0 :     for (int i = 0; i < aosFields.size(); i++)
    2100           0 :         ret.push_back(aosFields[i]);
    2101             : 
    2102           0 :     return ret;
    2103             : }
    2104             : 
    2105             : /************************************************************************/
    2106             : /*                           OpenMDArray()                              */
    2107             : /************************************************************************/
    2108             : 
    2109             : std::shared_ptr<GDALMDArray>
    2110           0 : HDF4EOSGridSubGroup::OpenMDArray(const std::string &osName, CSLConstList) const
    2111             : {
    2112           0 :     CPLMutexHolderD(&hHDF4Mutex);
    2113             : 
    2114             :     int32 iRank;
    2115             :     int32 iNumType;
    2116           0 :     std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
    2117           0 :     std::string dimNames;
    2118             : 
    2119           0 :     int32 nStrBufSize = 0;
    2120           0 :     GDnentries(m_poGDHandle->m_handle, HDFE_NENTDIM, &nStrBufSize);
    2121           0 :     if (nStrBufSize <= 0)
    2122           0 :         dimNames.resize(HDFE_DIMBUFSIZE);
    2123             :     else
    2124           0 :         dimNames.resize(nStrBufSize);
    2125           0 :     if (GDfieldinfo(m_poGDHandle->m_handle, osName.c_str(), &iRank,
    2126           0 :                     &aiDimSizes[0], &iNumType, &dimNames[0]) < 0)
    2127             :     {
    2128           0 :         return nullptr;
    2129             :     }
    2130           0 :     aiDimSizes.resize(iRank);
    2131           0 :     dimNames.resize(strlen(dimNames.c_str()));
    2132             : 
    2133           0 :     return HDF4EOSGridArray::Create(GetFullName(), osName, m_poShared,
    2134           0 :                                     m_poGDHandle, aiDimSizes, dimNames,
    2135           0 :                                     iNumType, m_groupDims);
    2136             : }
    2137             : 
    2138             : /************************************************************************/
    2139             : /*                         HDF4EOSGridArray()                           */
    2140             : /************************************************************************/
    2141             : 
    2142           0 : HDF4EOSGridArray::HDF4EOSGridArray(
    2143             :     const std::string &osParentName, const std::string &osName,
    2144             :     const std::shared_ptr<HDF4SharedResources> &poShared,
    2145             :     const std::shared_ptr<HDF4GDHandle> &poGDHandle,
    2146             :     const std::vector<int32> &aiDimSizes, const std::string &dimNames,
    2147             :     int32 iNumType,
    2148           0 :     const std::vector<std::shared_ptr<GDALDimension>> &groupDims)
    2149             :     : GDALAbstractMDArray(osParentName, osName),
    2150             :       GDALPamMDArray(osParentName, osName, poShared->GetPAM()),
    2151             :       m_poShared(poShared), m_poGDHandle(poGDHandle),
    2152             :       m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
    2153             :                                   : GDALExtendedDataType::Create(
    2154           0 :                                         HDF4Dataset::GetDataType(iNumType)))
    2155             : {
    2156             :     CPLStringList aosDimNames(
    2157           0 :         CSLTokenizeString2(dimNames.c_str(), ",", CSLT_HONOURSTRINGS));
    2158           0 :     if (static_cast<size_t>(aosDimNames.size()) == aiDimSizes.size())
    2159             :     {
    2160           0 :         for (int i = 0; i < aosDimNames.size(); i++)
    2161             :         {
    2162           0 :             bool bFound = false;
    2163           0 :             for (const auto &poDim : groupDims)
    2164             :             {
    2165           0 :                 if (poDim->GetName() == aosDimNames[i] &&
    2166           0 :                     poDim->GetSize() == static_cast<GUInt64>(aiDimSizes[i]))
    2167             :                 {
    2168           0 :                     bFound = true;
    2169           0 :                     m_dims.push_back(poDim);
    2170           0 :                     break;
    2171             :                 }
    2172             :             }
    2173           0 :             if (!bFound)
    2174             :             {
    2175           0 :                 m_dims.push_back(std::make_shared<GDALDimension>(
    2176           0 :                     std::string(), aosDimNames[i], std::string(), std::string(),
    2177           0 :                     aiDimSizes[i]));
    2178             :             }
    2179             :         }
    2180             :     }
    2181           0 : }
    2182             : 
    2183             : /************************************************************************/
    2184             : /*                           GetAttributes()                            */
    2185             : /************************************************************************/
    2186             : 
    2187             : std::vector<std::shared_ptr<GDALAttribute>>
    2188           0 : HDF4EOSGridArray::GetAttributes(CSLConstList) const
    2189             : {
    2190           0 :     CPLMutexHolderD(&hHDF4Mutex);
    2191           0 :     std::vector<std::shared_ptr<GDALAttribute>> ret;
    2192           0 :     int32 iSDS = 0;
    2193           0 :     if (GDsdid(m_poGDHandle->m_handle, GetName().c_str(), &iSDS) != -1)
    2194             :     {
    2195           0 :         int32 iRank = 0;
    2196           0 :         int32 iNumType = 0;
    2197           0 :         int32 nAttrs = 0;
    2198           0 :         std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
    2199             : 
    2200           0 :         if (SDgetinfo(iSDS, nullptr, &iRank, &aiDimSizes[0], &iNumType,
    2201           0 :                       &nAttrs) == 0)
    2202             :         {
    2203           0 :             for (int32 iAttribute = 0; iAttribute < nAttrs; iAttribute++)
    2204             :             {
    2205           0 :                 std::string osAttrName;
    2206           0 :                 osAttrName.resize(H4_MAX_NC_NAME);
    2207           0 :                 iNumType = 0;
    2208           0 :                 int32 nValues = 0;
    2209           0 :                 SDattrinfo(iSDS, iAttribute, &osAttrName[0], &iNumType,
    2210             :                            &nValues);
    2211           0 :                 osAttrName.resize(strlen(osAttrName.c_str()));
    2212           0 :                 ret.emplace_back(std::make_shared<HDF4SDAttribute>(
    2213           0 :                     GetFullName(), osAttrName, m_poShared, nullptr,
    2214           0 :                     m_poGDHandle, iSDS, iAttribute, iNumType, nValues));
    2215             :             }
    2216             :         }
    2217             :     }
    2218           0 :     return ret;
    2219             : }
    2220             : 
    2221             : /************************************************************************/
    2222             : /*                          GetRawNoDataValue()                         */
    2223             : /************************************************************************/
    2224             : 
    2225           0 : const void *HDF4EOSGridArray::GetRawNoDataValue() const
    2226             : {
    2227           0 :     if (!m_abyNoData.empty())
    2228           0 :         return m_abyNoData.data();
    2229           0 :     m_abyNoData.resize(GetDataType().GetSize());
    2230             : 
    2231           0 :     auto poAttr = GetAttribute("_FillValue");
    2232           0 :     if (poAttr)
    2233             :     {
    2234           0 :         const double dfVal = poAttr->ReadAsDouble();
    2235           0 :         GDALExtendedDataType::CopyValue(
    2236           0 :             &dfVal, GDALExtendedDataType::Create(GDT_Float64), &m_abyNoData[0],
    2237             :             GetDataType());
    2238           0 :         return m_abyNoData.data();
    2239             :     }
    2240             : 
    2241           0 :     CPLMutexHolderD(&hHDF4Mutex);
    2242           0 :     if (GDgetfillvalue(m_poGDHandle->m_handle, GetName().c_str(),
    2243           0 :                        &m_abyNoData[0]) != -1)
    2244             :     {
    2245           0 :         return m_abyNoData.data();
    2246             :     }
    2247           0 :     m_abyNoData.clear();
    2248           0 :     return nullptr;
    2249             : }
    2250             : 
    2251             : /************************************************************************/
    2252             : /*                           GetOffsetOrScale()                         */
    2253             : /************************************************************************/
    2254             : 
    2255           2 : static double GetOffsetOrScale(const GDALMDArray *poArray,
    2256             :                                const char *pszAttrName, double dfDefaultValue,
    2257             :                                bool *pbHasVal, GDALDataType *peStorageType)
    2258             : {
    2259           6 :     auto poAttr = poArray->GetAttribute(pszAttrName);
    2260           2 :     if (poAttr && (poAttr->GetDataType().GetNumericDataType() == GDT_Float32 ||
    2261           2 :                    poAttr->GetDataType().GetNumericDataType() == GDT_Float64))
    2262             :     {
    2263           0 :         if (pbHasVal)
    2264           0 :             *pbHasVal = true;
    2265           0 :         if (peStorageType)
    2266           0 :             *peStorageType = poAttr->GetDataType().GetNumericDataType();
    2267           0 :         return poAttr->ReadAsDouble();
    2268             :     }
    2269           2 :     if (pbHasVal)
    2270           2 :         *pbHasVal = false;
    2271           2 :     return dfDefaultValue;
    2272             : }
    2273             : 
    2274             : /************************************************************************/
    2275             : /*                              GetOffset()                             */
    2276             : /************************************************************************/
    2277             : 
    2278           1 : static double GetOffset(const GDALMDArray *poArray, bool *pbHasOffset,
    2279             :                         GDALDataType *peStorageType)
    2280             : {
    2281           1 :     return GetOffsetOrScale(poArray, "add_offset", 0, pbHasOffset,
    2282           1 :                             peStorageType);
    2283             : }
    2284             : 
    2285             : /************************************************************************/
    2286             : /*                              GetOffset()                             */
    2287             : /************************************************************************/
    2288             : 
    2289           0 : double HDF4EOSGridArray::GetOffset(bool *pbHasOffset,
    2290             :                                    GDALDataType *peStorageType) const
    2291             : {
    2292           0 :     return ::GetOffset(this, pbHasOffset, peStorageType);
    2293             : }
    2294             : 
    2295             : /************************************************************************/
    2296             : /*                               GetScale()                             */
    2297             : /************************************************************************/
    2298             : 
    2299           1 : static double GetScale(const GDALMDArray *poArray, bool *pbHasScale,
    2300             :                        GDALDataType *peStorageType)
    2301             : {
    2302           1 :     return GetOffsetOrScale(poArray, "scale_factor", 1, pbHasScale,
    2303           1 :                             peStorageType);
    2304             : }
    2305             : 
    2306             : /************************************************************************/
    2307             : /*                               GetScale()                             */
    2308             : /************************************************************************/
    2309             : 
    2310           0 : double HDF4EOSGridArray::GetScale(bool *pbHasScale,
    2311             :                                   GDALDataType *peStorageType) const
    2312             : {
    2313           0 :     return ::GetScale(this, pbHasScale, peStorageType);
    2314             : }
    2315             : 
    2316             : /************************************************************************/
    2317             : /*                             GetUnit()                                */
    2318             : /************************************************************************/
    2319             : 
    2320           0 : const std::string &HDF4EOSGridArray::GetUnit() const
    2321             : {
    2322           0 :     auto poAttr = GetAttribute("units");
    2323           0 :     if (poAttr && poAttr->GetDataType().GetClass() == GEDTC_STRING)
    2324             :     {
    2325           0 :         const char *pszVal = poAttr->ReadAsString();
    2326           0 :         if (pszVal)
    2327           0 :             m_osUnit = pszVal;
    2328             :     }
    2329           0 :     return m_osUnit;
    2330             : }
    2331             : 
    2332             : /************************************************************************/
    2333             : /*                          GetSpatialRef()                             */
    2334             : /************************************************************************/
    2335             : 
    2336           0 : std::shared_ptr<OGRSpatialReference> HDF4EOSGridArray::GetSpatialRef() const
    2337             : {
    2338           0 :     CPLMutexHolderD(&hHDF4Mutex);
    2339           0 :     int32 iProjCode = 0;
    2340           0 :     int32 iZoneCode = 0;
    2341           0 :     int32 iSphereCode = 0;
    2342             :     double adfProjParams[15];
    2343             : 
    2344           0 :     if (GDprojinfo(m_poGDHandle->m_handle, &iProjCode, &iZoneCode, &iSphereCode,
    2345           0 :                    adfProjParams) >= 0)
    2346             :     {
    2347           0 :         auto poSRS(std::make_shared<OGRSpatialReference>());
    2348           0 :         poSRS->importFromUSGS(iProjCode, iZoneCode, adfProjParams, iSphereCode,
    2349             :                               USGS_ANGLE_RADIANS);
    2350           0 :         int iDimY = -1;
    2351           0 :         int iDimX = -1;
    2352           0 :         if (m_dims.size() >= 2)
    2353             :         {
    2354           0 :             iDimY = 1 + static_cast<int>(m_dims.size() - 2);
    2355           0 :             iDimX = 1 + static_cast<int>(m_dims.size() - 1);
    2356             :         }
    2357           0 :         if (iDimX > 0 && iDimY > 0)
    2358             :         {
    2359           0 :             poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    2360           0 :             if (poSRS->GetDataAxisToSRSAxisMapping() == std::vector<int>{2, 1})
    2361           0 :                 poSRS->SetDataAxisToSRSAxisMapping({iDimY, iDimX});
    2362             :             else
    2363           0 :                 poSRS->SetDataAxisToSRSAxisMapping({iDimX, iDimY});
    2364             :         }
    2365           0 :         return poSRS;
    2366             :     }
    2367           0 :     return nullptr;
    2368             : }
    2369             : 
    2370             : /************************************************************************/
    2371             : /*                               IRead()                                */
    2372             : /************************************************************************/
    2373             : 
    2374           0 : bool HDF4EOSGridArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
    2375             :                              const GInt64 *arrayStep,
    2376             :                              const GPtrDiff_t *bufferStride,
    2377             :                              const GDALExtendedDataType &bufferDataType,
    2378             :                              void *pDstBuffer) const
    2379             : {
    2380             :     ReadFunc readFunc;
    2381           0 :     readFunc.pReadField = GDreadfield;
    2382           0 :     return ReadPixels(arrayStartIdx, count, arrayStep, bufferStride,
    2383           0 :                       bufferDataType, pDstBuffer, m_poShared, m_dt, m_dims,
    2384           0 :                       m_poGDHandle->m_handle, GetName().c_str(), readFunc);
    2385             : }
    2386             : 
    2387             : /************************************************************************/
    2388             : /*                         GetMDArrayNames()                            */
    2389             : /************************************************************************/
    2390             : 
    2391           4 : std::vector<std::string> HDF4SDSGroup::GetMDArrayNames(CSLConstList) const
    2392             : {
    2393           8 :     CPLMutexHolderD(&hHDF4Mutex);
    2394           4 :     std::vector<std::string> ret;
    2395             : 
    2396           4 :     int32 nDatasets = 0;
    2397           4 :     int32 nAttrs = 0;
    2398           4 :     if (SDfileinfo(m_poShared->GetSDHandle(), &nDatasets, &nAttrs) != 0)
    2399           0 :         return ret;
    2400             : 
    2401           8 :     std::set<std::string> oSetNames;
    2402          10 :     for (int32 i = 0; i < nDatasets; i++)
    2403             :     {
    2404           6 :         const int32 iSDS = SDselect(m_poShared->GetSDHandle(), i);
    2405          12 :         std::string osName;
    2406           6 :         osName.resize(VSNAMELENMAX);
    2407           6 :         int32 iRank = 0;
    2408           6 :         int32 iNumType = 0;
    2409          12 :         std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
    2410           6 :         if (SDgetinfo(iSDS, &osName[0], &iRank, &aiDimSizes[0], &iNumType,
    2411           6 :                       &nAttrs) == 0)
    2412             :         {
    2413           6 :             osName.resize(strlen(osName.c_str()));
    2414           6 :             int counter = 2;
    2415           6 :             std::string osRadix(osName);
    2416           6 :             while (oSetNames.find(osName) != oSetNames.end())
    2417             :             {
    2418           0 :                 osName = osRadix + CPLSPrintf("_%d", counter);
    2419           0 :                 counter++;
    2420             :             }
    2421           6 :             ret.push_back(osName);
    2422           6 :             m_oMapNameToSDSIdx[osName] = i;
    2423             :         }
    2424           6 :         SDendaccess(iSDS);
    2425             :     }
    2426             : 
    2427           4 :     if (m_bIsGDALDataset)
    2428             :     {
    2429           2 :         GetDimensions();
    2430           2 :         if (m_varX && m_varY)
    2431             :         {
    2432           2 :             ret.push_back(m_varX->GetName());
    2433           2 :             ret.push_back(m_varY->GetName());
    2434             :         }
    2435             :     }
    2436             : 
    2437           4 :     return ret;
    2438             : }
    2439             : 
    2440             : /************************************************************************/
    2441             : /*                           OpenMDArray()                              */
    2442             : /************************************************************************/
    2443             : 
    2444             : std::shared_ptr<GDALMDArray>
    2445          10 : HDF4SDSGroup::OpenMDArray(const std::string &osName, CSLConstList) const
    2446             : {
    2447          20 :     CPLMutexHolderD(&hHDF4Mutex);
    2448          10 :     if (m_oMapNameToSDSIdx.empty())
    2449             :     {
    2450           0 :         GetMDArrayNames(nullptr);
    2451             :     }
    2452          10 :     auto oIter = m_oMapNameToSDSIdx.find(osName);
    2453          10 :     if (oIter == m_oMapNameToSDSIdx.end())
    2454             :     {
    2455           2 :         if (m_bIsGDALDataset)
    2456             :         {
    2457           2 :             GetDimensions();
    2458           2 :             if (m_varX && m_varX->GetName() == osName)
    2459             :             {
    2460           1 :                 return m_varX;
    2461             :             }
    2462           1 :             if (m_varY && m_varY->GetName() == osName)
    2463             :             {
    2464           1 :                 return m_varY;
    2465             :             }
    2466             :         }
    2467           0 :         return nullptr;
    2468             :     }
    2469           8 :     const int32 iSDS = SDselect(m_poShared->GetSDHandle(), oIter->second);
    2470             : 
    2471           8 :     int32 iRank = 0;
    2472           8 :     int32 iNumType = 0;
    2473           8 :     int32 nAttrs = 0;
    2474          16 :     std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
    2475           8 :     SDgetinfo(iSDS, nullptr, &iRank, &aiDimSizes[0], &iNumType, &nAttrs);
    2476           8 :     aiDimSizes.resize(iRank);
    2477             : 
    2478           8 :     auto ar = HDF4SDSArray::Create(GetFullName(), osName, m_poShared, iSDS,
    2479           0 :                                    aiDimSizes, GetDimensions(), iNumType,
    2480          16 :                                    nAttrs, m_bIsGDALDataset);
    2481           8 :     if (m_bIsGDALDataset)
    2482           2 :         ar->SetGlobalAttributes(m_oGlobalAttributes);
    2483           8 :     return ar;
    2484             : }
    2485             : 
    2486             : /************************************************************************/
    2487             : /*                            GetDimensions()                           */
    2488             : /************************************************************************/
    2489             : 
    2490             : std::vector<std::shared_ptr<GDALDimension>>
    2491          16 : HDF4SDSGroup::GetDimensions(CSLConstList) const
    2492             : {
    2493          32 :     CPLMutexHolderD(&hHDF4Mutex);
    2494          16 :     if (m_bInGetDimensions)
    2495           2 :         return {};
    2496          14 :     if (!m_dims.empty())
    2497          10 :         return m_dims;
    2498           4 :     if (m_oMapNameToSDSIdx.empty())
    2499             :     {
    2500           1 :         m_bInGetDimensions = true;
    2501           1 :         GetMDArrayNames(nullptr);
    2502           1 :         m_bInGetDimensions = false;
    2503             :     }
    2504             : 
    2505           8 :     std::string osProjection;
    2506           8 :     std::string osTransformationMatrix;
    2507           4 :     if (m_bIsGDALDataset)
    2508             :     {
    2509           8 :         for (const auto &poAttr : m_oGlobalAttributes)
    2510             :         {
    2511           8 :             if (poAttr->GetName() == "Projection" &&
    2512           2 :                 poAttr->GetDataType().GetClass() == GEDTC_STRING)
    2513             :             {
    2514           2 :                 const char *pszVal = poAttr->ReadAsString();
    2515           2 :                 if (pszVal)
    2516           2 :                     osProjection = pszVal;
    2517             :             }
    2518           6 :             else if (poAttr->GetName() == "TransformationMatrix" &&
    2519           2 :                      poAttr->GetDataType().GetClass() == GEDTC_STRING)
    2520             :             {
    2521           2 :                 const char *pszVal = poAttr->ReadAsString();
    2522           2 :                 if (pszVal)
    2523           2 :                     osTransformationMatrix = pszVal;
    2524             :             }
    2525             :         }
    2526             :     }
    2527             : 
    2528             :     // First collect all dimension ids referenced by all datasets
    2529           8 :     std::map<int32, int32> oMapDimIdToDimSize;
    2530           8 :     std::set<std::string> oSetArrayNames;
    2531          10 :     for (const auto &oIter : m_oMapNameToSDSIdx)
    2532             :     {
    2533           6 :         const int32 iSDS = SDselect(m_poShared->GetSDHandle(), oIter.second);
    2534           6 :         int32 iRank = 0;
    2535           6 :         int32 iNumType = 0;
    2536           6 :         int32 nAttrs = 0;
    2537          12 :         std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
    2538           6 :         SDgetinfo(iSDS, nullptr, &iRank, &aiDimSizes[0], &iNumType, &nAttrs);
    2539          17 :         for (int i = 0; i < iRank; i++)
    2540             :         {
    2541          11 :             const auto dimId = SDgetdimid(iSDS, i);
    2542          11 :             oMapDimIdToDimSize[dimId] =
    2543          11 :                 std::max(oMapDimIdToDimSize[dimId], aiDimSizes[i]);
    2544             :         }
    2545           6 :         oSetArrayNames.insert(oIter.first);
    2546           6 :         SDendaccess(iSDS);
    2547             :     }
    2548             : 
    2549             :     // Instantiate dimensions
    2550             :     std::set<std::shared_ptr<GDALDimensionWeakIndexingVar>>
    2551           8 :         oSetDimsWithVariable;
    2552          13 :     for (const auto &iter : oMapDimIdToDimSize)
    2553             :     {
    2554          18 :         std::string osName;
    2555           9 :         osName.resize(VSNAMELENMAX);
    2556           9 :         int32 iSize = 0;  // can be 0 for unlimited dimension
    2557           9 :         int32 iNumType = 0;
    2558           9 :         int32 nAttrs = 0;
    2559           9 :         SDdiminfo(iter.first, &osName[0], &iSize, &iNumType, &nAttrs);
    2560           9 :         osName.resize(strlen(osName.c_str()));
    2561             : 
    2562          18 :         std::string osType;
    2563          18 :         std::string osDirection;
    2564           9 :         bool bIsIndexedDim = false;
    2565           9 :         if (iNumType > 0 && oSetArrayNames.find(osName) != oSetArrayNames.end())
    2566             :         {
    2567           2 :             bIsIndexedDim = true;
    2568           2 :             m_bInGetDimensions = true;
    2569           4 :             auto poArray(OpenMDArray(osName, nullptr));
    2570           2 :             m_bInGetDimensions = false;
    2571           2 :             if (poArray)
    2572             :             {
    2573           6 :                 auto poAxis = poArray->GetAttribute("axis");
    2574           2 :                 if (poAxis && poAxis->GetDataType().GetClass() == GEDTC_STRING)
    2575             :                 {
    2576           0 :                     const char *pszVal = poAxis->ReadAsString();
    2577           0 :                     if (pszVal && EQUAL(pszVal, "X"))
    2578           0 :                         osType = GDAL_DIM_TYPE_HORIZONTAL_X;
    2579           0 :                     else if (pszVal && EQUAL(pszVal, "Y"))
    2580           0 :                         osType = GDAL_DIM_TYPE_HORIZONTAL_Y;
    2581             :                 }
    2582             :             }
    2583             :         }
    2584             : 
    2585             :         // Do not trust iSize which can be 0 for a unlimited dimension, but
    2586             :         // the size actually taken by the array(s)
    2587             :         auto poDim(std::make_shared<GDALDimensionWeakIndexingVar>(
    2588           9 :             GetFullName(), osName, osType, osDirection, iter.second));
    2589             :         // cppcheck-suppress knownConditionTrueFalse
    2590           9 :         if (bIsIndexedDim)
    2591             :         {
    2592           2 :             oSetDimsWithVariable.insert(poDim);
    2593             :         }
    2594           9 :         m_dims.push_back(poDim);
    2595             :     }
    2596             : 
    2597           2 :     if (m_bIsGDALDataset && (m_dims.size() == 2 || m_dims.size() == 3) &&
    2598           6 :         !osProjection.empty() && !osTransformationMatrix.empty())
    2599             :     {
    2600             :         CPLStringList aosCoeffs(
    2601           4 :             CSLTokenizeString2(osTransformationMatrix.c_str(), ",", 0));
    2602           4 :         if (aosCoeffs.size() == 6 && CPLAtof(aosCoeffs[2]) == 0 &&
    2603           2 :             CPLAtof(aosCoeffs[4]) == 0)
    2604             :         {
    2605             :             auto newDims = std::vector<std::shared_ptr<GDALDimension>>{
    2606           4 :                 std::make_shared<GDALDimensionWeakIndexingVar>(
    2607           2 :                     GetFullName(), "Y", GDAL_DIM_TYPE_HORIZONTAL_Y,
    2608           2 :                     std::string(), m_dims[0]->GetSize()),
    2609           4 :                 std::make_shared<GDALDimensionWeakIndexingVar>(
    2610           2 :                     GetFullName(), "X", GDAL_DIM_TYPE_HORIZONTAL_X,
    2611          14 :                     std::string(), m_dims[1]->GetSize())};
    2612           2 :             if (m_dims.size() == 3)
    2613             :             {
    2614           1 :                 newDims.push_back(
    2615           2 :                     std::make_shared<GDALDimensionWeakIndexingVar>(
    2616           2 :                         GetFullName(), "Band", std::string(), std::string(),
    2617           2 :                         m_dims[2]->GetSize()));
    2618             :             }
    2619           2 :             m_dims = std::move(newDims);
    2620             : 
    2621           4 :             m_varX = GDALMDArrayRegularlySpaced::Create(
    2622           2 :                 GetFullName(), m_dims[1]->GetName(), m_dims[1],
    2623           4 :                 CPLAtof(aosCoeffs[0]), CPLAtof(aosCoeffs[1]), 0.5);
    2624           2 :             m_dims[1]->SetIndexingVariable(m_varX);
    2625             : 
    2626           4 :             m_varY = GDALMDArrayRegularlySpaced::Create(
    2627           2 :                 GetFullName(), m_dims[0]->GetName(), m_dims[0],
    2628           4 :                 CPLAtof(aosCoeffs[3]), CPLAtof(aosCoeffs[5]), 0.5);
    2629           2 :             m_dims[0]->SetIndexingVariable(m_varY);
    2630             :         }
    2631             :     }
    2632             : 
    2633             :     // Now that we have eatablished all dimensions, we can link them to
    2634             :     // variables
    2635           6 :     for (auto &poDim : oSetDimsWithVariable)
    2636             :     {
    2637           4 :         auto poArray(OpenMDArray(poDim->GetName(), nullptr));
    2638           2 :         if (poArray)
    2639             :         {
    2640           2 :             m_oSetIndexingVariables.push_back(poArray);
    2641           2 :             poDim->SetIndexingVariable(std::move(poArray));
    2642             :         }
    2643             :     }
    2644             : 
    2645           4 :     return m_dims;
    2646             : }
    2647             : 
    2648             : /************************************************************************/
    2649             : /*                           HDF4SDSArray()                             */
    2650             : /************************************************************************/
    2651             : 
    2652           8 : HDF4SDSArray::HDF4SDSArray(
    2653             :     const std::string &osParentName, const std::string &osName,
    2654             :     const std::shared_ptr<HDF4SharedResources> &poShared, int32 iSDS,
    2655             :     const std::vector<int32> &aiDimSizes,
    2656             :     const std::vector<std::shared_ptr<GDALDimension>> &groupDims,
    2657           8 :     int32 iNumType, int32 nAttrs, bool bIsGDALDS)
    2658             :     : GDALAbstractMDArray(osParentName, osName),
    2659             :       GDALPamMDArray(osParentName, osName, poShared->GetPAM()),
    2660             :       m_poShared(poShared), m_iSDS(iSDS),
    2661             :       m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
    2662             :                                   : GDALExtendedDataType::Create(
    2663             :                                         HDF4Dataset::GetDataType(iNumType))),
    2664           8 :       m_nAttributes(nAttrs), m_bIsGDALDataset(bIsGDALDS)
    2665             : {
    2666          21 :     for (int i = 0; i < static_cast<int>(aiDimSizes.size()); i++)
    2667             :     {
    2668          26 :         std::string osDimName;
    2669          13 :         osDimName.resize(VSNAMELENMAX);
    2670          13 :         int32 iSize = 0;
    2671          13 :         int32 iDimNumType = 0;
    2672          13 :         int32 nDimAttrs = 0;
    2673          13 :         int32 dimId = SDgetdimid(iSDS, i);
    2674          13 :         SDdiminfo(dimId, &osDimName[0], &iSize, &iDimNumType, &nDimAttrs);
    2675          13 :         osDimName.resize(strlen(osDimName.c_str()));
    2676          13 :         bool bFound = false;
    2677          20 :         for (const auto &poDim : groupDims)
    2678             :         {
    2679          30 :             if (poDim->GetName() == osDimName ||
    2680          12 :                 (bIsGDALDS && i == 0 && poDim->GetName() == "Y") ||
    2681          35 :                 (bIsGDALDS && i == 1 && poDim->GetName() == "X") ||
    2682           5 :                 (bIsGDALDS && i == 2 && poDim->GetName() == "Band"))
    2683             :             {
    2684          11 :                 bFound = true;
    2685          11 :                 m_dims.push_back(poDim);
    2686          11 :                 break;
    2687             :             }
    2688             :         }
    2689          13 :         if (!bFound)
    2690             :         {
    2691           2 :             m_dims.push_back(std::make_shared<GDALDimension>(
    2692           4 :                 std::string(), CPLSPrintf("dim%d", i), std::string(),
    2693           4 :                 std::string(), aiDimSizes[i]));
    2694             :         }
    2695             :     }
    2696           8 : }
    2697             : 
    2698             : /************************************************************************/
    2699             : /*                          ~HDF4SDSArray()                             */
    2700             : /************************************************************************/
    2701             : 
    2702          16 : HDF4SDSArray::~HDF4SDSArray()
    2703             : {
    2704          16 :     CPLMutexHolderD(&hHDF4Mutex);
    2705           8 :     SDendaccess(m_iSDS);
    2706          16 : }
    2707             : 
    2708             : /************************************************************************/
    2709             : /*                          GetRawNoDataValue()                         */
    2710             : /************************************************************************/
    2711             : 
    2712           1 : const void *HDF4SDSArray::GetRawNoDataValue() const
    2713             : {
    2714           1 :     if (!m_abyNoData.empty())
    2715           0 :         return m_abyNoData.data();
    2716           1 :     m_abyNoData.resize(GetDataType().GetSize());
    2717             : 
    2718           3 :     auto poAttr = GetAttribute("_FillValue");
    2719           1 :     if (poAttr)
    2720             :     {
    2721           0 :         const double dfVal = poAttr->ReadAsDouble();
    2722           0 :         GDALExtendedDataType::CopyValue(
    2723           0 :             &dfVal, GDALExtendedDataType::Create(GDT_Float64), &m_abyNoData[0],
    2724             :             GetDataType());
    2725           0 :         return m_abyNoData.data();
    2726             :     }
    2727             : 
    2728           2 :     CPLMutexHolderD(&hHDF4Mutex);
    2729           1 :     if (SDgetfillvalue(m_iSDS, &m_abyNoData[0]) != -1)
    2730             :     {
    2731           0 :         return m_abyNoData.data();
    2732             :     }
    2733             : 
    2734           1 :     m_abyNoData.clear();
    2735           1 :     return nullptr;
    2736             : }
    2737             : 
    2738             : /************************************************************************/
    2739             : /*                           GetAttributes()                            */
    2740             : /************************************************************************/
    2741             : 
    2742             : std::vector<std::shared_ptr<GDALAttribute>>
    2743           9 : HDF4SDSArray::GetAttributes(CSLConstList) const
    2744             : {
    2745          18 :     CPLMutexHolderD(&hHDF4Mutex);
    2746           9 :     std::vector<std::shared_ptr<GDALAttribute>> ret;
    2747             : 
    2748          13 :     for (int32 iAttribute = 0; iAttribute < m_nAttributes; iAttribute++)
    2749             :     {
    2750           4 :         std::string osAttrName;
    2751           4 :         osAttrName.resize(H4_MAX_NC_NAME);
    2752           4 :         int32 iNumType = 0;
    2753           4 :         int32 nValues = 0;
    2754           4 :         SDattrinfo(m_iSDS, iAttribute, &osAttrName[0], &iNumType, &nValues);
    2755           4 :         osAttrName.resize(strlen(osAttrName.c_str()));
    2756           8 :         ret.emplace_back(std::make_shared<HDF4SDAttribute>(
    2757           8 :             GetFullName(), osAttrName, m_poShared, nullptr, nullptr, m_iSDS,
    2758           4 :             iAttribute, iNumType, nValues));
    2759             :     }
    2760             : 
    2761          18 :     return ret;
    2762             : }
    2763             : 
    2764             : /************************************************************************/
    2765             : /*                              GetOffset()                             */
    2766             : /************************************************************************/
    2767             : 
    2768           1 : double HDF4SDSArray::GetOffset(bool *pbHasOffset,
    2769             :                                GDALDataType *peStorageType) const
    2770             : {
    2771           1 :     return ::GetOffset(this, pbHasOffset, peStorageType);
    2772             : }
    2773             : 
    2774             : /************************************************************************/
    2775             : /*                               GetScale()                             */
    2776             : /************************************************************************/
    2777             : 
    2778           1 : double HDF4SDSArray::GetScale(bool *pbHasScale,
    2779             :                               GDALDataType *peStorageType) const
    2780             : {
    2781           1 :     return ::GetScale(this, pbHasScale, peStorageType);
    2782             : }
    2783             : 
    2784             : /************************************************************************/
    2785             : /*                             GetUnit()                                */
    2786             : /************************************************************************/
    2787             : 
    2788           2 : const std::string &HDF4SDSArray::GetUnit() const
    2789             : {
    2790           4 :     auto poAttr = GetAttribute("units");
    2791           2 :     if (poAttr && poAttr->GetDataType().GetClass() == GEDTC_STRING)
    2792             :     {
    2793           0 :         const char *pszVal = poAttr->ReadAsString();
    2794           0 :         if (pszVal)
    2795           0 :             m_osUnit = pszVal;
    2796             :     }
    2797           4 :     return m_osUnit;
    2798             : }
    2799             : 
    2800             : /************************************************************************/
    2801             : /*                          GetSpatialRef()                             */
    2802             : /************************************************************************/
    2803             : 
    2804           3 : std::shared_ptr<OGRSpatialReference> HDF4SDSArray::GetSpatialRef() const
    2805             : {
    2806           3 :     if (m_bIsGDALDataset)
    2807             :     {
    2808           2 :         std::string osProjection;
    2809           6 :         for (const auto &poAttr : m_oGlobalAttributes)
    2810             :         {
    2811           8 :             if (poAttr->GetName() == "Projection" &&
    2812           2 :                 poAttr->GetDataType().GetClass() == GEDTC_STRING)
    2813             :             {
    2814           2 :                 const char *pszVal = poAttr->ReadAsString();
    2815           2 :                 if (pszVal)
    2816           2 :                     osProjection = pszVal;
    2817           2 :                 break;
    2818             :             }
    2819             :         }
    2820           2 :         if (!osProjection.empty())
    2821             :         {
    2822           4 :             auto poSRS(std::make_shared<OGRSpatialReference>());
    2823           2 :             poSRS->SetFromUserInput(
    2824             :                 osProjection.c_str(),
    2825             :                 OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get());
    2826           2 :             poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    2827           2 :             if (poSRS->GetDataAxisToSRSAxisMapping() == std::vector<int>{2, 1})
    2828           0 :                 poSRS->SetDataAxisToSRSAxisMapping({1, 2});
    2829             :             else
    2830           2 :                 poSRS->SetDataAxisToSRSAxisMapping({2, 1});
    2831           2 :             return poSRS;
    2832             :         }
    2833             :     }
    2834           1 :     return nullptr;
    2835             : }
    2836             : 
    2837             : /************************************************************************/
    2838             : /*                               IRead()                                */
    2839             : /************************************************************************/
    2840             : 
    2841           4 : bool HDF4SDSArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
    2842             :                          const GInt64 *arrayStep,
    2843             :                          const GPtrDiff_t *bufferStride,
    2844             :                          const GDALExtendedDataType &bufferDataType,
    2845             :                          void *pDstBuffer) const
    2846             : {
    2847             :     ReadFunc readFunc;
    2848           4 :     readFunc.pReadData = SDreaddata;
    2849           8 :     return ReadPixels(arrayStartIdx, count, arrayStep, bufferStride,
    2850           4 :                       bufferDataType, pDstBuffer, m_poShared, m_dt, m_dims,
    2851           8 :                       m_iSDS, nullptr, readFunc);
    2852             : }
    2853             : 
    2854             : /************************************************************************/
    2855             : /*                          GetMDArrayNames()                           */
    2856             : /************************************************************************/
    2857             : 
    2858           2 : std::vector<std::string> HDF4GRsGroup::GetMDArrayNames(CSLConstList) const
    2859             : {
    2860           4 :     CPLMutexHolderD(&hHDF4Mutex);
    2861           2 :     std::vector<std::string> res;
    2862             : 
    2863           2 :     int32 nImages = 0;
    2864           2 :     int32 nAttrs = 0;
    2865           2 :     GRfileinfo(m_poGRsHandle->m_grHandle, &nImages, &nAttrs);
    2866           4 :     for (int32 i = 0; i < nImages; i++)
    2867             :     {
    2868           2 :         const int32 iGR = GRselect(m_poGRsHandle->m_grHandle, i);
    2869             : 
    2870           4 :         std::string osName;
    2871           2 :         osName.resize(VSNAMELENMAX);
    2872           2 :         int32 nBands = 0;
    2873           2 :         int32 iNumType = 0;
    2874           2 :         int32 iInterlaceMode = 0;
    2875           4 :         std::vector<int32> aiDimSizes(2);
    2876           2 :         if (GRgetiminfo(iGR, &osName[0], &nBands, &iNumType, &iInterlaceMode,
    2877           4 :                         &aiDimSizes[0], &nAttrs) == 0)
    2878             :         {
    2879           2 :             osName.resize(strlen(osName.c_str()));
    2880           2 :             m_oMapNameToGRIdx[osName] = i;
    2881           2 :             res.push_back(osName);
    2882             :         }
    2883             : 
    2884           2 :         GRendaccess(iGR);
    2885             :     }
    2886           4 :     return res;
    2887             : }
    2888             : 
    2889             : /************************************************************************/
    2890             : /*                           GetAttributes()                            */
    2891             : /************************************************************************/
    2892             : 
    2893             : std::vector<std::shared_ptr<GDALAttribute>>
    2894           2 : HDF4GRsGroup::GetAttributes(CSLConstList) const
    2895             : {
    2896           4 :     CPLMutexHolderD(&hHDF4Mutex);
    2897           2 :     std::vector<std::shared_ptr<GDALAttribute>> ret;
    2898           2 :     int32 nDatasets = 0;
    2899           2 :     int32 nAttributes = 0;
    2900           2 :     if (GRfileinfo(m_poGRsHandle->m_grHandle, &nDatasets, &nAttributes) != 0)
    2901           0 :         return ret;
    2902           6 :     for (int32 iAttribute = 0; iAttribute < nAttributes; iAttribute++)
    2903             :     {
    2904           4 :         int32 iNumType = 0;
    2905           4 :         int32 nValues = 0;
    2906             : 
    2907           4 :         std::string osAttrName;
    2908           4 :         osAttrName.resize(H4_MAX_NC_NAME);
    2909           4 :         GRattrinfo(m_poGRsHandle->m_grHandle, iAttribute, &osAttrName[0],
    2910             :                    &iNumType, &nValues);
    2911           4 :         osAttrName.resize(strlen(osAttrName.c_str()));
    2912             : 
    2913           8 :         ret.emplace_back(std::make_shared<HDF4GRAttribute>(
    2914           4 :             GetFullName(), osAttrName, m_poShared, m_poGRsHandle, nullptr,
    2915           8 :             m_poGRsHandle->m_grHandle, iAttribute, iNumType, nValues));
    2916             :     }
    2917           2 :     return ret;
    2918             : }
    2919             : 
    2920             : /************************************************************************/
    2921             : /*                           OpenMDArray()                              */
    2922             : /************************************************************************/
    2923             : 
    2924             : std::shared_ptr<GDALMDArray>
    2925           3 : HDF4GRsGroup::OpenMDArray(const std::string &osName, CSLConstList) const
    2926             : {
    2927           6 :     CPLMutexHolderD(&hHDF4Mutex);
    2928           3 :     if (m_oMapNameToGRIdx.empty())
    2929             :     {
    2930           1 :         GetMDArrayNames(nullptr);
    2931             :     }
    2932           3 :     auto oIter = m_oMapNameToGRIdx.find(osName);
    2933           3 :     if (oIter == m_oMapNameToGRIdx.end())
    2934             :     {
    2935           1 :         return nullptr;
    2936             :     }
    2937           2 :     const int32 iGR = GRselect(m_poGRsHandle->m_grHandle, oIter->second);
    2938             : 
    2939           2 :     int32 nBands = 0;
    2940           2 :     int32 iNumType = 0;
    2941           2 :     int32 iInterlaceMode = 0;
    2942           2 :     std::vector<int32> aiDimSizes(2);
    2943             :     int32 nAttrs;
    2944           2 :     GRgetiminfo(iGR, nullptr, &nBands, &iNumType, &iInterlaceMode,
    2945           2 :                 &aiDimSizes[0], &nAttrs);
    2946             : 
    2947           4 :     return HDF4GRArray::Create(
    2948           2 :         GetFullName(), osName, m_poShared,
    2949           4 :         std::make_shared<HDF4GRHandle>(m_poGRsHandle, iGR), nBands, aiDimSizes,
    2950           2 :         iNumType, nAttrs);
    2951             : }
    2952             : 
    2953             : /************************************************************************/
    2954             : /*                           HDF4GRArray()                              */
    2955             : /************************************************************************/
    2956             : 
    2957           2 : HDF4GRArray::HDF4GRArray(const std::string &osParentName,
    2958             :                          const std::string &osName,
    2959             :                          const std::shared_ptr<HDF4SharedResources> &poShared,
    2960             :                          const std::shared_ptr<HDF4GRHandle> &poGRHandle,
    2961             :                          int32 nBands, const std::vector<int32> &aiDimSizes,
    2962           2 :                          int32 iNumType, int32 nAttrs)
    2963             :     : GDALAbstractMDArray(osParentName, osName),
    2964             :       GDALPamMDArray(osParentName, osName, poShared->GetPAM()),
    2965             :       m_poShared(poShared), m_poGRHandle(poGRHandle),
    2966             :       m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
    2967             :                                   : GDALExtendedDataType::Create(
    2968             :                                         HDF4Dataset::GetDataType(iNumType))),
    2969           2 :       m_nAttributes(nAttrs)
    2970             : {
    2971           6 :     for (int i = 0; i < static_cast<int>(aiDimSizes.size()); i++)
    2972             :     {
    2973           8 :         m_dims.push_back(std::make_shared<GDALDimension>(
    2974          12 :             std::string(), i == 0 ? "y" : "x", std::string(), std::string(),
    2975           4 :             aiDimSizes[i]));
    2976             :     }
    2977           2 :     m_dims.push_back(std::make_shared<GDALDimension>(
    2978           4 :         std::string(), "bands", std::string(), std::string(), nBands));
    2979           2 : }
    2980             : 
    2981             : /************************************************************************/
    2982             : /*                           GetAttributes()                            */
    2983             : /************************************************************************/
    2984             : 
    2985             : std::vector<std::shared_ptr<GDALAttribute>>
    2986           4 : HDF4GRArray::GetAttributes(CSLConstList) const
    2987             : {
    2988           8 :     CPLMutexHolderD(&hHDF4Mutex);
    2989           4 :     std::vector<std::shared_ptr<GDALAttribute>> ret;
    2990          10 :     for (int32 iAttribute = 0; iAttribute < m_nAttributes; iAttribute++)
    2991             :     {
    2992           6 :         int32 iNumType = 0;
    2993           6 :         int32 nValues = 0;
    2994             : 
    2995           6 :         std::string osAttrName;
    2996           6 :         osAttrName.resize(H4_MAX_NC_NAME);
    2997           6 :         GRattrinfo(m_poGRHandle->m_iGR, iAttribute, &osAttrName[0], &iNumType,
    2998             :                    &nValues);
    2999           6 :         osAttrName.resize(strlen(osAttrName.c_str()));
    3000             : 
    3001          12 :         ret.emplace_back(std::make_shared<HDF4GRAttribute>(
    3002           6 :             GetFullName(), osAttrName, m_poShared, nullptr, m_poGRHandle,
    3003          12 :             m_poGRHandle->m_iGR, iAttribute, iNumType, nValues));
    3004             :     }
    3005             : 
    3006           4 :     auto iPal = GRgetlutid(m_poGRHandle->m_iGR, 0);
    3007           4 :     if (iPal != -1)
    3008             :     {
    3009           4 :         int32 nComps = 0;
    3010           4 :         int32 iPalDataType = 0;
    3011           4 :         int32 iPalInterlaceMode = 0;
    3012           4 :         int32 nPalEntries = 0;
    3013           4 :         GRgetlutinfo(iPal, &nComps, &iPalDataType, &iPalInterlaceMode,
    3014             :                      &nPalEntries);
    3015           1 :         if (nPalEntries && nComps == 3 &&
    3016           1 :             GDALGetDataTypeSizeBytes(HDF4Dataset::GetDataType(iPalDataType)) ==
    3017           5 :                 1 &&
    3018           1 :             nPalEntries <= 256)
    3019             :         {
    3020           2 :             ret.emplace_back(std::make_shared<HDF4GRPalette>(
    3021           1 :                 GetFullName(), "lut", m_poShared, m_poGRHandle, iPal,
    3022           1 :                 nPalEntries));
    3023             :         }
    3024             :     }
    3025             : 
    3026           8 :     return ret;
    3027             : }
    3028             : 
    3029             : /************************************************************************/
    3030             : /*                               IRead()                                */
    3031             : /************************************************************************/
    3032             : 
    3033           4 : bool HDF4GRArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
    3034             :                         const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    3035             :                         const GDALExtendedDataType &bufferDataType,
    3036             :                         void *pDstBuffer) const
    3037             : {
    3038           8 :     CPLMutexHolderD(&hHDF4Mutex);
    3039             :     /* -------------------------------------------------------------------- */
    3040             :     /*      HDF files with external data files, such as some landsat        */
    3041             :     /*      products (eg. data/hdf/L1G) need to be told what directory      */
    3042             :     /*      to look in to find the external files.  Normally this is the    */
    3043             :     /*      directory holding the hdf file.                                 */
    3044             :     /* -------------------------------------------------------------------- */
    3045           4 :     HXsetdir(CPLGetPath(m_poShared->GetFilename().c_str()));
    3046             : 
    3047           4 :     const size_t nDims(m_dims.size());
    3048           8 :     std::vector<int32> sw_start(nDims);
    3049           8 :     std::vector<int32> sw_stride(nDims);
    3050           8 :     std::vector<int32> sw_edge(nDims);
    3051           8 :     std::vector<GPtrDiff_t> newBufferStride(nDims);
    3052           4 :     GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
    3053           4 :     const size_t nBufferDataTypeSize = bufferDataType.GetSize();
    3054          16 :     for (size_t i = 0; i < nDims; i++)
    3055             :     {
    3056          12 :         sw_start[i] = static_cast<int>(arrayStartIdx[i]);
    3057          12 :         sw_stride[i] = static_cast<int>(arrayStep[i]);
    3058          12 :         sw_edge[i] = static_cast<int>(count[i]);
    3059          12 :         newBufferStride[i] = bufferStride[i];
    3060          12 :         if (sw_stride[i] < 0)
    3061             :         {
    3062             :             // GRreadimage() doesn't like negative step / array stride, so
    3063             :             // transform the request to a classic "left-to-right" one
    3064           1 :             sw_start[i] += sw_stride[i] * (sw_edge[i] - 1);
    3065           1 :             sw_stride[i] = -sw_stride[i];
    3066           1 :             pabyDstBuffer +=
    3067           1 :                 (sw_edge[i] - 1) * newBufferStride[i] * nBufferDataTypeSize;
    3068           1 :             newBufferStride[i] = -newBufferStride[i];
    3069             :         }
    3070             :     }
    3071           4 :     size_t nExpectedStride = 1;
    3072           4 :     bool bContiguousStride = true;
    3073          13 :     for (size_t i = nDims; i > 0;)
    3074             :     {
    3075          10 :         --i;
    3076          10 :         if (newBufferStride[i] != static_cast<GPtrDiff_t>(nExpectedStride))
    3077             :         {
    3078           1 :             bContiguousStride = false;
    3079           1 :             break;
    3080             :         }
    3081           9 :         nExpectedStride *= count[i];
    3082             :     }
    3083          10 :     if (bufferDataType == m_dt && bContiguousStride && arrayStartIdx[2] == 0 &&
    3084          10 :         count[2] == m_dims[2]->GetSize() && arrayStep[2] == 1)
    3085             :     {
    3086           1 :         auto status = GRreadimage(m_poGRHandle->m_iGR, &sw_start[0],
    3087           1 :                                   &sw_stride[0], &sw_edge[0], pabyDstBuffer);
    3088           1 :         return status >= 0;
    3089             :     }
    3090           3 :     auto pabyTemp = static_cast<GByte *>(VSI_MALLOC2_VERBOSE(
    3091             :         m_dt.GetSize(),
    3092             :         count[0] * count[1] * static_cast<size_t>(m_dims[2]->GetSize())));
    3093           3 :     if (pabyTemp == nullptr)
    3094           0 :         return false;
    3095           3 :     auto status = GRreadimage(m_poGRHandle->m_iGR, &sw_start[0], &sw_stride[0],
    3096           3 :                               &sw_edge[0], pabyTemp);
    3097           3 :     if (status < 0)
    3098             :     {
    3099           0 :         VSIFree(pabyTemp);
    3100           0 :         return false;
    3101             :     }
    3102             : 
    3103           3 :     const size_t nSrcDataTypeSize = m_dt.GetSize();
    3104           6 :     std::vector<size_t> anStackCount(nDims);
    3105           3 :     GByte *pabySrc = pabyTemp + nSrcDataTypeSize * sw_start[2];
    3106           3 :     std::vector<GByte *> pabyDstBufferStack(nDims + 1);
    3107           3 :     pabyDstBufferStack[0] = pabyDstBuffer;
    3108           3 :     size_t iDim = 0;
    3109          54 : lbl_next_depth:
    3110          54 :     if (iDim == nDims)
    3111             :     {
    3112          24 :         GDALExtendedDataType::CopyValue(
    3113          24 :             pabySrc, m_dt, pabyDstBufferStack[nDims], bufferDataType);
    3114          24 :         pabySrc += nSrcDataTypeSize * sw_stride[2];
    3115             :     }
    3116             :     else
    3117             :     {
    3118          30 :         anStackCount[iDim] = count[iDim];
    3119             :         while (true)
    3120             :         {
    3121          51 :             ++iDim;
    3122          51 :             pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
    3123          51 :             goto lbl_next_depth;
    3124          51 :         lbl_return_to_caller_in_loop:
    3125          51 :             --iDim;
    3126          51 :             --anStackCount[iDim];
    3127          51 :             if (anStackCount[iDim] == 0)
    3128          30 :                 break;
    3129          21 :             IncrPointer(pabyDstBufferStack[iDim], newBufferStride[iDim],
    3130             :                         nBufferDataTypeSize);
    3131             :         }
    3132          30 :         if (iDim == 2)
    3133          18 :             pabySrc +=
    3134          18 :                 nSrcDataTypeSize * static_cast<size_t>(m_dims[2]->GetSize() -
    3135          18 :                                                        count[2] * sw_stride[2]);
    3136             :     }
    3137          54 :     if (iDim > 0)
    3138          51 :         goto lbl_return_to_caller_in_loop;
    3139             : 
    3140           3 :     VSIFree(pabyTemp);
    3141           3 :     return true;
    3142             : }
    3143             : 
    3144             : /************************************************************************/
    3145             : /*                           HDF4GRPalette()                            */
    3146             : /************************************************************************/
    3147             : 
    3148           1 : HDF4GRPalette::HDF4GRPalette(
    3149             :     const std::string &osParentName, const std::string &osName,
    3150             :     const std::shared_ptr<HDF4SharedResources> &poShared,
    3151           1 :     const std::shared_ptr<HDF4GRHandle> &poGRHandle, int32 iPal, int32 nValues)
    3152             :     : GDALAbstractMDArray(osParentName, osName),
    3153             :       GDALAttribute(osParentName, osName), m_poShared(poShared),
    3154           1 :       m_poGRHandle(poGRHandle), m_iPal(iPal), m_nValues(nValues)
    3155             : {
    3156           1 :     m_dims.push_back(std::make_shared<GDALDimension>(
    3157           2 :         std::string(), "index", std::string(), std::string(), nValues));
    3158           1 :     m_dims.push_back(std::make_shared<GDALDimension>(
    3159           2 :         std::string(), "component", std::string(), std::string(), 3));
    3160           1 : }
    3161             : 
    3162             : /************************************************************************/
    3163             : /*                               IRead()                                */
    3164             : /************************************************************************/
    3165             : 
    3166           1 : bool HDF4GRPalette::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
    3167             :                           const GInt64 *arrayStep,
    3168             :                           const GPtrDiff_t *bufferStride,
    3169             :                           const GDALExtendedDataType &bufferDataType,
    3170             :                           void *pDstBuffer) const
    3171             : {
    3172           2 :     CPLMutexHolderD(&hHDF4Mutex);
    3173             : 
    3174           2 :     std::vector<GByte> abyValues(3 * m_nValues);
    3175           1 :     GRreadlut(m_iPal, &abyValues[0]);
    3176             : 
    3177           1 :     GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
    3178           1 :     const size_t nBufferDataTypeSize = bufferDataType.GetSize();
    3179           1 :     const auto srcDt(GDALExtendedDataType::Create(GDT_Byte));
    3180         257 :     for (size_t i = 0; i < count[0]; ++i)
    3181             :     {
    3182         256 :         size_t idx = static_cast<size_t>(arrayStartIdx[0] + i * arrayStep[0]);
    3183        1024 :         for (size_t j = 0; j < count[1]; ++j)
    3184             :         {
    3185         768 :             size_t comp =
    3186         768 :                 static_cast<size_t>(arrayStartIdx[1] + j * arrayStep[1]);
    3187         768 :             GByte *pDst =
    3188         768 :                 pabyDstBuffer + (i * bufferStride[0] + j * bufferStride[1]) *
    3189             :                                     nBufferDataTypeSize;
    3190         768 :             GDALExtendedDataType::CopyValue(&abyValues[3 * idx + comp], srcDt,
    3191             :                                             pDst, bufferDataType);
    3192             :         }
    3193             :     }
    3194             : 
    3195           2 :     return true;
    3196             : }
    3197             : 
    3198             : /************************************************************************/
    3199             : /*                           OpenMultiDim()                             */
    3200             : /************************************************************************/
    3201             : 
    3202           6 : void HDF4Dataset::OpenMultiDim(const char *pszFilename,
    3203             :                                CSLConstList papszOpenOptionsIn)
    3204             : {
    3205             :     // under hHDF4Mutex
    3206             : 
    3207          12 :     auto poShared = std::make_shared<HDF4SharedResources>(pszFilename);
    3208           6 :     poShared->m_hSD = hSD;
    3209           6 :     poShared->m_aosOpenOptions = papszOpenOptionsIn;
    3210             : 
    3211           6 :     hSD = -1;
    3212             : 
    3213           6 :     m_poRootGroup = HDF4Group::Create(std::string(), "/", poShared);
    3214             : 
    3215           6 :     SetDescription(pszFilename);
    3216             : 
    3217             :     // Setup/check for pam .aux.xml.
    3218           6 :     TryLoadXML();
    3219           6 : }

Generated by: LCOV version 1.14