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

Generated by: LCOV version 1.14