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 : #include <limits>
17 :
18 : /************************************************************************/
19 : /* GH5_FetchAttribute(CPLString) */
20 : /************************************************************************/
21 :
22 85 : bool GH5_FetchAttribute(hid_t loc_id, const char *pszAttrName,
23 : CPLString &osResult, bool bReportError)
24 :
25 : {
26 85 : if (!bReportError && H5Aexists(loc_id, pszAttrName) <= 0)
27 : {
28 0 : return false;
29 : }
30 :
31 85 : hid_t hAttr = H5Aopen_name(loc_id, pszAttrName);
32 :
33 85 : osResult.clear();
34 :
35 85 : if (hAttr < 0)
36 : {
37 0 : if (bReportError)
38 0 : CPLError(CE_Failure, CPLE_AppDefined,
39 : "Attempt to read attribute %s failed, not found.",
40 : pszAttrName);
41 0 : return false;
42 : }
43 :
44 85 : const hid_t hAttrSpace = H5Aget_space(hAttr);
45 85 : hsize_t anSize[H5S_MAX_RANK] = {};
46 : const unsigned int nAttrDims =
47 85 : H5Sget_simple_extent_dims(hAttrSpace, anSize, nullptr);
48 85 : if (nAttrDims != 0 && !(nAttrDims == 1 && anSize[0] == 1))
49 : {
50 0 : H5Sclose(hAttrSpace);
51 0 : H5Aclose(hAttr);
52 0 : return false;
53 : }
54 :
55 85 : hid_t hAttrTypeID = H5Aget_type(hAttr);
56 85 : hid_t hAttrNativeType = H5Tget_native_type(hAttrTypeID, H5T_DIR_DEFAULT);
57 :
58 85 : bool retVal = false;
59 85 : if (H5Tget_class(hAttrNativeType) == H5T_STRING)
60 : {
61 85 : if (H5Tis_variable_str(hAttrNativeType))
62 : {
63 14 : char *aszBuffer[1] = {nullptr};
64 14 : H5Aread(hAttr, hAttrNativeType, aszBuffer);
65 :
66 14 : if (aszBuffer[0])
67 14 : osResult = aszBuffer[0];
68 :
69 14 : H5Dvlen_reclaim(hAttrNativeType, hAttrSpace, H5P_DEFAULT,
70 : aszBuffer);
71 : }
72 : else
73 : {
74 71 : const size_t nAttrSize = H5Tget_size(hAttrTypeID);
75 71 : char *pachBuffer = static_cast<char *>(CPLCalloc(nAttrSize + 1, 1));
76 71 : H5Aread(hAttr, hAttrNativeType, pachBuffer);
77 :
78 71 : osResult = pachBuffer;
79 71 : CPLFree(pachBuffer);
80 : }
81 :
82 85 : retVal = true;
83 : }
84 : else
85 : {
86 0 : if (bReportError)
87 0 : CPLError(
88 : CE_Failure, CPLE_AppDefined,
89 : "Attribute %s of unsupported type for conversion to string.",
90 : pszAttrName);
91 :
92 0 : retVal = false;
93 : }
94 :
95 85 : H5Sclose(hAttrSpace);
96 85 : H5Tclose(hAttrNativeType);
97 85 : H5Tclose(hAttrTypeID);
98 85 : H5Aclose(hAttr);
99 85 : return retVal;
100 : }
101 :
102 : /************************************************************************/
103 : /* GH5_FetchAttribute(double) */
104 : /************************************************************************/
105 :
106 1061 : bool GH5_FetchAttribute(hid_t loc_id, const char *pszAttrName, double &dfResult,
107 : bool bReportError)
108 :
109 : {
110 1061 : if (!bReportError && H5Aexists(loc_id, pszAttrName) <= 0)
111 : {
112 444 : return false;
113 : }
114 :
115 617 : const hid_t hAttr = H5Aopen_name(loc_id, pszAttrName);
116 :
117 617 : dfResult = 0.0;
118 617 : if (hAttr < 0)
119 : {
120 0 : if (bReportError)
121 0 : CPLError(CE_Failure, CPLE_AppDefined,
122 : "Attempt to read attribute %s failed, not found.",
123 : pszAttrName);
124 0 : return false;
125 : }
126 :
127 617 : hid_t hAttrTypeID = H5Aget_type(hAttr);
128 617 : hid_t hAttrNativeType = H5Tget_native_type(hAttrTypeID, H5T_DIR_DEFAULT);
129 :
130 : // Confirm that we have a single element value.
131 617 : hid_t hAttrSpace = H5Aget_space(hAttr);
132 617 : hsize_t anSize[H5S_MAX_RANK] = {};
133 617 : int nAttrDims = H5Sget_simple_extent_dims(hAttrSpace, anSize, nullptr);
134 :
135 617 : int i, nAttrElements = 1;
136 :
137 628 : for (i = 0; i < nAttrDims; i++)
138 : {
139 11 : nAttrElements *= static_cast<int>(anSize[i]);
140 : }
141 :
142 617 : if (nAttrElements != 1)
143 : {
144 0 : if (bReportError)
145 0 : CPLError(CE_Failure, CPLE_AppDefined,
146 : "Attempt to read attribute %s failed, count=%d, not 1.",
147 : pszAttrName, nAttrElements);
148 :
149 0 : H5Sclose(hAttrSpace);
150 0 : H5Tclose(hAttrNativeType);
151 0 : H5Tclose(hAttrTypeID);
152 0 : H5Aclose(hAttr);
153 0 : return false;
154 : }
155 :
156 : // Read the value.
157 617 : void *buf = CPLMalloc(H5Tget_size(hAttrNativeType));
158 617 : H5Aread(hAttr, hAttrNativeType, buf);
159 :
160 : // Translate to double.
161 617 : if (H5Tequal(H5T_NATIVE_CHAR, hAttrNativeType))
162 0 : dfResult = *(static_cast<char *>(buf));
163 617 : else if (H5Tequal(H5T_NATIVE_SCHAR, hAttrNativeType))
164 0 : dfResult = *(static_cast<signed char *>(buf));
165 617 : else if (H5Tequal(H5T_NATIVE_UCHAR, hAttrNativeType))
166 1 : dfResult = *(static_cast<unsigned char *>(buf));
167 616 : else if (H5Tequal(H5T_NATIVE_SHORT, hAttrNativeType))
168 0 : dfResult = *(static_cast<short *>(buf));
169 616 : else if (H5Tequal(H5T_NATIVE_USHORT, hAttrNativeType))
170 2 : dfResult = *(static_cast<unsigned short *>(buf));
171 614 : else if (H5Tequal(H5T_NATIVE_INT, hAttrNativeType))
172 2 : dfResult = *(static_cast<int *>(buf));
173 612 : else if (H5Tequal(H5T_NATIVE_UINT, hAttrNativeType))
174 5 : dfResult = *(static_cast<unsigned int *>(buf));
175 607 : else if (H5Tequal(H5T_NATIVE_INT64, hAttrNativeType))
176 : {
177 1 : const auto nVal = *static_cast<int64_t *>(buf);
178 1 : dfResult = static_cast<double>(nVal);
179 1 : if (nVal != static_cast<int64_t>(dfResult))
180 : {
181 0 : CPLDebug("HDF5",
182 : "Loss of accuracy when reading attribute %s. "
183 : "Value " CPL_FRMT_GIB " will be read as %.17g",
184 : pszAttrName, static_cast<GIntBig>(nVal), dfResult);
185 : }
186 : }
187 606 : else if (H5Tequal(H5T_NATIVE_UINT64, hAttrNativeType))
188 : {
189 1 : const auto nVal = *static_cast<uint64_t *>(buf);
190 1 : dfResult = static_cast<double>(nVal);
191 1 : if (nVal != static_cast<uint64_t>(dfResult))
192 : {
193 0 : CPLDebug("HDF5",
194 : "Loss of accuracy when reading attribute %s. "
195 : "Value " CPL_FRMT_GUIB " will be read as %.17g",
196 : pszAttrName, static_cast<GUIntBig>(nVal), dfResult);
197 : }
198 : }
199 : #ifdef HDF5_HAVE_FLOAT16
200 : else if (H5Tequal(H5T_NATIVE_FLOAT16, hAttrNativeType))
201 : {
202 : const uint16_t nVal16 = *(static_cast<uint16_t *>(buf));
203 : const uint32_t nVal32 = CPLHalfToFloat(nVal16);
204 : float fVal;
205 : memcpy(&fVal, &nVal32, sizeof(fVal));
206 : dfResult = fVal;
207 : }
208 : #endif
209 605 : else if (H5Tequal(H5T_NATIVE_FLOAT, hAttrNativeType))
210 551 : dfResult = *(static_cast<float *>(buf));
211 54 : else if (H5Tequal(H5T_NATIVE_DOUBLE, hAttrNativeType))
212 54 : dfResult = *(static_cast<double *>(buf));
213 : else
214 : {
215 0 : if (bReportError)
216 0 : CPLError(
217 : CE_Failure, CPLE_AppDefined,
218 : "Attribute %s of unsupported type for conversion to double.",
219 : pszAttrName);
220 0 : CPLFree(buf);
221 :
222 0 : H5Sclose(hAttrSpace);
223 0 : H5Tclose(hAttrNativeType);
224 0 : H5Tclose(hAttrTypeID);
225 0 : H5Aclose(hAttr);
226 :
227 0 : return false;
228 : }
229 :
230 617 : CPLFree(buf);
231 :
232 617 : H5Sclose(hAttrSpace);
233 617 : H5Tclose(hAttrNativeType);
234 617 : H5Tclose(hAttrTypeID);
235 617 : H5Aclose(hAttr);
236 617 : return true;
237 : }
238 :
239 : /************************************************************************/
240 : /* GH5_GetDataType() */
241 : /* */
242 : /* Transform HDF5 datatype to GDAL datatype */
243 : /************************************************************************/
244 145 : GDALDataType GH5_GetDataType(hid_t TypeID)
245 : {
246 145 : if (H5Tequal(H5T_NATIVE_CHAR, TypeID))
247 0 : return GDT_UInt8;
248 145 : else if (H5Tequal(H5T_NATIVE_SCHAR, TypeID))
249 0 : return GDT_Int8;
250 145 : else if (H5Tequal(H5T_NATIVE_UCHAR, TypeID))
251 0 : return GDT_UInt8;
252 145 : else if (H5Tequal(H5T_NATIVE_SHORT, TypeID))
253 0 : return GDT_Int16;
254 145 : else if (H5Tequal(H5T_NATIVE_USHORT, TypeID))
255 0 : return GDT_UInt16;
256 145 : else if (H5Tequal(H5T_NATIVE_INT, TypeID))
257 0 : return GDT_Int32;
258 145 : else if (H5Tequal(H5T_NATIVE_UINT, TypeID))
259 0 : return GDT_UInt32;
260 145 : else if (H5Tequal(H5T_NATIVE_LONG, TypeID))
261 : {
262 : #if SIZEOF_UNSIGNED_LONG == 4
263 : return GDT_Int32;
264 : #else
265 0 : return GDT_Unknown;
266 : #endif
267 : }
268 145 : else if (H5Tequal(H5T_NATIVE_ULONG, TypeID))
269 : {
270 : #if SIZEOF_UNSIGNED_LONG == 4
271 : return GDT_UInt32;
272 : #else
273 0 : return GDT_Unknown;
274 : #endif
275 : }
276 145 : else if (H5Tequal(H5T_NATIVE_FLOAT, TypeID))
277 145 : return GDT_Float32;
278 0 : else if (H5Tequal(H5T_NATIVE_DOUBLE, TypeID))
279 0 : return GDT_Float64;
280 : #ifdef notdef
281 : else if (H5Tequal(H5T_NATIVE_LLONG, TypeID))
282 : return GDT_Unknown;
283 : else if (H5Tequal(H5T_NATIVE_ULLONG, TypeID))
284 : return GDT_Unknown;
285 : #endif
286 :
287 0 : return GDT_Unknown;
288 : }
289 :
290 : /************************************************************************/
291 : /* GH5_CreateAttribute() */
292 : /************************************************************************/
293 :
294 3733 : bool GH5_CreateAttribute(hid_t loc_id, const char *pszAttrName, hid_t TypeID,
295 : unsigned nMaxLen)
296 : {
297 3733 : hid_t hDataSpace = H5Screate(H5S_SCALAR);
298 3733 : if (hDataSpace < 0)
299 0 : return false;
300 :
301 3733 : hid_t hDataType = H5Tcopy(TypeID);
302 3733 : if (hDataType < 0)
303 : {
304 0 : H5Sclose(hDataSpace);
305 0 : return false;
306 : }
307 :
308 3733 : if (TypeID == H5T_C_S1)
309 : {
310 683 : if (nMaxLen == VARIABLE_LENGTH)
311 : {
312 663 : H5Tset_size(hDataType, H5T_VARIABLE);
313 663 : H5Tset_strpad(hDataType, H5T_STR_NULLTERM);
314 : }
315 20 : else if (H5Tset_size(hDataType, nMaxLen) < 0)
316 : {
317 0 : H5Tclose(hDataType);
318 0 : H5Sclose(hDataSpace);
319 0 : return false;
320 : }
321 : }
322 :
323 : hid_t hAttr =
324 3733 : H5Acreate(loc_id, pszAttrName, hDataType, hDataSpace, H5P_DEFAULT);
325 3733 : if (hAttr < 0)
326 : {
327 0 : H5Sclose(hDataSpace);
328 0 : H5Tclose(hDataType);
329 0 : return false;
330 : }
331 :
332 3733 : H5Aclose(hAttr);
333 3733 : H5Sclose(hDataSpace);
334 3733 : H5Tclose(hDataType);
335 :
336 3733 : return true;
337 : }
338 :
339 : /************************************************************************/
340 : /* GH5_WriteAttribute() */
341 : /************************************************************************/
342 :
343 683 : bool GH5_WriteAttribute(hid_t loc_id, const char *pszAttrName,
344 : const char *pszValue)
345 : {
346 :
347 683 : hid_t hAttr = H5Aopen_name(loc_id, pszAttrName);
348 683 : if (hAttr < 0)
349 0 : return false;
350 :
351 683 : hid_t hDataType = H5Aget_type(hAttr);
352 683 : if (hDataType < 0)
353 : {
354 0 : H5Aclose(hAttr);
355 0 : return false;
356 : }
357 :
358 683 : hid_t hAttrNativeType = H5Tget_native_type(hDataType, H5T_DIR_DEFAULT);
359 683 : bool bSuccess = false;
360 683 : if (H5Tget_class(hAttrNativeType) == H5T_STRING)
361 : {
362 683 : if (H5Tis_variable_str(hAttrNativeType) > 0)
363 663 : bSuccess = H5Awrite(hAttr, hDataType, &pszValue) >= 0;
364 : else
365 20 : bSuccess = H5Awrite(hAttr, hDataType, pszValue) >= 0;
366 : }
367 : else
368 : {
369 0 : CPLError(CE_Failure, CPLE_AppDefined,
370 : "Attribute %s is not of type string", pszAttrName);
371 : }
372 :
373 683 : H5Tclose(hAttrNativeType);
374 683 : H5Tclose(hDataType);
375 683 : H5Aclose(hAttr);
376 :
377 683 : return bSuccess;
378 : }
379 :
380 : /************************************************************************/
381 : /* GH5_WriteAttribute() */
382 : /************************************************************************/
383 :
384 1623 : bool GH5_WriteAttribute(hid_t loc_id, const char *pszAttrName, double dfValue)
385 : {
386 :
387 1623 : hid_t hAttr = H5Aopen_name(loc_id, pszAttrName);
388 1623 : if (hAttr < 0)
389 0 : return false;
390 :
391 1623 : hid_t hDataType = H5Aget_type(hAttr);
392 1623 : if (hDataType < 0)
393 : {
394 0 : H5Aclose(hAttr);
395 0 : return false;
396 : }
397 :
398 1623 : hid_t hAttrNativeType = H5Tget_native_type(hDataType, H5T_DIR_DEFAULT);
399 1623 : bool bSuccess = false;
400 1623 : if (H5Tequal(hAttrNativeType, H5T_NATIVE_FLOAT))
401 : {
402 1087 : float fVal = static_cast<float>(dfValue);
403 1087 : bSuccess = H5Awrite(hAttr, hAttrNativeType, &fVal) >= 0;
404 : }
405 536 : else if (H5Tequal(hAttrNativeType, H5T_NATIVE_DOUBLE))
406 : {
407 536 : bSuccess = H5Awrite(hAttr, hAttrNativeType, &dfValue) >= 0;
408 : }
409 : else
410 : {
411 0 : CPLError(CE_Failure, CPLE_AppDefined,
412 : "Attribute %s is not of type float or double", pszAttrName);
413 : }
414 :
415 1623 : H5Tclose(hAttrNativeType);
416 1623 : H5Aclose(hAttr);
417 1623 : H5Tclose(hDataType);
418 :
419 1623 : return bSuccess;
420 : }
421 :
422 : /************************************************************************/
423 : /* GH5_WriteAttribute() */
424 : /************************************************************************/
425 :
426 1213 : bool GH5_WriteAttribute(hid_t loc_id, const char *pszAttrName, int nValue)
427 : {
428 :
429 1213 : hid_t hAttr = H5Aopen_name(loc_id, pszAttrName);
430 1213 : if (hAttr < 0)
431 0 : return false;
432 :
433 1213 : hid_t hDataType = H5Aget_type(hAttr);
434 1213 : if (hDataType < 0)
435 : {
436 0 : H5Aclose(hAttr);
437 0 : return false;
438 : }
439 :
440 1213 : hid_t hEnumType = -1;
441 1213 : if (H5Tget_class(hDataType) == H5T_ENUM)
442 : {
443 654 : hEnumType = hDataType;
444 654 : hDataType = H5Tget_super(hDataType);
445 : }
446 :
447 1213 : hid_t hAttrNativeType = H5Tget_native_type(hDataType, H5T_DIR_DEFAULT);
448 1213 : bool bSuccess = false;
449 1213 : if (hEnumType < 0 && H5Tequal(hAttrNativeType, H5T_NATIVE_INT))
450 : {
451 297 : bSuccess = H5Awrite(hAttr, hAttrNativeType, &nValue) >= 0;
452 : }
453 916 : else if (hEnumType < 0 && H5Tequal(hAttrNativeType, H5T_NATIVE_UINT))
454 : {
455 126 : if (nValue < 0)
456 : {
457 0 : CPLError(CE_Failure, CPLE_AppDefined,
458 : "Attribute %s has value %d which is negative but the type "
459 : "is uint",
460 : pszAttrName, nValue);
461 : }
462 : else
463 : {
464 126 : bSuccess = H5Awrite(hAttr, hAttrNativeType, &nValue) >= 0;
465 : }
466 : }
467 790 : else if (hEnumType < 0 && H5Tequal(hAttrNativeType, H5T_NATIVE_UINT8))
468 : {
469 232 : if (nValue < 0 ||
470 116 : nValue > static_cast<int>(std::numeric_limits<uint8_t>::max()))
471 : {
472 0 : CPLError(CE_Failure, CPLE_AppDefined,
473 : "Attribute %s has value %d which is not in the range of a "
474 : "uint8",
475 : pszAttrName, nValue);
476 : }
477 : else
478 : {
479 116 : uint8_t nUint8 = static_cast<uint8_t>(nValue);
480 116 : bSuccess = H5Awrite(hAttr, hAttrNativeType, &nUint8) >= 0;
481 : }
482 : }
483 674 : else if (hEnumType < 0 && H5Tequal(hAttrNativeType, H5T_NATIVE_UINT16))
484 : {
485 40 : if (nValue < 0 ||
486 20 : nValue >= static_cast<int>(std::numeric_limits<uint16_t>::max()))
487 : {
488 0 : CPLError(CE_Failure, CPLE_AppDefined,
489 : "Attribute %s has value %d which is not in the range of a "
490 : "uint16",
491 : pszAttrName, nValue);
492 : }
493 : else
494 : {
495 20 : uint16_t nUint16 = static_cast<uint16_t>(nValue);
496 20 : bSuccess = H5Awrite(hAttr, hAttrNativeType, &nUint16) >= 0;
497 : }
498 : }
499 654 : else if (hEnumType >= 0 && H5Tequal(hAttrNativeType, H5T_NATIVE_UINT8))
500 : {
501 654 : if (nValue < 0 || nValue > 255)
502 : {
503 0 : CPLError(CE_Failure, CPLE_AppDefined,
504 : "Attribute %s has value %d which is not in the range of a "
505 : "uint8",
506 : pszAttrName, nValue);
507 : }
508 : else
509 : {
510 654 : uint8_t nUint8 = static_cast<uint8_t>(nValue);
511 654 : bSuccess = H5Awrite(hAttr, hEnumType, &nUint8) >= 0;
512 : }
513 : }
514 : else
515 : {
516 0 : CPLError(CE_Failure, CPLE_AppDefined,
517 : "Attribute %s is not of type int/uint", pszAttrName);
518 : }
519 :
520 1213 : H5Tclose(hAttrNativeType);
521 1213 : H5Aclose(hAttr);
522 1213 : H5Tclose(hDataType);
523 1213 : if (hEnumType >= 0)
524 654 : H5Tclose(hEnumType);
525 :
526 1213 : return bSuccess;
527 : }
528 :
529 : /************************************************************************/
530 : /* GH5_WriteAttribute() */
531 : /************************************************************************/
532 :
533 247 : bool GH5_WriteAttribute(hid_t loc_id, const char *pszAttrName, unsigned nValue)
534 : {
535 :
536 247 : hid_t hAttr = H5Aopen_name(loc_id, pszAttrName);
537 247 : if (hAttr < 0)
538 0 : return false;
539 :
540 247 : hid_t hDataType = H5Aget_type(hAttr);
541 247 : if (hDataType < 0)
542 : {
543 0 : H5Aclose(hAttr);
544 0 : return false;
545 : }
546 :
547 247 : hid_t hEnumType = -1;
548 247 : if (H5Tget_class(hDataType) == H5T_ENUM)
549 : {
550 0 : hEnumType = hDataType;
551 0 : hDataType = H5Tget_super(hDataType);
552 : }
553 :
554 247 : hid_t hAttrNativeType = H5Tget_native_type(hDataType, H5T_DIR_DEFAULT);
555 247 : bool bSuccess = false;
556 247 : if (H5Tequal(hAttrNativeType, H5T_NATIVE_UINT))
557 : {
558 247 : bSuccess = H5Awrite(hAttr, hAttrNativeType, &nValue) >= 0;
559 : }
560 0 : else if (H5Tequal(hAttrNativeType, H5T_NATIVE_INT))
561 : {
562 0 : if (nValue > static_cast<unsigned>(INT_MAX))
563 : {
564 0 : CPLError(
565 : CE_Failure, CPLE_AppDefined,
566 : "Attribute %s has value %u which does not fit on a signed int",
567 : pszAttrName, nValue);
568 : }
569 : else
570 : {
571 0 : bSuccess = H5Awrite(hAttr, hAttrNativeType, &nValue) >= 0;
572 : }
573 : }
574 : else
575 : {
576 0 : CPLError(CE_Failure, CPLE_AppDefined,
577 : "Attribute %s is not of type int/uint", pszAttrName);
578 : }
579 :
580 247 : H5Tclose(hAttrNativeType);
581 247 : H5Aclose(hAttr);
582 247 : H5Tclose(hDataType);
583 247 : if (hEnumType >= 0)
584 0 : H5Tclose(hEnumType);
585 :
586 247 : return bSuccess;
587 : }
|