Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Hierarchical Data Format Release 5 (HDF5)
4 : * Purpose: HDF5 convenience functions.
5 : * Author: Frank Warmerdam <warmerdam@pobox.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "cpl_float.h"
14 : #include "gh5_convenience.h"
15 :
16 : /************************************************************************/
17 : /* GH5_FetchAttribute(CPLString) */
18 : /************************************************************************/
19 :
20 84 : bool GH5_FetchAttribute(hid_t loc_id, const char *pszAttrName,
21 : CPLString &osResult, bool bReportError)
22 :
23 : {
24 84 : if (!bReportError && H5Aexists(loc_id, pszAttrName) <= 0)
25 : {
26 0 : return false;
27 : }
28 :
29 84 : hid_t hAttr = H5Aopen_name(loc_id, pszAttrName);
30 :
31 84 : osResult.clear();
32 :
33 84 : if (hAttr < 0)
34 : {
35 0 : if (bReportError)
36 0 : CPLError(CE_Failure, CPLE_AppDefined,
37 : "Attempt to read attribute %s failed, not found.",
38 : pszAttrName);
39 0 : return false;
40 : }
41 :
42 84 : const hid_t hAttrSpace = H5Aget_space(hAttr);
43 84 : hsize_t anSize[H5S_MAX_RANK] = {};
44 : const unsigned int nAttrDims =
45 84 : H5Sget_simple_extent_dims(hAttrSpace, anSize, nullptr);
46 84 : if (nAttrDims != 0 && !(nAttrDims == 1 && anSize[0] == 1))
47 : {
48 0 : H5Sclose(hAttrSpace);
49 0 : H5Aclose(hAttr);
50 0 : return false;
51 : }
52 :
53 84 : hid_t hAttrTypeID = H5Aget_type(hAttr);
54 84 : hid_t hAttrNativeType = H5Tget_native_type(hAttrTypeID, H5T_DIR_DEFAULT);
55 :
56 84 : bool retVal = false;
57 84 : if (H5Tget_class(hAttrNativeType) == H5T_STRING)
58 : {
59 84 : if (H5Tis_variable_str(hAttrNativeType))
60 : {
61 13 : char *aszBuffer[1] = {nullptr};
62 13 : H5Aread(hAttr, hAttrNativeType, aszBuffer);
63 :
64 13 : if (aszBuffer[0])
65 13 : osResult = aszBuffer[0];
66 :
67 13 : H5Dvlen_reclaim(hAttrNativeType, hAttrSpace, H5P_DEFAULT,
68 : aszBuffer);
69 : }
70 : else
71 : {
72 71 : const size_t nAttrSize = H5Tget_size(hAttrTypeID);
73 71 : char *pachBuffer = static_cast<char *>(CPLCalloc(nAttrSize + 1, 1));
74 71 : H5Aread(hAttr, hAttrNativeType, pachBuffer);
75 :
76 71 : osResult = pachBuffer;
77 71 : CPLFree(pachBuffer);
78 : }
79 :
80 84 : retVal = true;
81 : }
82 : else
83 : {
84 0 : if (bReportError)
85 0 : CPLError(
86 : CE_Failure, CPLE_AppDefined,
87 : "Attribute %s of unsupported type for conversion to string.",
88 : pszAttrName);
89 :
90 0 : retVal = false;
91 : }
92 :
93 84 : H5Sclose(hAttrSpace);
94 84 : H5Tclose(hAttrNativeType);
95 84 : H5Tclose(hAttrTypeID);
96 84 : H5Aclose(hAttr);
97 84 : return retVal;
98 : }
99 :
100 : /************************************************************************/
101 : /* GH5_FetchAttribute(double) */
102 : /************************************************************************/
103 :
104 964 : bool GH5_FetchAttribute(hid_t loc_id, const char *pszAttrName, double &dfResult,
105 : bool bReportError)
106 :
107 : {
108 964 : if (!bReportError && H5Aexists(loc_id, pszAttrName) <= 0)
109 : {
110 383 : return false;
111 : }
112 :
113 581 : const hid_t hAttr = H5Aopen_name(loc_id, pszAttrName);
114 :
115 581 : dfResult = 0.0;
116 581 : if (hAttr < 0)
117 : {
118 0 : if (bReportError)
119 0 : CPLError(CE_Failure, CPLE_AppDefined,
120 : "Attempt to read attribute %s failed, not found.",
121 : pszAttrName);
122 0 : return false;
123 : }
124 :
125 581 : hid_t hAttrTypeID = H5Aget_type(hAttr);
126 581 : hid_t hAttrNativeType = H5Tget_native_type(hAttrTypeID, H5T_DIR_DEFAULT);
127 :
128 : // Confirm that we have a single element value.
129 581 : hid_t hAttrSpace = H5Aget_space(hAttr);
130 581 : hsize_t anSize[H5S_MAX_RANK] = {};
131 581 : int nAttrDims = H5Sget_simple_extent_dims(hAttrSpace, anSize, nullptr);
132 :
133 581 : int i, nAttrElements = 1;
134 :
135 592 : for (i = 0; i < nAttrDims; i++)
136 : {
137 11 : nAttrElements *= (int)anSize[i];
138 : }
139 :
140 581 : if (nAttrElements != 1)
141 : {
142 0 : if (bReportError)
143 0 : CPLError(CE_Failure, CPLE_AppDefined,
144 : "Attempt to read attribute %s failed, count=%d, not 1.",
145 : pszAttrName, nAttrElements);
146 :
147 0 : H5Sclose(hAttrSpace);
148 0 : H5Tclose(hAttrNativeType);
149 0 : H5Tclose(hAttrTypeID);
150 0 : H5Aclose(hAttr);
151 0 : return false;
152 : }
153 :
154 : // Read the value.
155 581 : void *buf = CPLMalloc(H5Tget_size(hAttrNativeType));
156 581 : H5Aread(hAttr, hAttrNativeType, buf);
157 :
158 : // Translate to double.
159 581 : if (H5Tequal(H5T_NATIVE_CHAR, hAttrNativeType))
160 0 : dfResult = *((char *)buf);
161 581 : else if (H5Tequal(H5T_NATIVE_SCHAR, hAttrNativeType))
162 0 : dfResult = *((signed char *)buf);
163 581 : else if (H5Tequal(H5T_NATIVE_UCHAR, hAttrNativeType))
164 0 : dfResult = *((unsigned char *)buf);
165 581 : else if (H5Tequal(H5T_NATIVE_SHORT, hAttrNativeType))
166 0 : dfResult = *((short *)buf);
167 581 : else if (H5Tequal(H5T_NATIVE_USHORT, hAttrNativeType))
168 1 : dfResult = *((unsigned short *)buf);
169 580 : else if (H5Tequal(H5T_NATIVE_INT, hAttrNativeType))
170 0 : dfResult = *((int *)buf);
171 580 : else if (H5Tequal(H5T_NATIVE_UINT, hAttrNativeType))
172 1 : dfResult = *((unsigned int *)buf);
173 579 : else if (H5Tequal(H5T_NATIVE_INT64, hAttrNativeType))
174 : {
175 1 : const auto nVal = *static_cast<int64_t *>(buf);
176 1 : dfResult = static_cast<double>(nVal);
177 1 : if (nVal != static_cast<int64_t>(dfResult))
178 : {
179 0 : CPLDebug("HDF5",
180 : "Loss of accuracy when reading attribute %s. "
181 : "Value " CPL_FRMT_GIB " will be read as %.17g",
182 : pszAttrName, static_cast<GIntBig>(nVal), dfResult);
183 : }
184 : }
185 578 : else if (H5Tequal(H5T_NATIVE_UINT64, hAttrNativeType))
186 : {
187 1 : const auto nVal = *static_cast<uint64_t *>(buf);
188 1 : dfResult = static_cast<double>(nVal);
189 1 : if (nVal != static_cast<uint64_t>(dfResult))
190 : {
191 0 : CPLDebug("HDF5",
192 : "Loss of accuracy when reading attribute %s. "
193 : "Value " CPL_FRMT_GUIB " will be read as %.17g",
194 : pszAttrName, static_cast<GUIntBig>(nVal), dfResult);
195 : }
196 : }
197 : #ifdef HDF5_HAVE_FLOAT16
198 : else if (H5Tequal(H5T_NATIVE_FLOAT16, hAttrNativeType))
199 : {
200 : const uint16_t nVal16 = *((uint16_t *)buf);
201 : const uint32_t nVal32 = CPLHalfToFloat(nVal16);
202 : float fVal;
203 : memcpy(&fVal, &nVal32, sizeof(fVal));
204 : dfResult = fVal;
205 : }
206 : #endif
207 577 : else if (H5Tequal(H5T_NATIVE_FLOAT, hAttrNativeType))
208 535 : dfResult = *((float *)buf);
209 42 : else if (H5Tequal(H5T_NATIVE_DOUBLE, hAttrNativeType))
210 42 : dfResult = *((double *)buf);
211 : else
212 : {
213 0 : if (bReportError)
214 0 : CPLError(
215 : CE_Failure, CPLE_AppDefined,
216 : "Attribute %s of unsupported type for conversion to double.",
217 : pszAttrName);
218 0 : CPLFree(buf);
219 :
220 0 : H5Sclose(hAttrSpace);
221 0 : H5Tclose(hAttrNativeType);
222 0 : H5Tclose(hAttrTypeID);
223 0 : H5Aclose(hAttr);
224 :
225 0 : return false;
226 : }
227 :
228 581 : CPLFree(buf);
229 :
230 581 : H5Sclose(hAttrSpace);
231 581 : H5Tclose(hAttrNativeType);
232 581 : H5Tclose(hAttrTypeID);
233 581 : H5Aclose(hAttr);
234 581 : return true;
235 : }
236 :
237 : /************************************************************************/
238 : /* GH5_GetDataType() */
239 : /* */
240 : /* Transform HDF5 datatype to GDAL datatype */
241 : /************************************************************************/
242 144 : GDALDataType GH5_GetDataType(hid_t TypeID)
243 : {
244 144 : if (H5Tequal(H5T_NATIVE_CHAR, TypeID))
245 0 : return GDT_Byte;
246 144 : else if (H5Tequal(H5T_NATIVE_SCHAR, TypeID))
247 0 : return GDT_Int8;
248 144 : else if (H5Tequal(H5T_NATIVE_UCHAR, TypeID))
249 0 : return GDT_Byte;
250 144 : else if (H5Tequal(H5T_NATIVE_SHORT, TypeID))
251 0 : return GDT_Int16;
252 144 : else if (H5Tequal(H5T_NATIVE_USHORT, TypeID))
253 0 : return GDT_UInt16;
254 144 : else if (H5Tequal(H5T_NATIVE_INT, TypeID))
255 0 : return GDT_Int32;
256 144 : else if (H5Tequal(H5T_NATIVE_UINT, TypeID))
257 0 : return GDT_UInt32;
258 144 : else if (H5Tequal(H5T_NATIVE_LONG, TypeID))
259 : {
260 : #if SIZEOF_UNSIGNED_LONG == 4
261 : return GDT_Int32;
262 : #else
263 0 : return GDT_Unknown;
264 : #endif
265 : }
266 144 : else if (H5Tequal(H5T_NATIVE_ULONG, TypeID))
267 : {
268 : #if SIZEOF_UNSIGNED_LONG == 4
269 : return GDT_UInt32;
270 : #else
271 0 : return GDT_Unknown;
272 : #endif
273 : }
274 144 : else if (H5Tequal(H5T_NATIVE_FLOAT, TypeID))
275 144 : return GDT_Float32;
276 0 : else if (H5Tequal(H5T_NATIVE_DOUBLE, TypeID))
277 0 : return GDT_Float64;
278 : #ifdef notdef
279 : else if (H5Tequal(H5T_NATIVE_LLONG, TypeID))
280 : return GDT_Unknown;
281 : else if (H5Tequal(H5T_NATIVE_ULLONG, TypeID))
282 : return GDT_Unknown;
283 : #endif
284 :
285 0 : return GDT_Unknown;
286 : }
287 :
288 : /************************************************************************/
289 : /* GH5_CreateAttribute() */
290 : /************************************************************************/
291 :
292 114 : bool GH5_CreateAttribute(hid_t loc_id, const char *pszAttrName, hid_t TypeID,
293 : unsigned nMaxLen)
294 : {
295 : #ifdef notdef_write_variable_length_string
296 : if (TypeID == H5T_C_S1)
297 : {
298 : hsize_t dims[1] = {1};
299 : hid_t dataspace = H5Screate_simple(1, dims, nullptr);
300 : hid_t type = H5Tcopy(TypeID);
301 : H5Tset_size(type, H5T_VARIABLE);
302 : hid_t att =
303 : H5Acreate(loc_id, pszAttrName, type, dataspace, H5P_DEFAULT);
304 : H5Tclose(type);
305 : H5Aclose(att);
306 : H5Sclose(dataspace);
307 : return true;
308 : }
309 : #endif
310 :
311 114 : hid_t hDataSpace = H5Screate(H5S_SCALAR);
312 114 : if (hDataSpace < 0)
313 0 : return false;
314 :
315 114 : hid_t hDataType = H5Tcopy(TypeID);
316 114 : if (hDataType < 0)
317 : {
318 0 : H5Sclose(hDataSpace);
319 0 : return false;
320 : }
321 :
322 114 : if (TypeID == H5T_C_S1)
323 : {
324 20 : if (H5Tset_size(hDataType, nMaxLen) < 0)
325 : {
326 0 : H5Tclose(hDataType);
327 0 : H5Sclose(hDataSpace);
328 0 : return false;
329 : }
330 : }
331 :
332 : hid_t hAttr =
333 114 : H5Acreate(loc_id, pszAttrName, hDataType, hDataSpace, H5P_DEFAULT);
334 114 : if (hAttr < 0)
335 : {
336 0 : H5Sclose(hDataSpace);
337 0 : H5Tclose(hDataType);
338 0 : return false;
339 : }
340 :
341 114 : H5Aclose(hAttr);
342 114 : H5Sclose(hDataSpace);
343 114 : H5Tclose(hDataType);
344 :
345 114 : return true;
346 : }
347 :
348 : /************************************************************************/
349 : /* GH5_WriteAttribute() */
350 : /************************************************************************/
351 :
352 20 : bool GH5_WriteAttribute(hid_t loc_id, const char *pszAttrName,
353 : const char *pszValue)
354 : {
355 :
356 20 : hid_t hAttr = H5Aopen_name(loc_id, pszAttrName);
357 20 : if (hAttr < 0)
358 0 : return false;
359 :
360 20 : hid_t hDataType = H5Aget_type(hAttr);
361 20 : if (hDataType < 0)
362 : {
363 0 : H5Aclose(hAttr);
364 0 : return false;
365 : }
366 :
367 20 : hid_t hAttrNativeType = H5Tget_native_type(hDataType, H5T_DIR_DEFAULT);
368 20 : bool bSuccess = false;
369 20 : if (H5Tget_class(hAttrNativeType) == H5T_STRING)
370 : {
371 : #ifdef notdef_write_variable_length_string
372 : bSuccess = H5Awrite(hAttr, hDataType, &pszValue) >= 0;
373 : #else
374 20 : bSuccess = H5Awrite(hAttr, hDataType, pszValue) >= 0;
375 : #endif
376 : }
377 : else
378 : {
379 0 : CPLError(CE_Failure, CPLE_AppDefined,
380 : "Attribute %s is not of type string", pszAttrName);
381 : }
382 :
383 20 : H5Tclose(hAttrNativeType);
384 20 : H5Tclose(hDataType);
385 20 : H5Aclose(hAttr);
386 :
387 20 : return bSuccess;
388 : }
389 :
390 : /************************************************************************/
391 : /* GH5_WriteAttribute() */
392 : /************************************************************************/
393 :
394 74 : bool GH5_WriteAttribute(hid_t loc_id, const char *pszAttrName, double dfValue)
395 : {
396 :
397 74 : hid_t hAttr = H5Aopen_name(loc_id, pszAttrName);
398 74 : if (hAttr < 0)
399 0 : return false;
400 :
401 74 : hid_t hDataType = H5Aget_type(hAttr);
402 74 : if (hDataType < 0)
403 : {
404 0 : H5Aclose(hAttr);
405 0 : return false;
406 : }
407 :
408 74 : hid_t hAttrNativeType = H5Tget_native_type(hDataType, H5T_DIR_DEFAULT);
409 74 : bool bSuccess = false;
410 74 : if (H5Tequal(hAttrNativeType, H5T_NATIVE_FLOAT))
411 : {
412 74 : float fVal = static_cast<float>(dfValue);
413 74 : bSuccess = H5Awrite(hAttr, hAttrNativeType, &fVal) >= 0;
414 : }
415 0 : else if (H5Tequal(hAttrNativeType, H5T_NATIVE_DOUBLE))
416 : {
417 0 : bSuccess = H5Awrite(hAttr, hAttrNativeType, &dfValue) >= 0;
418 : }
419 : else
420 : {
421 0 : CPLError(CE_Failure, CPLE_AppDefined,
422 : "Attribute %s is not of type float or double", pszAttrName);
423 : }
424 :
425 74 : H5Tclose(hAttrNativeType);
426 74 : H5Aclose(hAttr);
427 74 : H5Tclose(hDataType);
428 :
429 74 : return bSuccess;
430 : }
431 :
432 : /************************************************************************/
433 : /* GH5_WriteAttribute() */
434 : /************************************************************************/
435 :
436 20 : bool GH5_WriteAttribute(hid_t loc_id, const char *pszAttrName, unsigned nValue)
437 : {
438 :
439 20 : hid_t hAttr = H5Aopen_name(loc_id, pszAttrName);
440 20 : if (hAttr < 0)
441 0 : return false;
442 :
443 20 : hid_t hDataType = H5Aget_type(hAttr);
444 20 : if (hDataType < 0)
445 : {
446 0 : H5Aclose(hAttr);
447 0 : return false;
448 : }
449 :
450 20 : hid_t hAttrNativeType = H5Tget_native_type(hDataType, H5T_DIR_DEFAULT);
451 20 : bool bSuccess = false;
452 40 : if (H5Tequal(hAttrNativeType, H5T_NATIVE_INT) ||
453 20 : H5Tequal(hAttrNativeType, H5T_NATIVE_UINT))
454 : {
455 20 : bSuccess = H5Awrite(hAttr, hAttrNativeType, &nValue) >= 0;
456 : }
457 : else
458 : {
459 0 : CPLError(CE_Failure, CPLE_AppDefined,
460 : "Attribute %s is not of type int/uint", pszAttrName);
461 : }
462 :
463 20 : H5Tclose(hAttrNativeType);
464 20 : H5Aclose(hAttr);
465 20 : H5Tclose(hDataType);
466 :
467 20 : return bSuccess;
468 : }
|