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 #ifndef __HDF5SCILAB_HXX__
17 #define __HDF5SCILAB_HXX__
18 
19 #include <vector>
20 #include <map>
21 
22 #include "H5Options.hxx"
23 #include "H5Object.hxx"
24 #include "H5File.hxx"
25 #include "H5Group.hxx"
26 #include "H5Dataset.hxx"
27 #include "H5Dataspace.hxx"
28 #include "H5Attribute.hxx"
29 #include "H5BasicData.hxx"
30 #include "H5Data.hxx"
31 #include "H5VariableScope.hxx"
32 
33 extern "C"
34 {
35 #include "doublecomplex.h"
36 #include "api_scilab.h"
37 #include "Scierror.h"
38 #include "HDF5Objects.h"
39 #include "sciprint.h"
40 #include "localization.h"
41 }
42 
43 namespace org_modules_hdf5
44 {
45 
46 class HDF5Scilab
47 {
48 
49 public:
50 
51     enum H5ObjectType
52     {
53         H5FILE,
54         H5GROUP,
55         H5DATASET,
56         H5ATTRIBUTE,
57         H5SPACE,
58         H5TYPE,
59         H5REFERENCE,
60         H5LIST,
61         H5COMPOUND,
62         H5ARRAY,
63         H5VLEN
64     };
65 
66     static std::map<std::string, H5Object::FilterType> filtersName;
67 
68     static int getH5ObjectId(int * mlist, void * pvApiCtx);
69 
70     static H5Object * getH5Object(int * mlist, void * pvApiCtx);
71 
72     static bool isH5Object(int * mlist, void * pvApiCtx);
73 
74     static void scilabPrint(const std::string & str);
75 
76     static void split(const std::string & str, std::vector<std::string> & v, const char c = '\n');
77 
78     static void readData(const std::string & filename, const std::string & name, const unsigned int size, const double * start, const double * stride, const double * count, const double * block, int pos, void * pvApiCtx);
79 
80     static void readData(H5Object & obj, const std::string & name, const unsigned int size, const double * start, const double * stride, const double * count, const double * block, int pos, void * pvApiCtx);
81 
82     static void readAttributeData(H5Object & obj, const std::string & path, const std::string & attrName, int pos, void * pvApiCtx);
83 
84     static void readAttributeData(const std::string & filename, const std::string & path, const std::string & attrName, int pos, void * pvApiCtx);
85 
86     static void deleteObject(const std::string & file, const std::string & name);
87 
88     static void deleteObject(const std::string & file, const int size, const char ** names);
89 
90     static void deleteObject(const H5Object & parent, const std::string & name);
91 
92     static void deleteObject(const H5Object & parent, const int size, const char ** names);
93 
94     static void getObject(H5Object & parent, const std::string & location, const bool isAttr, int position, void * pvApiCtx);
95 
96     static void createLink(H5Object & parent, const std::string & name, const std::string & targetPath, const bool hard);
97 
98     static void createLink(H5Object & parent, const std::string & name, H5Object & targetObject, const bool hard);
99 
100     static void createLink(H5Object & parent, const std::string & name, const std::string & targetFile, const std::string & targetPath);
101 
102     static void createLink(H5Object & parent, const std::string & name, H5Object & targetObject);
103 
104     static void createLink(const std::string & file, const std::string & location, const std::string & name, const std::string & destName, const bool hard);
105 
106     static void createLink(const std::string & file, const std::string & location, const std::string & name, const std::string & destFile, const std::string & destName);
107 
108     static void copy(H5Object & src, const std::string & slocation, H5Object & dest, const std::string & dlocation);
109 
110     static void copy(H5Object & src, const std::string & slocation, const std::string & dfile, const std::string & dlocation);
111 
112     static void copy(const std::string & sfile, const std::string & slocation, H5Object & dest, const std::string & dlocation);
113 
114     static void copy(const std::string & sfile, const std::string & slocation, const std::string & dfile, const std::string & dlocation);
115 
116     static void ls(H5Object & obj, const std::string & name, int position, void * pvApiCtx);
117 
118     static void ls(const std::string & path, const std::string & name, int position, void * pvApiCtx);
119 
120     static void ls(H5Object & obj, const std::string & name, const std::string & type, int position, void * pvApiCtx);
121 
122     static void ls(const std::string & path, const std::string & name, const std::string & type, int position, void * pvApiCtx);
123 
124     static bool checkType(const H5Object & obj, const H5ObjectType type);
125 
126     static void mount(H5Object & obj, const std::string & location, H5Object & file);
127 
128     static void umount(H5Object & obj, const std::string & location);
129 
130     static void createGroup(H5Object & parent, const std::string & name);
131 
132     static void createGroup(const std::string & file, const std::string & name);
133 
134     static void createGroup(H5Object & parent, const int size, const char ** names);
135 
136     static void createGroup(const std::string & file, const int size, const char ** names);
137 
138     static void label(H5Object & obj, const std::string & location, const unsigned int size, const unsigned int * dim, const char ** names);
139 
140     static void label(const std::string & filename, const std::string & location, const unsigned int size, const unsigned int * dim, const char ** names);
141 
142     static int * exists(H5Object & obj, const unsigned int size, const char ** locations, const char ** attrNames);
143 
144     static int * exists(const std::string & filename, const unsigned int size, const char ** locations, const char ** attrNames);
145 
146     template <typename T>
create(H5Object & parent,const std::string & name,const unsigned int srank,const hsize_t * sdims,const hsize_t * sstart,const hsize_t * sstride,const hsize_t * scount,const hsize_t * sblock,const hid_t sourceType,void * data,const unsigned int drank,const hsize_t * ddims,const hsize_t * dmaxdims,const hsize_t * dstart,const hsize_t * dstride,const hsize_t * dcount,const hsize_t * dblock,const hid_t targetType)147     static T & create(H5Object & parent, const std::string & name, const unsigned int srank, const hsize_t * sdims, const hsize_t * sstart, const hsize_t * sstride, const hsize_t * scount, const hsize_t * sblock, const hid_t sourceType, void * data, const unsigned int drank, const hsize_t * ddims, const hsize_t * dmaxdims, const hsize_t * dstart, const hsize_t * dstride, const hsize_t * dcount, const hsize_t * dblock, const hid_t targetType)
148     {
149         hid_t obj;
150         hid_t srcspace;
151         hid_t targetspace;
152         hid_t targettype;
153         hsize_t * newdims = 0;
154         bool mustDelete = false;
155         H5T_cdata_t * pcdata = 0;
156         bool chunked = false;
157 
158         if (srank > __SCILAB_HDF5_MAX_DIMS__ || drank > __SCILAB_HDF5_MAX_DIMS__)
159         {
160             throw H5Exception(__LINE__, __FILE__, _("Invalid rank, must be in the interval [0, %d]."), __SCILAB_HDF5_MAX_DIMS__);
161         }
162 
163         if (targetType == (hid_t) - 1)
164         {
165             targettype = H5Tcopy(sourceType);
166         }
167         else
168         {
169             targettype = H5Tcopy(targetType);
170         }
171 
172         if (!H5Tfind(sourceType, targettype, &pcdata))
173         {
174             H5Tclose(targettype);
175             throw H5Exception(__LINE__, __FILE__, _("No converter found for the specified target datatype."));
176         }
177 
178         srcspace = H5Screate_simple(srank, sdims, 0);
179         if (srcspace < 0)
180         {
181             H5Tclose(targettype);
182             throw H5Exception(__LINE__, __FILE__, _("Cannot create a new dataspace."));
183         }
184 
185         try
186         {
187             newdims = H5Dataspace::select(srcspace, srank, sstart, sstride, scount, sblock);
188         }
189         catch (const H5Exception & /*e*/)
190         {
191             H5Tclose(targettype);
192             H5Sclose(srcspace);
193             throw;
194         }
195 
196         if (ddims)
197         {
198             targetspace = H5Screate_simple(drank, ddims, dmaxdims);
199             if (targetspace < 0)
200             {
201                 if (newdims)
202                 {
203                     delete[] newdims;
204                 }
205                 H5Sclose(srcspace);
206                 H5Tclose(targettype);
207                 throw H5Exception(__LINE__, __FILE__, _("Invalid target dataspace."));
208             }
209             if (dmaxdims)
210             {
211                 for (unsigned int i = 0; i < drank; i++)
212                 {
213                     if (ddims[i] != dmaxdims[i])
214                     {
215                         chunked = true;
216                         break;
217                     }
218                 }
219             }
220         }
221         else if (newdims)
222         {
223             targetspace = H5Screate_simple(srank, newdims, 0);
224             if (targetspace < 0)
225             {
226                 delete[] newdims;
227                 H5Sclose(srcspace);
228                 H5Tclose(targettype);
229                 throw H5Exception(__LINE__, __FILE__, _("Cannot create a new dataspace."));
230             }
231         }
232         else
233         {
234             targetspace = (hid_t) - 1;
235         }
236 
237         if (newdims)
238         {
239             delete[] newdims;
240         }
241 
242         if (targetspace != -1 && dstart)
243         {
244             try
245             {
246                 hsize_t * _newdims = H5Dataspace::select(targetspace, drank, dstart, dstride, dcount, dblock);
247                 if (_newdims)
248                 {
249                     delete[] _newdims;
250                 }
251             }
252             catch (const H5Exception & /*e*/)
253             {
254                 H5Tclose(targettype);
255                 H5Sclose(targetspace);
256                 H5Sclose(srcspace);
257                 throw;
258             }
259         }
260 
261         try
262         {
263             obj = T::create(parent, name, sourceType, targettype, srcspace, targetspace, data, chunked);
264             H5Sclose(srcspace);
265             if (targetspace >= 0)
266             {
267                 H5Sclose(targetspace);
268             }
269         }
270         catch (const H5Exception & /*e*/)
271         {
272             H5Tclose(targettype);
273             H5Sclose(srcspace);
274             if (targetspace >= 0)
275             {
276                 H5Sclose(targetspace);
277             }
278             throw;
279         }
280 
281         H5Tclose(targettype);
282 
283         return *new T(parent, obj, name);
284     }
285 
286     static void getScilabData(hid_t * type, unsigned int * ndims, hsize_t ** dims, void ** data, bool * mustDelete, bool * mustDeleteContent, const bool flip, int rhsPosition, void * pvApiCtx);
287 
288     static void getScilabData(hid_t * type, unsigned int * ndims, hsize_t ** dims, void ** data, bool * mustDelete, bool * mustDeleteContent, const bool flip, int * addr, int rhsPosition, void * pvApiCtx);
289 
290     template <typename T>
createObjectFromStack(const std::string & file,const std::string & location,const std::string & name,const bool flip,void * pvApiCtx,const int rhsPosition,const unsigned int srank,const hsize_t * sdims,const hsize_t * sstart,const hsize_t * sstride,const hsize_t * scount,const hsize_t * sblock,const std::string & targetType,const unsigned int drank,const hsize_t * ddims,const hsize_t * dmaxdims,const hsize_t * dstart,const hsize_t * dstride,const hsize_t * dcount,const hsize_t * dblock)291     static void createObjectFromStack(const std::string & file, const std::string & location, const std::string & name, const bool flip, void * pvApiCtx, const int rhsPosition, const unsigned int srank, const hsize_t * sdims, const hsize_t * sstart, const hsize_t * sstride, const hsize_t * scount, const hsize_t * sblock, const std::string & targetType, const unsigned int drank, const hsize_t * ddims, const hsize_t * dmaxdims, const hsize_t * dstart, const hsize_t * dstride, const hsize_t * dcount, const hsize_t * dblock)
292     {
293         H5File & src = *new H5File(file, "/", "r+");
294 
295         try
296         {
297             createObjectFromStack<T>(src, location, name, flip, pvApiCtx, rhsPosition, srank, sdims, sstart, sstride, scount, sblock, targetType, drank, ddims, dmaxdims, dstart, dstride, dcount, dblock);
298             delete &src;
299         }
300         catch (const H5Exception & /*e*/)
301         {
302             delete &src;
303             throw;
304         }
305     }
306 
307     template <typename T>
createObjectFromStack(H5Object & obj,const std::string & location,const std::string & name,const bool flip,void * pvApiCtx,const int rhsPosition,const unsigned int srank,const hsize_t * sdims,const hsize_t * sstart,const hsize_t * sstride,const hsize_t * scount,const hsize_t * sblock,const std::string & targetType,const unsigned int drank,const hsize_t * ddims,const hsize_t * dmaxdims,const hsize_t * dstart,const hsize_t * dstride,const hsize_t * dcount,const hsize_t * dblock)308     static void createObjectFromStack(H5Object & obj, const std::string & location, const std::string & name, const bool flip, void * pvApiCtx, const int rhsPosition, const unsigned int srank, const hsize_t * sdims, const hsize_t * sstart, const hsize_t * sstride, const hsize_t * scount, const hsize_t * sblock, const std::string & targetType, const unsigned int drank, const hsize_t * ddims, const hsize_t * dmaxdims, const hsize_t * dstart, const hsize_t * dstride, const hsize_t * dcount, const hsize_t * dblock)
309     {
310         hid_t sourceType = -1;;
311         hid_t targettype;
312         unsigned int rank;
313         hsize_t * dims = 0;
314         void * data = 0;
315         bool mustDelete = false;
316         bool mustDeleteContent = false;
317         H5Object * hobj = 0;
318         T * newobj = 0;
319         bool isReference = false;
320         hsize_t total = 1;
321 
322         if (targetType.empty())
323         {
324             targettype = (hid_t) - 1;
325         }
326         else
327         {
328             targettype = H5Type::getBaseType(targetType);
329             if (targettype < 0)
330             {
331                 throw H5Exception(__LINE__, __FILE__, _("Cannot create the target type."));
332             }
333 
334             if (H5Tequal(targettype, H5T_STD_REF_OBJ))
335             {
336                 isReference = true;
337             }
338         }
339 
340         try
341         {
342             hobj = H5Object::isEmptyPath(location) ? &obj : &H5Object::getObject(obj, location);
343             getScilabData(&sourceType, &rank, &dims, &data, &mustDelete, &mustDeleteContent, flip, rhsPosition, pvApiCtx);
344 
345             if (sdims)
346             {
347                 hsize_t p1 = 1;
348                 hsize_t p2 = 1;
349                 for (unsigned int i = 0; i < srank; i++)
350                 {
351                     p1 *= sdims[i];
352                 }
353                 for (unsigned int i = 0; i < rank; i++)
354                 {
355                     p2 *= dims[i];
356                 }
357 
358                 total = p1;
359 
360                 if (p1 != p2)
361                 {
362                     throw H5Exception(__LINE__, __FILE__, _("Incompatible dimensions"));
363                 }
364                 rank = srank;
365             }
366             else
367             {
368                 sdims = dims;
369                 for (unsigned int i = 0; i < rank; i++)
370                 {
371                     total *= sdims[i];
372                 }
373             }
374 
375             if (isReference)
376             {
377                 herr_t err;
378                 hid_t loc;
379                 hobj_ref_t * newData = 0;
380 
381                 if (H5Tget_class(sourceType) != H5T_STRING)
382                 {
383                     throw H5Exception(__LINE__, __FILE__, _("References must be given as strings"));
384                 }
385 
386                 loc = hobj->getFile().getH5Id();
387                 newData = (hobj_ref_t *)MALLOC(sizeof(hobj_ref_t) * total);
388 
389                 for (unsigned int i = 0; i < total; i++)
390                 {
391                     char * _name = static_cast<char **>(data)[i];
392                     err = H5Rcreate(newData + i, loc, _name, H5R_OBJECT, -1);
393                     if (err < 0)
394                     {
395                         FREE(newData);
396                         throw H5Exception(__LINE__, __FILE__, _("Invalid path: %s."), _name);
397                     }
398                 }
399 
400                 if (mustDeleteContent)
401                 {
402                     for (unsigned int i = 0; i < total; i++)
403                     {
404                         FREE(static_cast<void **>(data)[i]);
405                     }
406                 }
407                 if (mustDelete)
408                 {
409                     FREE(data);
410                 }
411 
412                 data = newData;
413                 mustDeleteContent = false;
414                 mustDelete = false;
415 
416                 if (sourceType > 0)
417                 {
418                     H5Tclose(sourceType);
419                 }
420                 sourceType = H5Tcopy(targettype);
421             }
422 
423             newobj = &create<T>(*hobj, name, rank, sdims, sstart, sstride, scount, sblock, sourceType, data, drank, ddims, dmaxdims, dstart, dstride, dcount, dblock, targettype);
424         }
425         catch (const H5Exception & /*e*/)
426         {
427             if (mustDeleteContent)
428             {
429                 for (unsigned int i = 0; i < total; i++)
430                 {
431                     FREE(static_cast<void **>(data)[i]);
432                 }
433             }
434             if (mustDelete)
435             {
436                 FREE(data);
437             }
438             if (dims)
439             {
440                 delete[] dims;
441             }
442             if (!H5Object::isEmptyPath(location))
443             {
444                 delete hobj;
445             }
446             if (targettype > 0)
447             {
448                 H5Tclose(targettype);
449             }
450 
451             if (sourceType > 0)
452             {
453                 H5Tclose(sourceType);
454             }
455 
456             throw;
457         }
458 
459         if (newobj)
460         {
461             delete newobj;
462         }
463 
464         if (mustDeleteContent)
465         {
466             for (unsigned int i = 0; i < total; i++)
467             {
468                 FREE(static_cast<void **>(data)[i]);
469             }
470         }
471         if (mustDelete)
472         {
473             FREE(data);
474         }
475         if (dims)
476         {
477             delete[] dims;
478         }
479         if (!H5Object::isEmptyPath(location))
480         {
481             delete hobj;
482         }
483         if (targettype > 0)
484         {
485             H5Tclose(targettype);
486         }
487         if (sourceType > 0)
488         {
489             H5Tclose(sourceType);
490         }
491     }
492 
493     template <typename T>
flip(const unsigned int size,T * data)494     static void flip(const unsigned int size, T * data)
495     {
496         if (!data)
497         {
498             return;
499         }
500 
501         for (unsigned int i = 0; i < size / 2; i++)
502         {
503             T x = data[i];
504             data[i] = data[size - 1 - i];
505             data[size - 1 - i] = x;
506         }
507     }
508 
509     template <typename T>
flipAndConvert(const unsigned int size,T * data)510     static hsize_t * flipAndConvert(const unsigned int size, T * data)
511     {
512         if (!data)
513         {
514             return 0;
515         }
516 
517         hsize_t * arr = new hsize_t[size];
518         for (unsigned int i = 0; i < size; i++)
519         {
520             arr[i] = (hsize_t)data[size - 1 - i];
521         }
522 
523         return arr;
524     }
525 
526 private:
527     static std::map<std::string, H5Object::FilterType> initFilterNames();
528 };
529 }
530 
531 #endif // __HDF5SCILAB_HXX__
532