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