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