LCOV - code coverage report
Current view: top level - frmts/hdf4 - hdf4drivercore.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 90 91 98.9 %
Date: 2025-10-01 17:07:58 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       62784 : int HDF4DatasetIdentify(GDALOpenInfo *poOpenInfo)
      27             : 
      28             : {
      29       62784 :     if (poOpenInfo->nHeaderBytes < 4)
      30       56472 :         return FALSE;
      31             : 
      32        6312 :     if (memcmp(poOpenInfo->pabyHeader, "\016\003\023\001", 4) != 0)
      33        5687 :         return FALSE;
      34             : 
      35         625 :     return TRUE;
      36             : }
      37             : 
      38             : /************************************************************************/
      39             : /*                    HDF4DriverGetSubdatasetInfo()                     */
      40             : /************************************************************************/
      41             : 
      42             : struct HDF4DriverSubdatasetInfo final : public GDALSubdatasetInfo
      43             : {
      44             :   public:
      45          17 :     explicit HDF4DriverSubdatasetInfo(const std::string &fileName)
      46          17 :         : GDALSubdatasetInfo(fileName)
      47             :     {
      48          17 :     }
      49             : 
      50             :     // GDALSubdatasetInfo interface
      51             :   private:
      52             :     void parseFileName() override;
      53             : };
      54             : 
      55          17 : void HDF4DriverSubdatasetInfo::parseFileName()
      56             : {
      57             : 
      58          34 :     if (!STARTS_WITH_CI(m_fileName.c_str(), "HDF4_SDS:") &&
      59          17 :         !STARTS_WITH_CI(m_fileName.c_str(), "HDF4_EOS:"))
      60             :     {
      61           0 :         return;
      62             :     }
      63             : 
      64          34 :     CPLStringList aosParts{CSLTokenizeString2(m_fileName.c_str(), ":", 0)};
      65          17 :     const int iPartsCount{CSLCount(aosParts)};
      66             : 
      67          17 :     if (iPartsCount >= 3)
      68             :     {
      69             : 
      70             :         // prefix + mode
      71          14 :         m_driverPrefixComponent = aosParts[0];
      72          14 :         m_driverPrefixComponent.append(":");
      73          14 :         m_driverPrefixComponent.append(aosParts[1]);
      74             : 
      75          14 :         int subdatasetIndex{3};
      76             : 
      77          14 :         if (iPartsCount >= 4)
      78             :         {
      79             :             const bool hasDriveLetter{
      80          12 :                 (strlen(aosParts[3]) > 1 &&
      81          18 :                  (aosParts[3][0] == '\\' || aosParts[3][0] == '/')) &&
      82           6 :                 ((strlen(aosParts[2]) == 2 &&
      83           2 :                   std::isalpha(static_cast<unsigned char>(aosParts[2][1]))) ||
      84           4 :                  (strlen(aosParts[2]) == 1 &&
      85           3 :                   std::isalpha(static_cast<unsigned char>(aosParts[2][0]))))};
      86          12 :             m_pathComponent = aosParts[2];
      87             : 
      88          12 :             const bool hasProtocol{m_pathComponent.find("/vsicurl/") !=
      89          12 :                                    std::string::npos};
      90             : 
      91          12 :             if (hasDriveLetter || hasProtocol)
      92             :             {
      93           6 :                 m_pathComponent.append(":");
      94           6 :                 m_pathComponent.append(aosParts[3]);
      95           6 :                 subdatasetIndex++;
      96             :             }
      97             :         }
      98             : 
      99          14 :         if (iPartsCount > subdatasetIndex)
     100             :         {
     101          12 :             m_subdatasetComponent = aosParts[subdatasetIndex];
     102             : 
     103             :             // Append any remaining part
     104          23 :             for (int i = subdatasetIndex + 1; i < iPartsCount; ++i)
     105             :             {
     106          11 :                 m_subdatasetComponent.append(":");
     107          11 :                 m_subdatasetComponent.append(aosParts[i]);
     108             :             }
     109             :         }
     110             :     }
     111             : }
     112             : 
     113        2729 : static GDALSubdatasetInfo *HDF4DriverGetSubdatasetInfo(const char *pszFileName)
     114             : {
     115        2729 :     if (STARTS_WITH_CI(pszFileName, "HDF4_SDS:") ||
     116        2729 :         STARTS_WITH_CI(pszFileName, "HDF4_EOS:"))
     117             :     {
     118             :         std::unique_ptr<GDALSubdatasetInfo> info =
     119          17 :             std::make_unique<HDF4DriverSubdatasetInfo>(pszFileName);
     120          46 :         if (!info->GetSubdatasetComponent().empty() &&
     121          29 :             !info->GetPathComponent().empty())
     122             :         {
     123          12 :             return info.release();
     124             :         }
     125             :     }
     126        2717 :     return nullptr;
     127             : }
     128             : 
     129             : /************************************************************************/
     130             : /*                   HDF4DriverSetCommonMetadata()                      */
     131             : /************************************************************************/
     132             : 
     133        2104 : void HDF4DriverSetCommonMetadata(GDALDriver *poDriver)
     134             : {
     135        2104 :     poDriver->SetDescription(HDF4_DRIVER_NAME);
     136        2104 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     137        2104 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     138        2104 :                               "Hierarchical Data Format Release 4");
     139        2104 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/hdf4.html");
     140        2104 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "hdf");
     141        2104 :     poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
     142             : 
     143        2104 :     poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
     144             : 
     145        2104 :     poDriver->SetMetadataItem(
     146             :         GDAL_DMD_OPENOPTIONLIST,
     147             :         "<OpenOptionList>"
     148             :         "  <Option name='LIST_SDS' type='string-select' "
     149             :         "description='Whether to report Scientific Data Sets' default='AUTO'>"
     150             :         "       <Value>AUTO</Value>"
     151             :         "       <Value>YES</Value>"
     152             :         "       <Value>NO</Value>"
     153             :         "  </Option>"
     154        2104 :         "</OpenOptionList>");
     155             : 
     156        2104 :     poDriver->pfnIdentify = HDF4DatasetIdentify;
     157        2104 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     158        2104 :     poDriver->pfnGetSubdatasetInfoFunc = HDF4DriverGetSubdatasetInfo;
     159        2104 : }
     160             : 
     161             : /************************************************************************/
     162             : /*                     HDF4ImageDatasetIdentify()                       */
     163             : /************************************************************************/
     164             : 
     165       61808 : int HDF4ImageDatasetIdentify(GDALOpenInfo *poOpenInfo)
     166             : {
     167       61808 :     if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_SDS:") &&
     168       61210 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_GR:") &&
     169       61206 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_GD:") &&
     170       61206 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_EOS:"))
     171       61206 :         return false;
     172         602 :     return true;
     173             : }
     174             : 
     175             : /************************************************************************/
     176             : /*                 HDF4ImageDriverSetCommonMetadata()                   */
     177             : /************************************************************************/
     178             : 
     179        2104 : void HDF4ImageDriverSetCommonMetadata(GDALDriver *poDriver)
     180             : {
     181        2104 :     poDriver->SetDescription(HDF4_IMAGE_DRIVER_NAME);
     182        2104 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     183        2104 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "HDF4 Dataset");
     184        2104 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/hdf4.html");
     185        2104 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
     186             :                               "Byte Int8 Int16 UInt16 Int32 UInt32 "
     187             :                               // "Int64 UInt64 "
     188        2104 :                               "Float32 Float64");
     189        2104 :     poDriver->SetMetadataItem(
     190             :         GDAL_DMD_CREATIONOPTIONLIST,
     191             :         "<CreationOptionList>"
     192             :         "   <Option name='RANK' type='int' description='Rank of output SDS'/>"
     193        2104 :         "</CreationOptionList>");
     194             : 
     195        2104 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     196        2104 :     poDriver->pfnIdentify = HDF4ImageDatasetIdentify;
     197        2104 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
     198        2104 : }
     199             : 
     200             : /************************************************************************/
     201             : /*                    DeclareDeferredHDF4Plugin()                       */
     202             : /************************************************************************/
     203             : 
     204             : #ifdef PLUGIN_FILENAME
     205        2033 : void DeclareDeferredHDF4Plugin()
     206             : {
     207        2033 :     if (GDALGetDriverByName(HDF4_DRIVER_NAME) != nullptr)
     208             :     {
     209         283 :         return;
     210             :     }
     211             :     {
     212        1750 :         auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     213             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     214             :         poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     215             :                                   PLUGIN_INSTALLATION_MESSAGE);
     216             : #endif
     217        1750 :         HDF4DriverSetCommonMetadata(poDriver);
     218        1750 :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     219             :     }
     220             :     {
     221        1750 :         auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     222             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     223             :         poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     224             :                                   PLUGIN_INSTALLATION_MESSAGE);
     225             : #endif
     226        1750 :         HDF4ImageDriverSetCommonMetadata(poDriver);
     227        1750 :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     228             :     }
     229             : }
     230             : #endif

Generated by: LCOV version 1.14