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