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 56001 : int HDF4DatasetIdentify(GDALOpenInfo *poOpenInfo) 22 : 23 : { 24 56001 : if (poOpenInfo->nHeaderBytes < 4) 25 49722 : return FALSE; 26 : 27 6279 : if (memcmp(poOpenInfo->pabyHeader, "\016\003\023\001", 4) != 0) 28 5654 : 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 17 : void parseFileName() override 48 : { 49 : 50 34 : if (!STARTS_WITH_CI(m_fileName.c_str(), "HDF4_SDS:") && 51 17 : !STARTS_WITH_CI(m_fileName.c_str(), "HDF4_EOS:")) 52 : { 53 0 : return; 54 : } 55 : 56 34 : CPLStringList aosParts{CSLTokenizeString2(m_fileName.c_str(), ":", 0)}; 57 17 : const int iPartsCount{CSLCount(aosParts)}; 58 : 59 17 : if (iPartsCount >= 3) 60 : { 61 : 62 : // prefix + mode 63 14 : m_driverPrefixComponent = aosParts[0]; 64 14 : m_driverPrefixComponent.append(":"); 65 14 : m_driverPrefixComponent.append(aosParts[1]); 66 : 67 14 : int subdatasetIndex{3}; 68 : 69 14 : if (iPartsCount >= 4) 70 : { 71 : const bool hasDriveLetter{ 72 12 : (strlen(aosParts[3]) > 1 && 73 18 : (aosParts[3][0] == '\\' || aosParts[3][0] == '/')) && 74 6 : ((strlen(aosParts[2]) == 2 && 75 2 : std::isalpha( 76 2 : static_cast<unsigned char>(aosParts[2][1]))) || 77 4 : (strlen(aosParts[2]) == 1 && 78 3 : std::isalpha( 79 3 : static_cast<unsigned char>(aosParts[2][0]))))}; 80 12 : m_pathComponent = aosParts[2]; 81 : 82 12 : const bool hasProtocol{m_pathComponent.find("/vsicurl/") != 83 12 : std::string::npos}; 84 : 85 12 : if (hasDriveLetter || hasProtocol) 86 : { 87 6 : m_pathComponent.append(":"); 88 6 : m_pathComponent.append(aosParts[3]); 89 6 : subdatasetIndex++; 90 : } 91 : } 92 : 93 14 : if (iPartsCount > subdatasetIndex) 94 : { 95 12 : m_subdatasetComponent = aosParts[subdatasetIndex]; 96 : 97 : // Append any remaining part 98 23 : for (int i = subdatasetIndex + 1; i < iPartsCount; ++i) 99 : { 100 11 : m_subdatasetComponent.append(":"); 101 11 : m_subdatasetComponent.append(aosParts[i]); 102 : } 103 : } 104 : } 105 : } 106 : }; 107 : 108 2627 : static GDALSubdatasetInfo *HDF4DriverGetSubdatasetInfo(const char *pszFileName) 109 : { 110 2627 : if (STARTS_WITH_CI(pszFileName, "HDF4_SDS:") || 111 2627 : 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 2615 : return nullptr; 122 : } 123 : 124 : /************************************************************************/ 125 : /* HDF4DriverSetCommonMetadata() */ 126 : /************************************************************************/ 127 : 128 1302 : void HDF4DriverSetCommonMetadata(GDALDriver *poDriver) 129 : { 130 1302 : poDriver->SetDescription(HDF4_DRIVER_NAME); 131 1302 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); 132 1302 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, 133 1302 : "Hierarchical Data Format Release 4"); 134 1302 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/hdf4.html"); 135 1302 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "hdf"); 136 1302 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES"); 137 : 138 1302 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES"); 139 : 140 1302 : 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 1302 : "</OpenOptionList>"); 150 : 151 1302 : poDriver->pfnIdentify = HDF4DatasetIdentify; 152 1302 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); 153 1302 : poDriver->pfnGetSubdatasetInfoFunc = HDF4DriverGetSubdatasetInfo; 154 1302 : } 155 : 156 : /************************************************************************/ 157 : /* HDF4ImageDatasetIdentify() */ 158 : /************************************************************************/ 159 : 160 55088 : int HDF4ImageDatasetIdentify(GDALOpenInfo *poOpenInfo) 161 : { 162 55088 : if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_SDS:") && 163 54491 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_GR:") && 164 54487 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_GD:") && 165 54486 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_EOS:")) 166 54487 : return false; 167 601 : return true; 168 : } 169 : 170 : /************************************************************************/ 171 : /* HDF4ImageDriverSetCommonMetadata() */ 172 : /************************************************************************/ 173 : 174 1302 : void HDF4ImageDriverSetCommonMetadata(GDALDriver *poDriver) 175 : { 176 1302 : poDriver->SetDescription(HDF4_IMAGE_DRIVER_NAME); 177 1302 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); 178 1302 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "HDF4 Dataset"); 179 1302 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/hdf4.html"); 180 1302 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, 181 : "Byte Int8 Int16 UInt16 Int32 UInt32 " 182 : // "Int64 UInt64 " 183 1302 : "Float32 Float64"); 184 1302 : poDriver->SetMetadataItem( 185 : GDAL_DMD_CREATIONOPTIONLIST, 186 : "<CreationOptionList>" 187 : " <Option name='RANK' type='int' description='Rank of output SDS'/>" 188 1302 : "</CreationOptionList>"); 189 : 190 1302 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); 191 1302 : poDriver->pfnIdentify = HDF4ImageDatasetIdentify; 192 1302 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES"); 193 1302 : } 194 : 195 : /************************************************************************/ 196 : /* DeclareDeferredHDF4Plugin() */ 197 : /************************************************************************/ 198 : 199 : #ifdef PLUGIN_FILENAME 200 1595 : void DeclareDeferredHDF4Plugin() 201 : { 202 1595 : if (GDALGetDriverByName(HDF4_DRIVER_NAME) != nullptr) 203 : { 204 302 : return; 205 : } 206 : { 207 1293 : 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 1293 : HDF4DriverSetCommonMetadata(poDriver); 213 1293 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); 214 : } 215 : { 216 1293 : 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 1293 : HDF4ImageDriverSetCommonMetadata(poDriver); 222 1293 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); 223 : } 224 : } 225 : #endif