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