LCOV - code coverage report
Current view: top level - frmts/hdf5 - hdf5eosparser.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 388 413 93.9 %
Date: 2025-12-29 15:50:47 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Hierarchical Data Format Release 5 (HDF5)
       4             :  * Purpose:  Implementation of HDF5 HDFEOS parser
       5             :  * Author:   Even Rouault
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2023, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_error.h"
      14             : #include "nasakeywordhandler.h"
      15             : 
      16             : #include "hdf5eosparser.h"
      17             : 
      18             : #include <cstring>
      19             : #include <utility>
      20             : 
      21             : /************************************************************************/
      22             : /*                             HasHDFEOS()                              */
      23             : /************************************************************************/
      24             : 
      25         479 : bool HDF5EOSParser::HasHDFEOS(hid_t hRoot)
      26             : {
      27         479 :     hsize_t numObjs = 0;
      28         479 :     H5Gget_num_objs(hRoot, &numObjs);
      29         479 :     bool bFound = false;
      30        1504 :     for (hsize_t i = 0; i < numObjs; ++i)
      31             :     {
      32             :         char szName[128];
      33             :         ssize_t nLen =
      34        1056 :             H5Gget_objname_by_idx(hRoot, i, szName, sizeof(szName) - 1);
      35        1056 :         if (nLen > 0)
      36             :         {
      37        1056 :             szName[nLen] = 0;
      38        1056 :             if (strcmp(szName, "HDFEOS INFORMATION") == 0)
      39             :             {
      40          31 :                 bFound = true;
      41          31 :                 break;
      42             :             }
      43             :         }
      44             :     }
      45         479 :     if (!bFound)
      46         448 :         return false;
      47             : 
      48             :     H5G_stat_t oStatbuf;
      49          31 :     if (H5Gget_objinfo(hRoot, "HDFEOS INFORMATION", false, &oStatbuf) < 0)
      50           0 :         return false;
      51             : 
      52          31 :     auto hHDFEOSInformation = H5Gopen(hRoot, "HDFEOS INFORMATION");
      53          31 :     if (hHDFEOSInformation < 0)
      54             :     {
      55           0 :         return false;
      56             :     }
      57          31 :     H5Gclose(hHDFEOSInformation);
      58          31 :     return true;
      59             : }
      60             : 
      61             : /************************************************************************/
      62             : /*                               Parse()                                */
      63             : /************************************************************************/
      64             : 
      65          31 : bool HDF5EOSParser::Parse(hid_t hRoot)
      66             : {
      67          31 :     auto hHDFEOSInformation = H5Gopen(hRoot, "HDFEOS INFORMATION");
      68          31 :     if (hHDFEOSInformation < 0)
      69             :     {
      70           0 :         return false;
      71             :     }
      72             : 
      73          31 :     const hid_t hArrayId = H5Dopen(hHDFEOSInformation, "StructMetadata.0");
      74          31 :     if (hArrayId < 0)
      75             :     {
      76           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find StructMetadata.0");
      77           0 :         H5Gclose(hHDFEOSInformation);
      78           0 :         return false;
      79             :     }
      80             : 
      81          31 :     const hid_t hAttrSpace = H5Dget_space(hArrayId);
      82          31 :     const hid_t hAttrTypeID = H5Dget_type(hArrayId);
      83             :     const hid_t hAttrNativeType =
      84          31 :         H5Tget_native_type(hAttrTypeID, H5T_DIR_DEFAULT);
      85             : 
      86             :     // Fetch StructMetadata.0 content in a std::string
      87          62 :     std::string osResult;
      88          31 :     if (H5Tget_class(hAttrNativeType) == H5T_STRING &&
      89          62 :         !H5Tis_variable_str(hAttrNativeType) &&
      90          31 :         H5Sget_simple_extent_ndims(hAttrSpace) == 0)
      91             :     {
      92          31 :         const auto nSize = H5Tget_size(hAttrNativeType);
      93          31 :         if (nSize > 10 * 1024 * 1024)
      94             :         {
      95           0 :             CPLError(CE_Failure, CPLE_AppDefined,
      96             :                      "Too large HDFEOS INFORMATION.StructMetadata.0");
      97             :         }
      98             :         else
      99             :         {
     100          31 :             osResult.resize(nSize);
     101          31 :             H5Dread(hArrayId, hAttrNativeType, H5S_ALL, hAttrSpace, H5P_DEFAULT,
     102          31 :                     &osResult[0]);
     103             :         }
     104             :     }
     105             :     else
     106             :     {
     107           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     108             :                  "HDFEOS INFORMATION.StructMetadata.0 not of type string");
     109             :     }
     110          31 :     H5Sclose(hAttrSpace);
     111          31 :     H5Tclose(hAttrNativeType);
     112          31 :     H5Tclose(hAttrTypeID);
     113             : 
     114          31 :     H5Dclose(hArrayId);
     115          31 :     H5Gclose(hHDFEOSInformation);
     116             : 
     117          31 :     if (osResult.empty())
     118           0 :         return false;
     119             : 
     120             :     // Parse StructMetadata.0 with NASAKeywordHandler
     121          62 :     NASAKeywordHandler oKWHandler;
     122             : #ifdef DEBUG
     123          31 :     CPLDebug("HDF5EOS", "%s", osResult.c_str());
     124             : #endif
     125          31 :     if (!oKWHandler.Parse(osResult.c_str()))
     126             :     {
     127           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     128             :                  "Cannot parse HDFEOS INFORMATION.StructMetadata.0 with "
     129             :                  "NASAKeywordHandler");
     130           0 :         return false;
     131             :     }
     132             : 
     133          62 :     auto oJsonRoot = oKWHandler.GetJsonObject();
     134          93 :     auto oGridStructure = oJsonRoot.GetObj("GridStructure");
     135          62 :     auto oSwathStructure = oJsonRoot.GetObj("SwathStructure");
     136          31 :     bool bOK = false;
     137             :     // An empty
     138             :     // GROUP=GridStructure
     139             :     // END_GROUP=GridStructure
     140             :     // will generate 2 keys (_type and END_GROUP)
     141          31 :     if (oGridStructure.IsValid() && oGridStructure.GetChildren().size() > 2)
     142             :     {
     143          15 :         bOK = true;
     144          15 :         m_eDataModel = DataModel::GRID;
     145          15 :         ParseGridStructure(oGridStructure);
     146             :     }
     147          32 :     else if (oSwathStructure.IsValid() &&
     148          32 :              oSwathStructure.GetChildren().size() > 2)
     149             :     {
     150          16 :         bOK = true;
     151          16 :         m_eDataModel = DataModel::SWATH;
     152          16 :         ParseSwathStructure(oSwathStructure);
     153             :     }
     154             : 
     155          31 :     return bOK;
     156             : }
     157             : 
     158             : /************************************************************************/
     159             : /*                     GetGTCPProjectionCode()                          */
     160             : /************************************************************************/
     161             : 
     162          15 : static int GetGTCPProjectionCode(const std::string &osProjection)
     163             : {
     164          15 :     const char *const apszGCTPProjections[] = {
     165             :         "HE5_GCTP_GEO",    "HE5_GCTP_UTM",    "HE5_GCTP_SPCS",
     166             :         "HE5_GCTP_ALBERS", "HE5_GCTP_LAMCC",  "HE5_GCTP_MERCAT",
     167             :         "HE5_GCTP_PS",     "HE5_GCTP_POLYC",  "HE5_GCTP_EQUIDC",
     168             :         "HE5_GCTP_TM",     "HE5_GCTP_STEREO", "HE5_GCTP_LAMAZ",
     169             :         "HE5_GCTP_AZMEQD", "HE5_GCTP_GNOMON", "HE5_GCTP_ORTHO",
     170             :         "HE5_GCTP_GVNSP",  "HE5_GCTP_SNSOID", "HE5_GCTP_EQRECT",
     171             :         "HE5_GCTP_MILLER", "HE5_GCTP_VGRINT", "HE5_GCTP_HOM",
     172             :         "HE5_GCTP_ROBIN",  "HE5_GCTP_SOM",    "HE5_GCTP_ALASKA",
     173             :         "HE5_GCTP_GOOD",   "HE5_GCTP_MOLL",   "HE5_GCTP_IMOLL",
     174             :         "HE5_GCTP_HAMMER", "HE5_GCTP_WAGIV",  "HE5_GCTP_WAGVII",
     175             :         "HE5_GCTP_OBLEQA"};
     176             :     // HE5_GCTP_CEA, HE5_GCTP_BCEA, HE5_GCTP_ISINUS not taken
     177             :     // into account.
     178         132 :     for (int i = 0; i < static_cast<int>(CPL_ARRAYSIZE(apszGCTPProjections));
     179             :          ++i)
     180             :     {
     181         132 :         if (osProjection == apszGCTPProjections[i])
     182             :         {
     183          15 :             return i;
     184             :         }
     185             :     }
     186           0 :     return -1;
     187             : }
     188             : 
     189             : /************************************************************************/
     190             : /*                        ParseGridStructure()                          */
     191             : /************************************************************************/
     192             : 
     193          15 : void HDF5EOSParser::ParseGridStructure(const CPLJSONObject &oGridStructure)
     194             : {
     195          60 :     for (const auto &oGrid : oGridStructure.GetChildren())
     196             :     {
     197          45 :         if (oGrid.GetType() == CPLJSONObject::Type::Object)
     198             :         {
     199          45 :             const auto osGridName = oGrid.GetString("GridName");
     200          45 :             const auto oDataFields = oGrid.GetObj("DataField");
     201          45 :             const auto oDimensions = oGrid.GetObj("Dimension");
     202          30 :             std::map<std::string, int> oMapDimensionNameToSize;
     203          30 :             auto poGridMetadata = std::make_unique<GridMetadata>();
     204          15 :             poGridMetadata->osGridName = osGridName;
     205          72 :             for (const auto &oDimension : oDimensions.GetChildren())
     206             :             {
     207          57 :                 if (oDimension.GetType() == CPLJSONObject::Type::Object)
     208             :                 {
     209             :                     std::string osDimensionName =
     210          81 :                         oDimension.GetString("DimensionName");
     211          27 :                     int nSize = oDimension.GetInteger("Size");
     212          27 :                     oMapDimensionNameToSize[osDimensionName] = nSize;
     213          54 :                     Dimension oDim;
     214          27 :                     oDim.osName = std::move(osDimensionName);
     215          27 :                     oDim.nSize = nSize;
     216          27 :                     poGridMetadata->aoDimensions.push_back(std::move(oDim));
     217             :                 }
     218             :             }
     219             : 
     220             :             // Happens for example for products following
     221             :             // AMSR-E/AMSR2 Unified L3 Daily 12.5 km Brightness Temperatures,
     222             :             // Sea Ice Concentration, Motion & Snow Depth Polar Grids
     223             :             // (https://nsidc.org/sites/default/files/au_si12-v001-userguide_1.pdf)
     224             :             // such as
     225             :             // https://n5eil01u.ecs.nsidc.org/AMSA/AU_SI12.001/2012.07.02/AMSR_U2_L3_SeaIce12km_B04_20120702.he5
     226          15 :             const int nXDim = oGrid.GetInteger("XDim", 0);
     227          15 :             const int nYDim = oGrid.GetInteger("YDim", 0);
     228          15 :             if (nXDim > 0 && nYDim > 0 &&
     229          35 :                 !cpl::contains(oMapDimensionNameToSize, "XDim") &&
     230           5 :                 !cpl::contains(oMapDimensionNameToSize, "YDim"))
     231             :             {
     232             :                 // Check that we have at least one data field with DimList=(YDim,XDim)
     233             :                 // property.
     234           5 :                 bool bHasDimListYDimXDim = false;
     235          15 :                 for (const auto &oDataField : oDataFields.GetChildren())
     236             :                 {
     237          10 :                     if (oDataField.GetType() == CPLJSONObject::Type::Object)
     238             :                     {
     239          10 :                         const auto oDimList = oDataField.GetArray("DimList");
     240           5 :                         if (oDimList.Size() == 2 &&
     241          15 :                             oDimList[0].ToString() == "YDim" &&
     242          10 :                             oDimList[1].ToString() == "XDim")
     243             :                         {
     244           5 :                             bHasDimListYDimXDim = true;
     245           5 :                             break;
     246             :                         }
     247             :                     }
     248             :                 }
     249           5 :                 if (bHasDimListYDimXDim)
     250             :                 {
     251             :                     {
     252          10 :                         std::string osDimensionName("YDim");
     253           5 :                         oMapDimensionNameToSize[osDimensionName] = nYDim;
     254          10 :                         Dimension oDim;
     255           5 :                         oDim.osName = std::move(osDimensionName);
     256           5 :                         oDim.nSize = nYDim;
     257           5 :                         poGridMetadata->aoDimensions.push_back(std::move(oDim));
     258             :                     }
     259             :                     {
     260          10 :                         std::string osDimensionName("XDim");
     261           5 :                         oMapDimensionNameToSize[osDimensionName] = nXDim;
     262          10 :                         Dimension oDim;
     263           5 :                         oDim.osName = std::move(osDimensionName);
     264           5 :                         oDim.nSize = nXDim;
     265           5 :                         poGridMetadata->aoDimensions.push_back(std::move(oDim));
     266             :                     }
     267             :                 }
     268             :             }
     269             : 
     270          15 :             poGridMetadata->osProjection = oGrid.GetString("Projection");
     271          30 :             poGridMetadata->nProjCode =
     272          15 :                 GetGTCPProjectionCode(poGridMetadata->osProjection);
     273          15 :             poGridMetadata->osGridOrigin = oGrid.GetString("GridOrigin");
     274          15 :             poGridMetadata->nZone = oGrid.GetInteger("ZoneCode", -1);
     275          15 :             poGridMetadata->nSphereCode = oGrid.GetInteger("SphereCode", -1);
     276             : 
     277          45 :             const auto oProjParams = oGrid.GetArray("ProjParams");
     278         106 :             for (int j = 0; j < oProjParams.Size(); ++j)
     279          91 :                 poGridMetadata->adfProjParams.push_back(
     280          91 :                     oProjParams[j].ToDouble());
     281             : 
     282             :             const auto oUpperLeftPointMtrs =
     283          45 :                 oGrid.GetArray("UpperLeftPointMtrs");
     284          45 :             for (int j = 0; j < oUpperLeftPointMtrs.Size(); ++j)
     285          30 :                 poGridMetadata->adfUpperLeftPointMeters.push_back(
     286          30 :                     oUpperLeftPointMtrs[j].ToDouble());
     287             : 
     288          45 :             const auto oLowerRightMtrs = oGrid.GetArray("LowerRightMtrs");
     289          45 :             for (int j = 0; j < oLowerRightMtrs.Size(); ++j)
     290          30 :                 poGridMetadata->adfLowerRightPointMeters.push_back(
     291          30 :                     oLowerRightMtrs[j].ToDouble());
     292             : 
     293          15 :             m_oMapGridNameToGridMetadata[osGridName] =
     294          30 :                 std::move(poGridMetadata);
     295             :             const auto poGridMetadataRef =
     296          15 :                 m_oMapGridNameToGridMetadata[osGridName].get();
     297             : 
     298          60 :             for (const auto &oDataField : oDataFields.GetChildren())
     299             :             {
     300          45 :                 if (oDataField.GetType() == CPLJSONObject::Type::Object)
     301             :                 {
     302             :                     const auto osDataFieldName =
     303          45 :                         oDataField.GetString("DataFieldName");
     304          45 :                     const auto oDimList = oDataField.GetArray("DimList");
     305          30 :                     GridDataFieldMetadata oDataFieldMetadata;
     306          15 :                     bool bValid = oDimList.Size() > 0;
     307          49 :                     for (int j = 0; j < oDimList.Size(); ++j)
     308             :                     {
     309          68 :                         std::string osDimensionName = oDimList[j].ToString();
     310             :                         const auto oIter = oMapDimensionNameToSize.find(
     311          34 :                             osDimensionName.c_str());
     312          34 :                         if (oIter == oMapDimensionNameToSize.end())
     313             :                         {
     314           0 :                             bValid = false;
     315           0 :                             break;
     316             :                         }
     317          68 :                         Dimension oDim;
     318          34 :                         oDim.osName = std::move(osDimensionName);
     319          34 :                         oDim.nSize = oIter->second;
     320          34 :                         oDataFieldMetadata.aoDimensions.push_back(
     321          34 :                             std::move(oDim));
     322             :                     }
     323          15 :                     if (bValid)
     324             :                     {
     325          15 :                         oDataFieldMetadata.poGridMetadata = poGridMetadataRef;
     326             :                         m_oMapSubdatasetNameToGridDataFieldMetadata
     327          30 :                             ["//HDFEOS/GRIDS/" + osGridName + "/Data_Fields/" +
     328          30 :                              osDataFieldName] = std::move(oDataFieldMetadata);
     329             :                     }
     330             :                 }
     331             :             }
     332             :         }
     333             :     }
     334          15 : }
     335             : 
     336             : /************************************************************************/
     337             : /*                        GetGridMetadata()                             */
     338             : /************************************************************************/
     339             : 
     340           9 : bool HDF5EOSParser::GetGridMetadata(const std::string &osGridName,
     341             :                                     GridMetadata &gridMetadataOut) const
     342             : {
     343           9 :     const auto oIter = m_oMapGridNameToGridMetadata.find(osGridName);
     344           9 :     if (oIter == m_oMapGridNameToGridMetadata.end())
     345           6 :         return false;
     346           3 :     gridMetadataOut = *(oIter->second);
     347           3 :     return true;
     348             : }
     349             : 
     350             : /************************************************************************/
     351             : /*                     GetGridDataFieldMetadata()                       */
     352             : /************************************************************************/
     353             : 
     354          12 : bool HDF5EOSParser::GetGridDataFieldMetadata(
     355             :     const char *pszSubdatasetName,
     356             :     GridDataFieldMetadata &gridDataFieldMetadataOut) const
     357             : {
     358             :     const auto oIter =
     359          12 :         m_oMapSubdatasetNameToGridDataFieldMetadata.find(pszSubdatasetName);
     360          12 :     if (oIter == m_oMapSubdatasetNameToGridDataFieldMetadata.end())
     361           3 :         return false;
     362           9 :     gridDataFieldMetadataOut = oIter->second;
     363           9 :     return true;
     364             : }
     365             : 
     366             : /************************************************************************/
     367             : /*                        ParseSwathStructure()                         */
     368             : /************************************************************************/
     369             : 
     370          16 : void HDF5EOSParser::ParseSwathStructure(const CPLJSONObject &oSwathStructure)
     371             : {
     372          64 :     for (const auto &oSwath : oSwathStructure.GetChildren())
     373             :     {
     374          48 :         if (oSwath.GetType() == CPLJSONObject::Type::Object)
     375             :         {
     376          48 :             const auto osSwathName = oSwath.GetString("SwathName");
     377             : 
     378          48 :             const auto oDimensions = oSwath.GetObj("Dimension");
     379          32 :             std::map<std::string, int> oMapDimensionNameToSize;
     380          32 :             auto poSwathMetadata = std::make_unique<SwathMetadata>();
     381          16 :             poSwathMetadata->osSwathName = osSwathName;
     382         132 :             for (const auto &oDimension : oDimensions.GetChildren())
     383             :             {
     384         116 :                 if (oDimension.GetType() == CPLJSONObject::Type::Object)
     385             :                 {
     386             :                     auto osDimensionName =
     387         252 :                         oDimension.GetString("DimensionName");
     388          84 :                     int nSize = oDimension.GetInteger("Size");
     389          84 :                     oMapDimensionNameToSize[osDimensionName] = nSize;
     390         168 :                     Dimension oDim;
     391          84 :                     oDim.osName = std::move(osDimensionName);
     392          84 :                     oDim.nSize = nSize;
     393          84 :                     poSwathMetadata->aoDimensions.emplace_back(std::move(oDim));
     394             :                 }
     395             :             }
     396             : 
     397          16 :             m_oMapSwathNameToSwathMetadata[osSwathName] =
     398          32 :                 std::move(poSwathMetadata);
     399             :             const auto poSwathMetadataRef =
     400          16 :                 m_oMapSwathNameToSwathMetadata[osSwathName].get();
     401             : 
     402             :             struct DimensionMap
     403             :             {
     404             :                 std::string osGeoDimName{};
     405             :                 std::string osDataDimName{};
     406             :                 int nOffset = 0;
     407             :                 int nIncrement = 1;
     408             :             };
     409             : 
     410          32 :             std::vector<DimensionMap> aoDimensionMaps;
     411          32 :             std::map<std::string, std::string> oMapDataDimensionToGeoDimension;
     412             : 
     413          48 :             const auto jsonDimensionMaps = oSwath.GetObj("DimensionMap");
     414          60 :             for (const auto &jsonDimensionMap : jsonDimensionMaps.GetChildren())
     415             :             {
     416          44 :                 if (jsonDimensionMap.GetType() == CPLJSONObject::Type::Object)
     417             :                 {
     418          24 :                     DimensionMap oDimensionMap;
     419             :                     oDimensionMap.osGeoDimName =
     420          12 :                         jsonDimensionMap.GetString("GeoDimension");
     421             :                     oDimensionMap.osDataDimName =
     422          12 :                         jsonDimensionMap.GetString("DataDimension");
     423          12 :                     oDimensionMap.nOffset =
     424          12 :                         jsonDimensionMap.GetInteger("Offset", 0);
     425          12 :                     oDimensionMap.nIncrement =
     426          12 :                         jsonDimensionMap.GetInteger("Increment", 1);
     427             :                     oMapDataDimensionToGeoDimension[oDimensionMap
     428          12 :                                                         .osDataDimName] =
     429          12 :                         oDimensionMap.osGeoDimName;
     430          12 :                     aoDimensionMaps.emplace_back(oDimensionMap);
     431             :                 }
     432             :             }
     433             : 
     434          48 :             const auto oGeoFields = oSwath.GetObj("GeoField");
     435          32 :             std::vector<Dimension> aoLongitudeDimensions;
     436          32 :             std::vector<Dimension> aoLatitudeDimensions;
     437             : 
     438             :             // First pass to create dimensions
     439          96 :             for (const auto &oGeoField : oGeoFields.GetChildren())
     440             :             {
     441          80 :                 if (oGeoField.GetType() == CPLJSONObject::Type::Object)
     442             :                 {
     443         144 :                     auto osGeoFieldName = oGeoField.GetString("GeoFieldName");
     444         144 :                     auto oDimList = oGeoField.GetArray("DimList");
     445          48 :                     bool bValid = true;
     446          96 :                     std::vector<Dimension> aoDimensions;
     447         128 :                     for (int j = 0; j < oDimList.Size(); ++j)
     448             :                     {
     449         160 :                         const auto osDimensionName = oDimList[j].ToString();
     450             :                         const auto oIter = oMapDimensionNameToSize.find(
     451          80 :                             osDimensionName.c_str());
     452          80 :                         if (oIter == oMapDimensionNameToSize.end())
     453             :                         {
     454           0 :                             bValid = false;
     455           0 :                             break;
     456             :                         }
     457         160 :                         Dimension oDim;
     458          80 :                         oDim.osName = osDimensionName;
     459          80 :                         oDim.nSize = oIter->second;
     460          80 :                         aoDimensions.push_back(std::move(oDim));
     461          80 :                         if (oMapDataDimensionToGeoDimension.find(
     462          80 :                                 osDimensionName) ==
     463         160 :                             oMapDataDimensionToGeoDimension.end())
     464             :                         {
     465             :                             // Create a fake dimension map for this dim
     466          64 :                             DimensionMap oDimensionMap;
     467          32 :                             oDimensionMap.osGeoDimName = osDimensionName;
     468          32 :                             oDimensionMap.osDataDimName = osDimensionName;
     469          32 :                             oDimensionMap.nOffset = 0;
     470          32 :                             oDimensionMap.nIncrement = 1;
     471          32 :                             oMapDataDimensionToGeoDimension[osDimensionName] =
     472          32 :                                 osDimensionName;
     473          32 :                             aoDimensionMaps.emplace_back(oDimensionMap);
     474             :                         }
     475             :                     }
     476          48 :                     if (bValid)
     477             :                     {
     478          48 :                         if (osGeoFieldName == "Longitude")
     479          16 :                             aoLongitudeDimensions = std::move(aoDimensions);
     480          32 :                         else if (osGeoFieldName == "Latitude")
     481          16 :                             aoLatitudeDimensions = std::move(aoDimensions);
     482             :                     }
     483             :                 }
     484             :             }
     485             : 
     486             :             // Second pass to register field
     487          96 :             for (const auto &oGeoField : oGeoFields.GetChildren())
     488             :             {
     489          80 :                 if (oGeoField.GetType() == CPLJSONObject::Type::Object)
     490             :                 {
     491             :                     const auto osGeoFieldName =
     492         144 :                         oGeoField.GetString("GeoFieldName");
     493         144 :                     const auto oDimList = oGeoField.GetArray("DimList");
     494          48 :                     bool bValid = true;
     495          96 :                     SwathFieldMetadata oMetadata;
     496          48 :                     oMetadata.poSwathMetadata = poSwathMetadataRef;
     497         128 :                     for (int j = 0; j < oDimList.Size(); ++j)
     498             :                     {
     499         160 :                         const auto osDimensionName = oDimList[j].ToString();
     500             :                         const auto oIter = oMapDimensionNameToSize.find(
     501          80 :                             osDimensionName.c_str());
     502          80 :                         if (oIter == oMapDimensionNameToSize.end())
     503             :                         {
     504           0 :                             bValid = false;
     505           0 :                             break;
     506             :                         }
     507         160 :                         Dimension oDim;
     508          80 :                         oDim.osName = std::move(osDimensionName);
     509          80 :                         oDim.nSize = oIter->second;
     510          80 :                         oMetadata.aoDimensions.push_back(std::move(oDim));
     511             :                     }
     512          48 :                     if (bValid)
     513             :                     {
     514          80 :                         if (oMetadata.aoDimensions.size() >= 2 &&
     515          80 :                             aoLongitudeDimensions.size() == 2 &&
     516          32 :                             aoLongitudeDimensions == aoLatitudeDimensions)
     517             :                         {
     518          32 :                             int i = 0;
     519          64 :                             std::string osDataXDimName;
     520          64 :                             std::string osDataYDimName;
     521          96 :                             for (const auto &oDimSwath : oMetadata.aoDimensions)
     522             :                             {
     523             :                                 auto oIter =
     524             :                                     oMapDataDimensionToGeoDimension.find(
     525          64 :                                         oDimSwath.osName);
     526          64 :                                 if (oIter !=
     527         128 :                                     oMapDataDimensionToGeoDimension.end())
     528             :                                 {
     529          64 :                                     const auto &osGeoDimName = oIter->second;
     530          64 :                                     if (osGeoDimName ==
     531          64 :                                         aoLongitudeDimensions[0].osName)
     532             :                                     {
     533          32 :                                         osDataYDimName = oDimSwath.osName;
     534          32 :                                         oMetadata.iYDim = i;
     535             :                                     }
     536          32 :                                     else if (osGeoDimName ==
     537          32 :                                              aoLongitudeDimensions[1].osName)
     538             :                                     {
     539          32 :                                         osDataXDimName = oDimSwath.osName;
     540          32 :                                         oMetadata.iXDim = i;
     541             :                                     }
     542             :                                 }
     543             :                                 else
     544             :                                 {
     545           0 :                                     oMetadata.iOtherDim = i;
     546             :                                 }
     547          64 :                                 ++i;
     548             :                             }
     549          32 :                             if (oMetadata.iXDim >= 0 && oMetadata.iYDim >= 0)
     550             :                             {
     551             :                                 oMetadata.osLongitudeSubdataset =
     552          64 :                                     "//HDFEOS/SWATHS/" + osSwathName +
     553          32 :                                     "/Geolocation_Fields/Longitude";
     554             :                                 oMetadata.osLatitudeSubdataset =
     555          64 :                                     "//HDFEOS/SWATHS/" + osSwathName +
     556          32 :                                     "/Geolocation_Fields/Latitude";
     557             : 
     558         120 :                                 for (const auto &oDimMap : aoDimensionMaps)
     559             :                                 {
     560          88 :                                     if (oDimMap.osDataDimName == osDataYDimName)
     561             :                                     {
     562          32 :                                         oMetadata.nLineOffset = oDimMap.nOffset;
     563          32 :                                         oMetadata.nLineStep =
     564          32 :                                             oDimMap.nIncrement;
     565             :                                     }
     566          56 :                                     else if (oDimMap.osDataDimName ==
     567             :                                              osDataXDimName)
     568             :                                     {
     569          32 :                                         oMetadata.nPixelOffset =
     570          32 :                                             oDimMap.nOffset;
     571          32 :                                         oMetadata.nPixelStep =
     572          32 :                                             oDimMap.nIncrement;
     573             :                                     }
     574             :                                 }
     575             :                             }
     576             :                         }
     577             : 
     578             :                         const std::string osSubdatasetName =
     579          96 :                             "//HDFEOS/SWATHS/" + osSwathName +
     580          96 :                             "/Geolocation_Fields/" + osGeoFieldName;
     581             :                         m_oMapSubdatasetNameToSwathFieldMetadata
     582          48 :                             [osSubdatasetName] = std::move(oMetadata);
     583             :                     }
     584             :                 }
     585             :             }
     586             : 
     587          48 :             const auto oDataFields = oSwath.GetObj("DataField");
     588          94 :             for (const auto &oDataField : oDataFields.GetChildren())
     589             :             {
     590          78 :                 if (oDataField.GetType() == CPLJSONObject::Type::Object)
     591             :                 {
     592             :                     const auto osDataFieldName =
     593         138 :                         oDataField.GetString("DataFieldName");
     594         138 :                     const auto oDimList = oDataField.GetArray("DimList");
     595          92 :                     SwathFieldMetadata oMetadata;
     596          46 :                     oMetadata.poSwathMetadata = poSwathMetadataRef;
     597          46 :                     bool bValid = oDimList.Size() > 0;
     598         130 :                     for (int j = 0; j < oDimList.Size(); ++j)
     599             :                     {
     600         168 :                         std::string osDimensionName = oDimList[j].ToString();
     601             :                         const auto oIter = oMapDimensionNameToSize.find(
     602          84 :                             osDimensionName.c_str());
     603          84 :                         if (oIter == oMapDimensionNameToSize.end())
     604             :                         {
     605           0 :                             bValid = false;
     606           0 :                             break;
     607             :                         }
     608         168 :                         Dimension oDim;
     609          84 :                         oDim.osName = std::move(osDimensionName);
     610          84 :                         oDim.nSize = oIter->second;
     611          84 :                         oMetadata.aoDimensions.push_back(std::move(oDim));
     612             :                     }
     613          46 :                     if (bValid)
     614             :                     {
     615          68 :                         if (oMetadata.aoDimensions.size() >= 2 &&
     616          68 :                             aoLongitudeDimensions.size() == 2 &&
     617          22 :                             aoLongitudeDimensions == aoLatitudeDimensions)
     618             :                         {
     619          22 :                             int i = 0;
     620          44 :                             std::string osDataXDimName;
     621          44 :                             std::string osDataYDimName;
     622          82 :                             for (const auto &oDimSwath : oMetadata.aoDimensions)
     623             :                             {
     624             :                                 auto oIter =
     625             :                                     oMapDataDimensionToGeoDimension.find(
     626          60 :                                         oDimSwath.osName);
     627          60 :                                 if (oIter !=
     628         120 :                                     oMapDataDimensionToGeoDimension.end())
     629             :                                 {
     630          44 :                                     const auto &osGeoDimName = oIter->second;
     631          44 :                                     if (osGeoDimName ==
     632          44 :                                         aoLongitudeDimensions[0].osName)
     633             :                                     {
     634          22 :                                         osDataYDimName = oDimSwath.osName;
     635          22 :                                         oMetadata.iYDim = i;
     636             :                                     }
     637          22 :                                     else if (osGeoDimName ==
     638          22 :                                              aoLongitudeDimensions[1].osName)
     639             :                                     {
     640          22 :                                         osDataXDimName = oDimSwath.osName;
     641          22 :                                         oMetadata.iXDim = i;
     642             :                                     }
     643             :                                 }
     644             :                                 else
     645             :                                 {
     646          16 :                                     oMetadata.iOtherDim = i;
     647             :                                 }
     648          60 :                                 ++i;
     649             :                             }
     650          22 :                             if (oMetadata.iXDim >= 0 && oMetadata.iYDim >= 0)
     651             :                             {
     652             :                                 oMetadata.osLongitudeSubdataset =
     653          44 :                                     "//HDFEOS/SWATHS/" + osSwathName +
     654          22 :                                     "/Geolocation_Fields/Longitude";
     655             :                                 oMetadata.osLatitudeSubdataset =
     656          44 :                                     "//HDFEOS/SWATHS/" + osSwathName +
     657          22 :                                     "/Geolocation_Fields/Latitude";
     658             : 
     659          90 :                                 for (const auto &oDimMap : aoDimensionMaps)
     660             :                                 {
     661          68 :                                     if (oDimMap.osDataDimName == osDataYDimName)
     662             :                                     {
     663          22 :                                         oMetadata.nLineOffset = oDimMap.nOffset;
     664          22 :                                         oMetadata.nLineStep =
     665          22 :                                             oDimMap.nIncrement;
     666             :                                     }
     667          46 :                                     else if (oDimMap.osDataDimName ==
     668             :                                              osDataXDimName)
     669             :                                     {
     670          22 :                                         oMetadata.nPixelOffset =
     671          22 :                                             oDimMap.nOffset;
     672          22 :                                         oMetadata.nPixelStep =
     673          22 :                                             oDimMap.nIncrement;
     674             :                                     }
     675             :                                 }
     676             :                             }
     677             :                         }
     678             : 
     679             :                         m_oMapSubdatasetNameToSwathFieldMetadata
     680          92 :                             ["//HDFEOS/SWATHS/" + osSwathName +
     681         138 :                              "/Data_Fields/" + osDataFieldName] =
     682          92 :                                 std::move(oMetadata);
     683             :                     }
     684             :                 }
     685             :             }
     686             :         }
     687             :     }
     688          16 : }
     689             : 
     690             : /************************************************************************/
     691             : /*                        GetSwathMetadata()                            */
     692             : /************************************************************************/
     693             : 
     694           3 : bool HDF5EOSParser::GetSwathMetadata(const std::string &osSwathName,
     695             :                                      SwathMetadata &swathMetadataOut) const
     696             : {
     697           3 :     const auto oIter = m_oMapSwathNameToSwathMetadata.find(osSwathName);
     698           3 :     if (oIter == m_oMapSwathNameToSwathMetadata.end())
     699           0 :         return false;
     700           3 :     swathMetadataOut = *(oIter->second.get());
     701           3 :     return true;
     702             : }
     703             : 
     704             : /************************************************************************/
     705             : /*                        GetSwathFieldMetadata()                       */
     706             : /************************************************************************/
     707             : 
     708          23 : bool HDF5EOSParser::GetSwathFieldMetadata(
     709             :     const char *pszSubdatasetName,
     710             :     SwathFieldMetadata &swathFieldMetadataOut) const
     711             : {
     712             :     const auto oIter =
     713          23 :         m_oMapSubdatasetNameToSwathFieldMetadata.find(pszSubdatasetName);
     714          23 :     if (oIter == m_oMapSubdatasetNameToSwathFieldMetadata.end())
     715           2 :         return false;
     716          21 :     swathFieldMetadataOut = oIter->second;
     717          21 :     return true;
     718             : }
     719             : 
     720             : /************************************************************************/
     721             : /*                        GetGeoTransform()                             */
     722             : /************************************************************************/
     723             : 
     724           9 : bool HDF5EOSParser::GridMetadata::GetGeoTransform(GDALGeoTransform &gt) const
     725             : {
     726           9 :     if (nProjCode >= 0 &&
     727          20 :         (osGridOrigin == "HE5_HDFE_GD_UL" || osGridOrigin.empty()) &&
     728          27 :         adfUpperLeftPointMeters.size() == 2 &&
     729           9 :         adfLowerRightPointMeters.size() == 2)
     730             :     {
     731           9 :         int nRasterXSize = 0;
     732           9 :         int nRasterYSize = 0;
     733             : 
     734          31 :         for (const auto &oDim : aoDimensions)
     735             :         {
     736          22 :             if (oDim.osName == "XDim")
     737           9 :                 nRasterXSize = oDim.nSize;
     738          13 :             else if (oDim.osName == "YDim")
     739           9 :                 nRasterYSize = oDim.nSize;
     740             :         }
     741           9 :         if (nRasterXSize <= 0 || nRasterYSize <= 0)
     742           0 :             return false;
     743           9 :         if (nProjCode == 0)  // GEO
     744             :         {
     745           2 :             gt[0] = CPLPackedDMSToDec(adfUpperLeftPointMeters[0]);
     746           2 :             gt[1] = (CPLPackedDMSToDec(adfLowerRightPointMeters[0]) -
     747           2 :                      CPLPackedDMSToDec(adfUpperLeftPointMeters[0])) /
     748             :                     nRasterXSize;
     749           2 :             gt[2] = 0;
     750           2 :             gt[3] = CPLPackedDMSToDec(adfUpperLeftPointMeters[1]);
     751           2 :             gt[4] = 0;
     752           4 :             gt[5] = (CPLPackedDMSToDec(adfLowerRightPointMeters[1]) -
     753           2 :                      CPLPackedDMSToDec(adfUpperLeftPointMeters[1])) /
     754             :                     nRasterYSize;
     755             :         }
     756             :         else
     757             :         {
     758           7 :             gt[0] = adfUpperLeftPointMeters[0];
     759           7 :             gt[1] = (adfLowerRightPointMeters[0] - adfUpperLeftPointMeters[0]) /
     760             :                     nRasterXSize;
     761           7 :             gt[2] = 0;
     762           7 :             gt[3] = adfUpperLeftPointMeters[1];
     763           7 :             gt[4] = 0;
     764           7 :             gt[5] = (adfLowerRightPointMeters[1] - adfUpperLeftPointMeters[1]) /
     765             :                     nRasterYSize;
     766             :         }
     767           9 :         return true;
     768             :     }
     769           0 :     return false;
     770             : }
     771             : 
     772             : /************************************************************************/
     773             : /*                              GetSRS()                                */
     774             : /************************************************************************/
     775             : 
     776           9 : std::unique_ptr<OGRSpatialReference> HDF5EOSParser::GridMetadata::GetSRS() const
     777             : {
     778          18 :     std::vector<double> l_adfProjParams = adfProjParams;
     779           9 :     l_adfProjParams.resize(15);
     780          18 :     auto poSRS = std::make_unique<OGRSpatialReference>();
     781           9 :     poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     782          18 :     if (poSRS->importFromUSGS(nProjCode, nZone, l_adfProjParams.data(),
     783          18 :                               nSphereCode) == OGRERR_NONE)
     784             :     {
     785           9 :         return poSRS;
     786             :     }
     787           0 :     return nullptr;
     788             : }

Generated by: LCOV version 1.14