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