LCOV - code coverage report
Current view: top level - frmts/hdf4 - hdf4drivercore.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 90 92 97.8 %
Date: 2026-08-22 15:37:05 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  HDF4 driver
       5             :  * Author:   Even Rouault, <even.rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2023, Even Rouault, <even.rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "hdf4drivercore.h"
      14             : 
      15             : #include "gdal_frmts.h"
      16             : #include "gdalplugindriverproxy.h"
      17             : 
      18             : #include <cctype>
      19             : 
      20             : #include "gdalsubdatasetinfo.h"
      21             : 
      22             : /************************************************************************/
      23             : /*                              Identify()                              */
      24             : /************************************************************************/
      25             : 
      26       68289 : int HDF4DatasetIdentify(GDALOpenInfo *poOpenInfo)
      27             : 
      28             : {
      29       68289 :     if (poOpenInfo->nHeaderBytes < 4)
      30       60245 :         return FALSE;
      31             : 
      32        8044 :     if (memcmp(poOpenInfo->pabyHeader, "\016\003\023\001", 4) != 0)
      33        7395 :         return FALSE;
      34             : 
      35         649 :     return TRUE;
      36             : }
      37             : 
      38             : /************************************************************************/
      39             : /*                    HDF4DriverGetSubdatasetInfo()                     */
      40             : /************************************************************************/
      41             : 
      42             : struct HDF4DriverSubdatasetInfo final : public GDALSubdatasetInfo
      43             : {
      44             :   public:
      45          14 :     explicit HDF4DriverSubdatasetInfo(const std::string &fileName)
      46          14 :         : GDALSubdatasetInfo(fileName)
      47             :     {
      48          14 :     }
      49             : 
      50             :     // GDALSubdatasetInfo interface
      51             :   private:
      52             :     void parseFileName() override;
      53             : };
      54             : 
      55          14 : void HDF4DriverSubdatasetInfo::parseFileName()
      56             : {
      57             : 
      58          28 :     if (!STARTS_WITH_CI(m_fileName.c_str(), "HDF4_SDS:") &&
      59          14 :         !STARTS_WITH_CI(m_fileName.c_str(), "HDF4_EOS:"))
      60             :     {
      61           0 :         return;
      62             :     }
      63             : 
      64             :     CPLStringList aosParts{CSLTokenizeString2(
      65          28 :         m_fileName.c_str(), ":", CSLT_HONOURSTRINGS | CSLT_PRESERVEQUOTES)};
      66          14 :     const int iPartsCount{CSLCount(aosParts)};
      67             : 
      68          14 :     if (iPartsCount >= 3)
      69             :     {
      70             : 
      71             :         // prefix + mode
      72          11 :         m_driverPrefixComponent = aosParts[0];
      73          11 :         m_driverPrefixComponent.append(":");
      74          11 :         m_driverPrefixComponent.append(aosParts[1]);
      75             : 
      76          11 :         int subdatasetIndex{3};
      77             : 
      78          11 :         if (iPartsCount >= 4)
      79             :         {
      80             :             const bool hasDriveLetter{
      81           9 :                 (strlen(aosParts[3]) > 1 &&
      82          13 :                  (aosParts[3][0] == '\\' || aosParts[3][0] == '/')) &&
      83           4 :                 ((strlen(aosParts[2]) == 2 &&
      84           0 :                   std::isalpha(static_cast<unsigned char>(aosParts[2][1]))) ||
      85           4 :                  (strlen(aosParts[2]) == 1 &&
      86           1 :                   std::isalpha(static_cast<unsigned char>(aosParts[2][0]))))};
      87           9 :             m_pathComponent = aosParts[2];
      88             : 
      89           9 :             const bool hasProtocol{m_pathComponent.find("/vsicurl/") !=
      90           9 :                                    std::string::npos};
      91             : 
      92             :             // If the patch component was double quoted, the drive or
      93             :             // protocol will be part of the path component and we should not append it again
      94             : 
      95          11 :             if ((m_pathComponent.size() > 0 && m_pathComponent[0] != '"') &&
      96           2 :                 (hasDriveLetter || hasProtocol))
      97             :             {
      98           1 :                 m_pathComponent.append(":");
      99           1 :                 m_pathComponent.append(aosParts[3]);
     100           1 :                 subdatasetIndex++;
     101             :             }
     102             :         }
     103             : 
     104          11 :         if (iPartsCount > subdatasetIndex)
     105             :         {
     106           9 :             m_subdatasetComponent = aosParts[subdatasetIndex];
     107             : 
     108             :             // Append any remaining part
     109          14 :             for (int i = subdatasetIndex + 1; i < iPartsCount; ++i)
     110             :             {
     111           5 :                 m_subdatasetComponent.append(":");
     112           5 :                 m_subdatasetComponent.append(aosParts[i]);
     113             :             }
     114             :         }
     115             :     }
     116             : }
     117             : 
     118        2763 : static GDALSubdatasetInfo *HDF4DriverGetSubdatasetInfo(const char *pszFileName)
     119             : {
     120        2763 :     if (STARTS_WITH_CI(pszFileName, "HDF4_SDS:") ||
     121        2763 :         STARTS_WITH_CI(pszFileName, "HDF4_EOS:"))
     122             :     {
     123             :         std::unique_ptr<GDALSubdatasetInfo> info =
     124          14 :             std::make_unique<HDF4DriverSubdatasetInfo>(pszFileName);
     125          37 :         if (!info->GetSubdatasetComponent().empty() &&
     126          23 :             !info->GetPathComponent().empty())
     127             :         {
     128           9 :             return info.release();
     129             :         }
     130             :     }
     131        2754 :     return nullptr;
     132             : }
     133             : 
     134             : /************************************************************************/
     135             : /*                    HDF4DriverSetCommonMetadata()                     */
     136             : /************************************************************************/
     137             : 
     138        1885 : void HDF4DriverSetCommonMetadata(GDALDriver *poDriver)
     139             : {
     140        1885 :     poDriver->SetDescription(HDF4_DRIVER_NAME);
     141        1885 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     142        1885 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     143        1885 :                               "Hierarchical Data Format Release 4");
     144        1885 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/hdf4.html");
     145        1885 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "hdf");
     146        1885 :     poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
     147             : 
     148        1885 :     poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
     149             : 
     150        1885 :     poDriver->SetMetadataItem(
     151             :         GDAL_DMD_OPENOPTIONLIST,
     152             :         "<OpenOptionList>"
     153             :         "  <Option name='LIST_SDS' type='string-select' "
     154             :         "description='Whether to report Scientific Data Sets' default='AUTO'>"
     155             :         "       <Value>AUTO</Value>"
     156             :         "       <Value>YES</Value>"
     157             :         "       <Value>NO</Value>"
     158             :         "  </Option>"
     159        1885 :         "</OpenOptionList>");
     160             : 
     161        1885 :     poDriver->pfnIdentify = HDF4DatasetIdentify;
     162        1885 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     163        1885 :     poDriver->pfnGetSubdatasetInfoFunc = HDF4DriverGetSubdatasetInfo;
     164        1885 : }
     165             : 
     166             : /************************************************************************/
     167             : /*                      HDF4ImageDatasetIdentify()                      */
     168             : /************************************************************************/
     169             : 
     170       66405 : int HDF4ImageDatasetIdentify(GDALOpenInfo *poOpenInfo)
     171             : {
     172       66405 :     if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_SDS:") &&
     173       66106 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_GR:") &&
     174       66104 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_GD:") &&
     175       66104 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_EOS:"))
     176       66102 :         return false;
     177         303 :     return true;
     178             : }
     179             : 
     180             : /************************************************************************/
     181             : /*                  HDF4ImageDriverSetCommonMetadata()                  */
     182             : /************************************************************************/
     183             : 
     184        1885 : void HDF4ImageDriverSetCommonMetadata(GDALDriver *poDriver)
     185             : {
     186        1885 :     poDriver->SetDescription(HDF4_IMAGE_DRIVER_NAME);
     187        1885 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     188        1885 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "HDF4 Dataset");
     189        1885 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/hdf4.html");
     190        1885 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
     191             :                               "Byte Int8 Int16 UInt16 Int32 UInt32 "
     192             :                               // "Int64 UInt64 "
     193        1885 :                               "Float32 Float64");
     194        1885 :     poDriver->SetMetadataItem(
     195             :         GDAL_DMD_CREATIONOPTIONLIST,
     196             :         "<CreationOptionList>"
     197             :         "   <Option name='RANK' type='int' description='Rank of output SDS'/>"
     198        1885 :         "</CreationOptionList>");
     199             : 
     200        1885 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     201        1885 :     poDriver->pfnIdentify = HDF4ImageDatasetIdentify;
     202        1885 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
     203        1885 : }
     204             : 
     205             : /************************************************************************/
     206             : /*                     DeclareDeferredHDF4Plugin()                      */
     207             : /************************************************************************/
     208             : 
     209             : #ifdef PLUGIN_FILENAME
     210        2138 : void DeclareDeferredHDF4Plugin()
     211             : {
     212        2138 :     if (GDALGetDriverByName(HDF4_DRIVER_NAME) != nullptr)
     213             :     {
     214         263 :         return;
     215             :     }
     216             :     {
     217        1875 :         auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     218             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     219             :         poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     220             :                                   PLUGIN_INSTALLATION_MESSAGE);
     221             : #endif
     222        1875 :         HDF4DriverSetCommonMetadata(poDriver);
     223        1875 :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     224             :     }
     225             :     {
     226        1875 :         auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     227             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     228             :         poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     229             :                                   PLUGIN_INSTALLATION_MESSAGE);
     230             : #endif
     231        1875 :         HDF4ImageDriverSetCommonMetadata(poDriver);
     232        1875 :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     233             :     }
     234             : }
     235             : #endif

Generated by: LCOV version 1.14