1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15 
16 #include "H5DataFactory.hxx"
17 
18 namespace org_modules_hdf5
19 {
20 
getData(H5Object & parent,const hid_t obj,H5Dataspace * space,hsize_t * selectdims,const bool isAttribute)21 H5Data & H5DataFactory::getData(H5Object & parent, const hid_t obj, H5Dataspace * space, hsize_t * selectdims, const bool isAttribute)
22 {
23     hsize_t ndims;
24     hsize_t * dims = 0;
25     hsize_t totalSize;
26     hsize_t dataSize;
27     void * data = 0;
28     const hid_t spaceId = space ? space->getH5Id() : -1;
29     const hid_t type = isAttribute ? H5Aget_type(obj) : H5Dget_type(obj);
30     const hid_t nativeType = H5Tget_native_type(type, H5T_DIR_DEFAULT);
31     if (type < 0)
32     {
33         throw H5Exception(__LINE__, __FILE__, _("Cannot get the data type"));
34     }
35 
36     try
37     {
38         getNativeData(obj, spaceId, selectdims, type, &totalSize, &dataSize, &ndims, &dims, &data, isAttribute);
39         H5Data & ret = getObjectData(parent, totalSize, dataSize, nativeType, ndims, dims, data, 0, 0, true);
40         H5Tclose(type);
41         H5Tclose(nativeType);
42 
43         return ret;
44     }
45     catch (const H5Exception & /*e*/)
46     {
47         H5Tclose(type);
48         H5Tclose(nativeType);
49         if (dims)
50         {
51             delete[] dims;
52         }
53 
54         if (data)
55         {
56             delete[] static_cast<char *>(data);
57         }
58         throw;
59     }
60 }
61 
getObjectData(H5Object & parent,const hsize_t totalSize,const hsize_t dataSize,const hid_t type,const hsize_t ndims,const hsize_t * dims,void * data,const hsize_t stride,const size_t offset,const bool dataOwner)62 H5Data & H5DataFactory::getObjectData(H5Object & parent, const hsize_t totalSize, const hsize_t dataSize, const hid_t type, const hsize_t ndims, const hsize_t * dims, void * data, const hsize_t stride, const size_t offset, const bool dataOwner)
63 {
64     switch (H5Tget_class(type))
65     {
66         case H5T_INTEGER:
67             if (H5Tequal(type, H5T_NATIVE_SCHAR))
68             {
69                 return *new H5CharData(parent, totalSize, dataSize, ndims, dims, (char *)data, stride, offset, dataOwner);
70             }
71             else if (H5Tequal(type, H5T_NATIVE_UCHAR))
72             {
73                 return *new H5UnsignedCharData(parent, totalSize, dataSize, ndims, dims, (unsigned char *)data, stride, offset, dataOwner);
74             }
75             else if (H5Tequal(type, H5T_NATIVE_SHORT))
76             {
77                 return *new H5BasicData<short>(parent, totalSize, dataSize, ndims, dims, (short *)data, stride, offset, dataOwner);
78             }
79             else if (H5Tequal(type, H5T_NATIVE_USHORT))
80             {
81                 return *new H5BasicData<unsigned short>(parent, totalSize, dataSize, ndims, dims, (unsigned short *)data, stride, offset, dataOwner);
82             }
83             else if (H5Tequal(type, H5T_NATIVE_INT))
84             {
85                 return *new H5BasicData<int>(parent, totalSize, dataSize, ndims, dims, (int *)data, stride, offset, dataOwner);
86             }
87             else if (H5Tequal(type, H5T_NATIVE_UINT))
88             {
89                 return *new H5BasicData<unsigned int>(parent, totalSize, dataSize, ndims, dims, (unsigned int *)data, stride, offset, dataOwner);
90             }
91 
92 #ifdef __SCILAB_INT64__
93 
94             else if (H5Tequal(type, H5T_NATIVE_LLONG))
95             {
96                 return *new H5BasicData<long long>(parent, totalSize, dataSize, ndims, dims, (long long *)data, stride, offset, dataOwner);
97             }
98             else if (H5Tequal(type, H5T_NATIVE_ULLONG))
99             {
100                 return *new H5BasicData<unsigned long long>(parent, totalSize, dataSize, ndims, dims, (unsigned long long *)data, stride, offset, dataOwner);
101             }
102 #else
103 
104             else if (H5Tequal(type, H5T_NATIVE_LONG))
105             {
106                 return *new H5TransformedData<long long, int>(parent, totalSize, dataSize, ndims, dims, (long long *)data, stride, offset, dataOwner);
107             }
108             else if (H5Tequal(type, H5T_NATIVE_ULONG))
109             {
110                 return *new H5TransformedData<unsigned long long, unsigned int>(parent, totalSize, dataSize, ndims, dims, (unsigned long long *)data, stride, offset, dataOwner);
111             }
112 
113 #endif // __SCILAB_INT64__
114 
115             else
116             {
117                 throw H5Exception(__LINE__, __FILE__, _("Unknown integer datatype."));
118             }
119             break;
120         case H5T_FLOAT:
121             if (H5Tequal(type, H5T_NATIVE_FLOAT))
122             {
123                 return *new H5TransformedData<float, double>(parent, totalSize, dataSize, ndims, dims, (float *)data, stride, offset, dataOwner);
124             }
125             else if (H5Tequal(type, H5T_NATIVE_DOUBLE))
126             {
127                 return *new H5BasicData<double>(parent, totalSize, dataSize, ndims, dims, (double *)data, stride, offset, dataOwner);
128             }
129             else
130             {
131                 throw H5Exception(__LINE__, __FILE__, _("Unknown floating-point datatype."));
132             }
133             break;
134         case H5T_TIME:
135             return *new H5TimeData(parent, totalSize, dataSize, ndims, dims, (char *)data, stride, offset, dataOwner);
136         case H5T_STRING:
137             if (H5Tis_variable_str(type))
138             {
139                 return *new H5StringData(parent, totalSize, dataSize, ndims, dims, (char **)data, stride, offset, dataOwner);
140             }
141             else
142             {
143                 return *new H5StringData(parent, totalSize, dataSize, ndims, dims, (char *)data, stride, offset, dataOwner);
144             }
145         case H5T_BITFIELD:
146             switch (dataSize)
147             {
148                 case 1:
149                     return *new H5Bitfield1Data(parent, totalSize, dataSize, ndims, dims, static_cast<unsigned char *>(data), stride, offset, dataOwner);
150                 case 2:
151                     return *new H5Bitfield2Data(parent, totalSize, dataSize, ndims, dims, static_cast<unsigned short *>(data), stride, offset, dataOwner);
152                 case 4:
153                     return *new H5Bitfield4Data(parent, totalSize, dataSize, ndims, dims, static_cast<unsigned int *>(data), stride, offset, dataOwner);
154                 case 8:
155                 //return *new H5BitfieldData<unsigned long long>(parent, totalSize, dataSize, ndims, dims, static_cast<unsigned long long *>(data), stride, offset, false);
156                 default:
157                     throw H5Exception(__LINE__, __FILE__, _("Bitfield is too big"));
158             }
159 
160         case H5T_OPAQUE:
161             return *new H5OpaqueData(parent, totalSize, dataSize, ndims, dims, (unsigned char *)data, stride, offset, dataOwner);
162         case H5T_COMPOUND:
163             return *new H5CompoundData(parent, totalSize, dataSize, ndims, dims, (char *)data, H5Tcopy(type), stride, offset, dataOwner);
164         case H5T_REFERENCE:
165             // TODO: virer le false
166             return *new H5ReferenceData(parent, H5Tequal(type, H5T_STD_REF_DSETREG) ? H5R_DATASET_REGION : H5R_OBJECT, totalSize, dataSize, ndims, dims, (char *)data, stride, offset, dataOwner);
167         case H5T_ENUM:
168         {
169             int nmembers = H5Tget_nmembers(type);
170             std::string * names = nmembers > 0 ? new std::string[nmembers] : 0;
171 
172             for (int i = 0; i < nmembers; i++)
173             {
174                 char * mname = H5Tget_member_name(type, i);
175                 names[i] = std::string(mname);
176                 //HDF5 version > 1.8.13
177                 //H5free_memory(mnale);
178 
179                 //freed memory allocated by H5Tget_member_name trigger a segfault on Windows.
180                 //http://lists.hdfgroup.org/pipermail/hdf-forum_lists.hdfgroup.org/2014-September/008061.html
181                 //little memory leaks are better then crashs :x
182 #ifndef _MSC_VER
183                 free(mname);
184 #endif
185             }
186 
187             if (H5Tget_sign(type) == H5T_SGN_NONE)
188             {
189                 switch (dataSize)
190                 {
191                     case 1:
192                         return *new H5EnumData<unsigned char>(parent, totalSize, dataSize, ndims, dims, (unsigned char *)data, type, H5T_NATIVE_UCHAR, nmembers, names, stride, offset, dataOwner);
193                     case 2:
194                         return *new H5EnumData<unsigned short>(parent, totalSize, dataSize, ndims, dims, (unsigned short *)data, type, H5T_NATIVE_USHORT, nmembers, names, stride, offset, dataOwner);
195                     case 4:
196                         return *new H5EnumData<unsigned int>(parent, totalSize, dataSize, ndims, dims, (unsigned int *)data, type, H5T_NATIVE_UINT, nmembers, names, stride, offset, dataOwner);
197 #ifdef __SCILAB_INT64__
198                     case 8:
199                         return *new H5EnumData<unsigned long long>(parent, totalSize, dataSize, ndims, dims, (unsigned long long *)data, type, H5T_NATIVE_ULLONG, nmembers, names, stride, offset, dataOwner);
200 #endif
201                 }
202             }
203             else
204             {
205                 switch (dataSize)
206                 {
207                     case 1:
208                         return *new H5EnumData<char>(parent, totalSize, dataSize, ndims, dims, (char *)data, type, H5T_NATIVE_CHAR, nmembers, names, stride, offset, dataOwner);
209                     case 2:
210                         return *new H5EnumData<short>(parent, totalSize, dataSize, ndims, dims, (short *)data, type, H5T_NATIVE_SHORT, nmembers, names, stride, offset, dataOwner);
211                     case 4:
212                         return *new H5EnumData<int>(parent, totalSize, dataSize, ndims, dims, (int *)data, type, H5T_NATIVE_INT, nmembers, names, stride, offset, dataOwner);
213 #ifdef __SCILAB_INT64__
214                     case 8:
215                         return *new H5EnumData<long long>(parent, totalSize, dataSize, ndims, dims, (long long *)data, type, H5T_NATIVE_LLONG, nmembers, names, stride, offset, dataOwner);
216 #endif
217                 }
218             }
219 
220             return *new H5EnumData<char>(parent, totalSize, dataSize, ndims, dims, (char *)data, type, H5T_NATIVE_CHAR, nmembers, names, stride, offset, dataOwner);
221         }
222         case H5T_VLEN:
223             return *new H5VlenData(parent, totalSize, dataSize, ndims, dims, static_cast<char *>(data), type, stride, offset, dataOwner);
224         case H5T_ARRAY:
225             return *new H5ArrayData(parent, totalSize, dataSize, ndims, dims, static_cast<char *>(data), type, stride, offset, dataOwner);
226         default:
227             throw H5Exception(__LINE__, __FILE__, _("Cannot get data from an unknown data type."));
228     }
229 
230     throw H5Exception(__LINE__, __FILE__, _("Cannot get data from an unknown data type."));
231 }
232 
getNativeData(const hid_t obj,const hid_t space,hsize_t * selectdims,const hid_t type,hsize_t * totalSize,hsize_t * dataSize,hsize_t * ndims,hsize_t ** dims,void ** data,const bool isAttribute)233 void H5DataFactory::getNativeData(const hid_t obj, const hid_t space, hsize_t * selectdims, const hid_t type, hsize_t * totalSize, hsize_t * dataSize, hsize_t * ndims, hsize_t ** dims, void ** data, const bool isAttribute)
234 {
235     hid_t nativeType = H5Tget_native_type(type, H5T_DIR_DEFAULT);
236     hid_t _space = space < 0 ? (isAttribute ? H5Aget_space(obj) : H5Dget_space(obj)) : space;
237     hsize_t size = H5Tget_size(nativeType);
238     H5S_sel_type sel;
239     hid_t targetspace;
240     herr_t err;
241     hsize_t * blockbuf = 0;
242     bool hyperslab = false;
243     bool isString = false;
244 
245     *totalSize = 1;
246     if (H5Tget_class(nativeType) == H5T_STRING && !H5Tis_variable_str(nativeType))
247     {
248         // We have a C-string so it is null terminated
249         size++;
250         isString = true;
251     }
252 
253     *dataSize = size;
254     *ndims = H5Sget_simple_extent_dims(_space, 0, 0);
255     *dims = new hsize_t[*ndims];
256 
257     if (isAttribute)
258     {
259         H5Sget_simple_extent_dims(_space, *dims, 0);
260         for (unsigned int i = 0; i < *ndims; i++)
261         {
262             *totalSize *= (*dims)[i];
263         }
264     }
265     else
266     {
267         sel = H5Sget_select_type(_space);
268         switch (sel)
269         {
270             case H5S_SEL_NONE:
271             case H5S_SEL_ALL:
272                 H5Sget_simple_extent_dims(_space, *dims, 0);
273                 for (unsigned int i = 0; i < *ndims; i++)
274                 {
275                     *totalSize *= (*dims)[i];
276                 }
277                 break;
278             case H5S_SEL_POINTS:
279                 break;
280             case H5S_SEL_HYPERSLABS:
281                 for (unsigned int i = 0; i < *ndims; i++)
282                 {
283                     (*dims)[i] = selectdims[i];
284                     *totalSize *= (*dims)[i];
285                 }
286                 hyperslab = true;
287                 break;
288             default:
289                 break;
290         }
291     }
292 
293     size *= *totalSize;
294 
295     if ((hsize_t)((size_t)size) != size)
296     {
297         H5Tclose(nativeType);
298         if (space < 0)
299         {
300             H5Sclose(_space);
301         }
302         delete[] *dims;
303         throw H5Exception(__LINE__, __FILE__, _("Memory to allocate is too big"));
304     }
305 
306     try
307     {
308         if (isString)
309         {
310             *data = static_cast<void *>(new char[(size_t)size]());
311         }
312         else
313         {
314             // No need to initialize the array
315             *data = static_cast<void *>(new char[(size_t)size]);
316         }
317     }
318     catch (const std::bad_alloc & /*e*/)
319     {
320         H5Tclose(nativeType);
321         if (space < 0)
322         {
323             H5Sclose(_space);
324         }
325         *data = 0;
326         delete[] *dims;
327         *dims = 0;
328         throw H5Exception(__LINE__, __FILE__, _("Cannot allocate memory to get the data"));
329     }
330 
331     if (!*data)
332     {
333         H5Tclose(nativeType);
334         if (space < 0)
335         {
336             H5Sclose(_space);
337         }
338         delete[] *dims;
339         *dims = 0;
340         throw H5Exception(__LINE__, __FILE__, _("Cannot allocate memory to get the data"));
341     }
342 
343     if (hyperslab)
344     {
345         targetspace =  H5Screate_simple((int) * ndims, *dims, 0);
346         err = H5Dread(obj, nativeType, targetspace, _space, H5P_DEFAULT, *data);
347         H5Sclose(targetspace);
348     }
349     else
350     {
351         if (isAttribute)
352         {
353             err = H5Aread(obj, nativeType, *data);
354         }
355         else
356         {
357             err = H5Dread(obj, nativeType, H5S_ALL, H5S_ALL, H5P_DEFAULT, *data);
358         }
359     }
360 
361     if (err < 0)
362     {
363         H5Tclose(nativeType);
364         if (space < 0)
365         {
366             H5Sclose(_space);
367         }
368         delete[] static_cast<char *>(*data);
369         *data = 0;
370         delete[] *dims;
371         *dims = 0;
372         throw H5Exception(__LINE__, __FILE__, _("Cannot retrieve the data from the attribute"));
373     }
374 
375     H5Tclose(nativeType);
376     if (space < 0)
377     {
378         H5Sclose(_space);
379     }
380 }
381 }
382