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