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 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "hdf4drivercore.h"
30 :
31 : #include <cctype>
32 :
33 : /************************************************************************/
34 : /* Identify() */
35 : /************************************************************************/
36 :
37 53213 : int HDF4DatasetIdentify(GDALOpenInfo *poOpenInfo)
38 :
39 : {
40 53213 : if (poOpenInfo->nHeaderBytes < 4)
41 47160 : return FALSE;
42 :
43 6053 : if (memcmp(poOpenInfo->pabyHeader, "\016\003\023\001", 4) != 0)
44 5428 : return FALSE;
45 :
46 625 : return TRUE;
47 : }
48 :
49 : /************************************************************************/
50 : /* HDF4DriverGetSubdatasetInfo() */
51 : /************************************************************************/
52 :
53 : struct HDF4DriverSubdatasetInfo : public GDALSubdatasetInfo
54 : {
55 : public:
56 17 : explicit HDF4DriverSubdatasetInfo(const std::string &fileName)
57 17 : : GDALSubdatasetInfo(fileName)
58 : {
59 17 : }
60 :
61 : // GDALSubdatasetInfo interface
62 : private:
63 17 : void parseFileName() override
64 : {
65 :
66 34 : if (!STARTS_WITH_CI(m_fileName.c_str(), "HDF4_SDS:") &&
67 17 : !STARTS_WITH_CI(m_fileName.c_str(), "HDF4_EOS:"))
68 : {
69 0 : return;
70 : }
71 :
72 34 : CPLStringList aosParts{CSLTokenizeString2(m_fileName.c_str(), ":", 0)};
73 17 : const int iPartsCount{CSLCount(aosParts)};
74 :
75 17 : if (iPartsCount >= 3)
76 : {
77 :
78 : // prefix + mode
79 14 : m_driverPrefixComponent = aosParts[0];
80 14 : m_driverPrefixComponent.append(":");
81 14 : m_driverPrefixComponent.append(aosParts[1]);
82 :
83 14 : int subdatasetIndex{3};
84 :
85 14 : if (iPartsCount >= 4)
86 : {
87 : const bool hasDriveLetter{
88 12 : (strlen(aosParts[3]) > 1 &&
89 18 : (aosParts[3][0] == '\\' || aosParts[3][0] == '/')) &&
90 6 : ((strlen(aosParts[2]) == 2 &&
91 2 : std::isalpha(
92 2 : static_cast<unsigned char>(aosParts[2][1]))) ||
93 4 : (strlen(aosParts[2]) == 1 &&
94 3 : std::isalpha(
95 3 : static_cast<unsigned char>(aosParts[2][0]))))};
96 12 : m_pathComponent = aosParts[2];
97 :
98 12 : const bool hasProtocol{m_pathComponent.find("/vsicurl/") !=
99 12 : std::string::npos};
100 :
101 12 : if (hasDriveLetter || hasProtocol)
102 : {
103 6 : m_pathComponent.append(":");
104 6 : m_pathComponent.append(aosParts[3]);
105 6 : subdatasetIndex++;
106 : }
107 : }
108 :
109 14 : if (iPartsCount > subdatasetIndex)
110 : {
111 12 : m_subdatasetComponent = aosParts[subdatasetIndex];
112 :
113 : // Append any remaining part
114 23 : for (int i = subdatasetIndex + 1; i < iPartsCount; ++i)
115 : {
116 11 : m_subdatasetComponent.append(":");
117 11 : m_subdatasetComponent.append(aosParts[i]);
118 : }
119 : }
120 : }
121 : }
122 : };
123 :
124 1020 : static GDALSubdatasetInfo *HDF4DriverGetSubdatasetInfo(const char *pszFileName)
125 : {
126 1020 : if (STARTS_WITH_CI(pszFileName, "HDF4_SDS:") ||
127 1020 : STARTS_WITH_CI(pszFileName, "HDF4_EOS:"))
128 : {
129 : std::unique_ptr<GDALSubdatasetInfo> info =
130 17 : std::make_unique<HDF4DriverSubdatasetInfo>(pszFileName);
131 46 : if (!info->GetSubdatasetComponent().empty() &&
132 29 : !info->GetPathComponent().empty())
133 : {
134 12 : return info.release();
135 : }
136 : }
137 1008 : return nullptr;
138 : }
139 :
140 : /************************************************************************/
141 : /* HDF4DriverSetCommonMetadata() */
142 : /************************************************************************/
143 :
144 1224 : void HDF4DriverSetCommonMetadata(GDALDriver *poDriver)
145 : {
146 1224 : poDriver->SetDescription(HDF4_DRIVER_NAME);
147 1224 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
148 1224 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
149 1224 : "Hierarchical Data Format Release 4");
150 1224 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/hdf4.html");
151 1224 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "hdf");
152 1224 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
153 :
154 1224 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
155 :
156 1224 : poDriver->SetMetadataItem(
157 : GDAL_DMD_OPENOPTIONLIST,
158 : "<OpenOptionList>"
159 : " <Option name='LIST_SDS' type='string-select' "
160 : "description='Whether to report Scientific Data Sets' default='AUTO'>"
161 : " <Value>AUTO</Value>"
162 : " <Value>YES</Value>"
163 : " <Value>NO</Value>"
164 : " </Option>"
165 1224 : "</OpenOptionList>");
166 :
167 1224 : poDriver->pfnIdentify = HDF4DatasetIdentify;
168 1224 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
169 1224 : poDriver->pfnGetSubdatasetInfoFunc = HDF4DriverGetSubdatasetInfo;
170 1224 : }
171 :
172 : /************************************************************************/
173 : /* HDF4ImageDatasetIdentify() */
174 : /************************************************************************/
175 :
176 52302 : int HDF4ImageDatasetIdentify(GDALOpenInfo *poOpenInfo)
177 : {
178 52302 : if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_SDS:") &&
179 51704 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_GR:") &&
180 51700 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_GD:") &&
181 51700 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "HDF4_EOS:"))
182 51699 : return false;
183 603 : return true;
184 : }
185 :
186 : /************************************************************************/
187 : /* HDF4ImageDriverSetCommonMetadata() */
188 : /************************************************************************/
189 :
190 1224 : void HDF4ImageDriverSetCommonMetadata(GDALDriver *poDriver)
191 : {
192 1224 : poDriver->SetDescription(HDF4_IMAGE_DRIVER_NAME);
193 1224 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
194 1224 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "HDF4 Dataset");
195 1224 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/hdf4.html");
196 1224 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
197 : "Byte Int8 Int16 UInt16 Int32 UInt32 "
198 : // "Int64 UInt64 "
199 1224 : "Float32 Float64");
200 1224 : poDriver->SetMetadataItem(
201 : GDAL_DMD_CREATIONOPTIONLIST,
202 : "<CreationOptionList>"
203 : " <Option name='RANK' type='int' description='Rank of output SDS'/>"
204 1224 : "</CreationOptionList>");
205 :
206 1224 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
207 1224 : poDriver->pfnIdentify = HDF4ImageDatasetIdentify;
208 1224 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
209 1224 : }
210 :
211 : /************************************************************************/
212 : /* DeclareDeferredHDF4Plugin() */
213 : /************************************************************************/
214 :
215 : #ifdef PLUGIN_FILENAME
216 1512 : void DeclareDeferredHDF4Plugin()
217 : {
218 1512 : if (GDALGetDriverByName(HDF4_DRIVER_NAME) != nullptr)
219 : {
220 295 : return;
221 : }
222 : {
223 1217 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
224 : #ifdef PLUGIN_INSTALLATION_MESSAGE
225 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
226 : PLUGIN_INSTALLATION_MESSAGE);
227 : #endif
228 1217 : HDF4DriverSetCommonMetadata(poDriver);
229 1217 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
230 : }
231 : {
232 1217 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
233 : #ifdef PLUGIN_INSTALLATION_MESSAGE
234 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
235 : PLUGIN_INSTALLATION_MESSAGE);
236 : #endif
237 1217 : HDF4ImageDriverSetCommonMetadata(poDriver);
238 1217 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
239 : }
240 : }
241 : #endif
|