e63b6f07de7bce14890371e5e077ede36212a376
[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                 free(mname);
174             }
175
176             if (H5Tget_sign(type) == H5T_SGN_NONE)
177             {
178                 switch (dataSize)
179                 {
180                     case 1:
181                         return *new H5EnumData<unsigned char>(parent, totalSize, dataSize, ndims, dims, (unsigned char *)data, type, H5T_NATIVE_UCHAR, nmembers, names, stride, offset, dataOwner);
182                     case 2:
183                         return *new H5EnumData<unsigned short>(parent, totalSize, dataSize, ndims, dims, (unsigned short *)data, type, H5T_NATIVE_USHORT, nmembers, names, stride, offset, dataOwner);
184                     case 4:
185                         return *new H5EnumData<unsigned int>(parent, totalSize, dataSize, ndims, dims, (unsigned int *)data, type, H5T_NATIVE_UINT, nmembers, names, stride, offset, dataOwner);
186 #ifdef __SCILAB_INT64__
187                     case 8:
188                         return *new H5EnumData<unsigned long long>(parent, totalSize, dataSize, ndims, dims, (unsigned long long *)data, type, H5T_NATIVE_ULLONG, nmembers, names, stride, offset, dataOwner);
189 #endif
190                 }
191             }
192             else
193             {
194                 switch (dataSize)
195                 {
196                     case 1:
197                         return *new H5EnumData<char>(parent, totalSize, dataSize, ndims, dims, (char *)data, type, H5T_NATIVE_CHAR, nmembers, names, stride, offset, dataOwner);
198                     case 2:
199                         return *new H5EnumData<short>(parent, totalSize, dataSize, ndims, dims, (short *)data, type, H5T_NATIVE_SHORT, nmembers, names, stride, offset, dataOwner);
200                     case 4:
201                         return *new H5EnumData<int>(parent, totalSize, dataSize, ndims, dims, (int *)data, type, H5T_NATIVE_INT, nmembers, names, stride, offset, dataOwner);
202 #ifdef __SCILAB_INT64__
203                     case 8:
204                         return *new H5EnumData<long long>(parent, totalSize, dataSize, ndims, dims, (long long *)data, type, H5T_NATIVE_LLONG, nmembers, names, stride, offset, dataOwner);
205 #endif
206                 }
207             }
208
209             return *new H5EnumData<char>(parent, totalSize, dataSize, ndims, dims, (char *)data, type, H5T_NATIVE_CHAR, nmembers, names, stride, offset, dataOwner);
210         }
211         case H5T_VLEN:
212             return *new H5VlenData(parent, totalSize, dataSize, ndims, dims, static_cast<char *>(data), type, stride, offset, dataOwner);
213         case H5T_ARRAY:
214             return *new H5ArrayData(parent, totalSize, dataSize, ndims, dims, static_cast<char *>(data), type, stride, offset, dataOwner);
215         default:
216             throw H5Exception(__LINE__, __FILE__, _("Cannot get data from an unknown data type."));
217     }
218
219     throw H5Exception(__LINE__, __FILE__, _("Cannot get data from an unknown data type."));
220 }
221
222 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)
223 {
224     hid_t nativeType = H5Tget_native_type(type, H5T_DIR_DEFAULT);
225     hid_t _space = space < 0 ? (isAttribute ? H5Aget_space(obj) : H5Dget_space(obj)) : space;
226     hsize_t size = H5Tget_size(nativeType);
227     H5S_sel_type sel;
228     hid_t targetspace;
229     herr_t err;
230     hsize_t * blockbuf = 0;
231     bool hyperslab = false;
232     bool isString = false;
233
234     *totalSize = 1;
235     if (H5Tget_class(nativeType) == H5T_STRING && !H5Tis_variable_str(nativeType))
236     {
237         // We have a C-string so it is null terminated
238         size++;
239         isString = true;
240     }
241
242     *dataSize = size;
243     *ndims = H5Sget_simple_extent_dims(_space, 0, 0);
244     *dims = new hsize_t[*ndims];
245
246     if (isAttribute)
247     {
248         H5Sget_simple_extent_dims(_space, *dims, 0);
249         for (unsigned int i = 0; i < *ndims; i++)
250         {
251             *totalSize *= (*dims)[i];
252         }
253     }
254     else
255     {
256         sel = H5Sget_select_type(_space);
257         switch (sel)
258         {
259             case H5S_SEL_NONE:
260             case H5S_SEL_ALL:
261                 H5Sget_simple_extent_dims(_space, *dims, 0);
262                 for (unsigned int i = 0; i < *ndims; i++)
263                 {
264                     *totalSize *= (*dims)[i];
265                 }
266                 break;
267             case H5S_SEL_POINTS:
268                 break;
269             case H5S_SEL_HYPERSLABS:
270                 for (unsigned int i = 0; i < *ndims; i++)
271                 {
272                     (*dims)[i] = selectdims[i];
273                     *totalSize *= (*dims)[i];
274                 }
275                 hyperslab = true;
276         }
277     }
278
279     size *= *totalSize;
280
281     if ((hsize_t)((size_t)size) != size)
282     {
283         H5Tclose(nativeType);
284         if (space < 0)
285         {
286             H5Sclose(_space);
287         }
288         delete[] *dims;
289         throw H5Exception(__LINE__, __FILE__, _("Memory to allocate is too big"));
290     }
291
292     try
293     {
294         if (isString)
295         {
296             *data = static_cast<void *>(new char[(size_t)size]());
297         }
298         else
299         {
300             // No need to initialize the array
301             *data = static_cast<void *>(new char[(size_t)size]);
302         }
303     }
304     catch (const std::bad_alloc & /*e*/)
305     {
306         H5Tclose(nativeType);
307         if (space < 0)
308         {
309             H5Sclose(_space);
310         }
311         *data = 0;
312         delete[] *dims;
313         *dims = 0;
314         throw H5Exception(__LINE__, __FILE__, _("Cannot allocate memory to get the data"));
315     }
316
317     if (!*data)
318     {
319         H5Tclose(nativeType);
320         if (space < 0)
321         {
322             H5Sclose(_space);
323         }
324         delete[] *dims;
325         *dims = 0;
326         throw H5Exception(__LINE__, __FILE__, _("Cannot allocate memory to get the data"));
327     }
328
329     if (hyperslab)
330     {
331         targetspace =  H5Screate_simple((int) * ndims, *dims, 0);
332         err = H5Dread(obj, nativeType, targetspace, _space, H5P_DEFAULT, *data);
333         H5Sclose(targetspace);
334     }
335     else
336     {
337         if (isAttribute)
338         {
339             err = H5Aread(obj, nativeType, *data);
340         }
341         else
342         {
343             err = H5Dread(obj, nativeType, H5S_ALL, H5S_ALL, H5P_DEFAULT, *data);
344         }
345     }
346
347     if (err < 0)
348     {
349         H5Tclose(nativeType);
350         if (space < 0)
351         {
352             H5Sclose(_space);
353         }
354         delete[] static_cast<char *>(*data);
355         *data = 0;
356         delete[] *dims;
357         *dims = 0;
358         throw H5Exception(__LINE__, __FILE__, _("Cannot retrieve the data from the attribute"));
359     }
360
361     H5Tclose(nativeType);
362     if (space < 0)
363     {
364         H5Sclose(_space);
365     }
366 }
367 }