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

Generated by: LCOV version 1.14