fc1766621706c9ff4a656af879c194923c72aab8
[scilab.git] / scilab / modules / hdf5 / sci_gateway / cpp / sci_hdf5_save.cpp
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2015 - Scilab Enterprises - Antoine ELIAS
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 <list>
14 #include <map>
15 #include <hdf5.h>
16 #include "hdf5_gw.hxx"
17 #include "context.hxx"
18 #include "string.hxx"
19 #include "double.hxx"
20 #include "struct.hxx"
21 #include "cell.hxx"
22 #include "int.hxx"
23 #include "polynom.hxx"
24 #include "sparse.hxx"
25 #include "macrofile.hxx"
26 #include "graphichandle.hxx"
27 #include "user.hxx"
28 #include "overload.hxx"
29 #include "execvisitor.hxx"
30 #include "handle_properties.hxx"
31 #include "context.hxx"
32 #include "serializervisitor.hxx"
33
34 extern "C"
35 {
36 #include "sci_malloc.h"
37 #include "Scierror.h"
38 #include "localization.h"
39 #include "freeArrayOfString.h"
40 #include "os_string.h"
41 #include "deleteafile.h"
42 #include "expandPathVariable.h"
43 #include "h5_fileManagement.h"
44 #include "h5_writeDataToFile.h"
45 #include "h5_readDataFromFile.h"
46 #include "h5_attributeConstants.h"
47 #include "HandleManagement.h"
48 }
49
50 /*--------------------------------------------------------------------------*/
51 static bool isVarExist(int _iFile, const char* _pstVarName);
52 static int extractVarNameList(int* pvCtx, int _iStart, int _iEnd, char** _pstNameList);
53
54 int export_data(int parent, const std::string& name, types::InternalType* data);
55 static int export_double(int parent, const std::string& name, types::Double* data);
56 static int export_string(int parent, const std::string& name, types::String* data);
57 static int export_boolean(int parent, const std::string& name, types::Bool* data);
58 static int export_list(int parent, const std::string& name, types::List* data);
59 static int export_struct(int parent, const std::string& name, types::Struct* data, const char* type = g_SCILAB_CLASS_STRUCT);
60 template <class T> static int export_int(int parent, const std::string& name, int type, const char* prec, T* data);
61 static int export_poly(int parent, const std::string& name, types::Polynom* data);
62 static int export_sparse(int parent, const std::string& name, types::Sparse* data);
63 static int export_cell(int parent, const std::string& name, types::Cell* data);
64 static int export_macro(int parent, const std::string& name, types::Macro* data);
65 static int export_usertype(int parent, const std::string& name, types::UserType* data);
66
67 static int export_boolean_sparse(int parent, const std::string& name, types::SparseBool* data);
68 static int export_handles(int parent, const std::string& name, types::GraphicHandle* data);
69 static int export_void(int parent, const std::string& name);
70 static int export_undefined(int parent, const std::string& name);
71
72 /*--------------------------------------------------------------------------*/
73 static const std::string fname("save");
74 /*--------------------------------------------------------------------------*/
75 types::Function::ReturnValue sci_hdf5_save(types::typed_list &in, int _iRetCount, types::typed_list &out)
76 {
77     int iH5File = 0;
78     bool bAppendMode = false;
79     int rhs = static_cast<int>(in.size());
80     std::string filename;
81     std::map<std::string, types::InternalType*> vars;
82     symbol::Context* ctx = symbol::Context::getInstance();
83
84     /* Check the number of input argument */
85     if (in.size() < 2)
86     {
87         Scierror(999, _("%s: Wrong number of input argument(s): at least %d expected.\n"), fname.data(), 2);
88         return types::Function::Error;
89     }
90
91     if (in[0]->getId() != types::InternalType::IdScalarString)
92     {
93         Scierror(999, _("%s: Wrong type for input argument #%d: A String expected.\n"), fname.data(), 1);
94         return types::Function::Error;
95     }
96
97     wchar_t* wfilename = expandPathVariableW(in[0]->getAs<types::String>()->get()[0]);
98     char* cfilename = wide_string_to_UTF8(wfilename);
99     filename = cfilename;
100     FREE(wfilename);
101     FREE(cfilename);
102
103     for (int i = 1; i < rhs; ++i)
104     {
105         if (in[i]->getId() != types::InternalType::IdScalarString)
106         {
107             Scierror(999, _("%s: Wrong type for input argument #%d: A String expected.\n"), fname.data(), 1);
108             return types::Function::Error;
109         }
110
111         wchar_t* wvar = in[i]->getAs<types::String>()->get()[0];
112         if (wcscmp(wvar, L"-append") == 0)
113         {
114             bAppendMode = true;
115             continue;
116         }
117
118         types::InternalType* pIT = ctx->get(symbol::Symbol(wvar));
119         if (pIT == NULL)
120         {
121             Scierror(999, _("%s: Wrong value for input argument #%d: Defined variable expected.\n"), fname.data(), i + 1);
122             return types::Function::Error;
123         }
124
125         char* cvar = wide_string_to_UTF8(wvar);
126         std::string var(cvar);
127         FREE(cvar);
128
129         //check var exists
130         vars[var] = pIT;
131     }
132
133     //check append option
134     if (bAppendMode)
135     {
136         // open hdf5 file
137         iH5File = openHDF5File(filename.data(), bAppendMode);
138         if (iH5File < 0)
139         {
140             iH5File = createHDF5File(filename.data());
141         }
142         else
143         {
144             int iVersion = getSODFormatAttribute(iH5File);
145             if (iVersion != SOD_FILE_VERSION)
146             {
147                 //to update version must be the same
148                 closeHDF5File(iH5File);
149                 Scierror(999, _("%s: Wrong SOD file format version. Expected: %d Found: %d\n"), fname.data(), SOD_FILE_VERSION, iVersion);
150                 return types::Function::Error;
151             }
152         }
153     }
154     else
155     {
156         iH5File = createHDF5File(filename.data());
157     }
158
159
160     if (iH5File < 0)
161     {
162         if (iH5File == -2)
163         {
164             Scierror(999, _("%s: Wrong value for input argument #%d: \"%s\" is a directory"), fname.data(), 1, filename.data());
165         }
166         else
167         {
168             Scierror(999, _("%s: Cannot open file %s.\n"), fname.data() , filename.data());
169         }
170
171         return types::Function::Error;
172     }
173
174     // export data
175     for (const auto var : vars)
176     {
177         if (isVarExist(iH5File, var.first.data()))
178         {
179             if (bAppendMode)
180             {
181                 if (deleteHDF5Var(iH5File, var.first.data()))
182                 {
183                     closeHDF5File(iH5File);
184                     Scierror(999, _("%s: Unable to delete existing variable \"%s\".\n"), fname.data(), var.first.data());
185                     return types::Function::Error;
186                 }
187             }
188             else
189             {
190                 closeHDF5File(iH5File);
191                 Scierror(999, _("%s: Variable \'%s\' already exists in file \'%s\'\nUse -append option to replace existing variable.\n"), fname.data(), var.first.data(), filename.data());
192                 return types::Function::Error;
193             }
194         }
195
196         int iDataset = export_data(iH5File, var.first, var.second);
197         if (iDataset == -1)
198         {
199             closeHDF5File(iH5File);
200             deleteafile(filename.data());
201             Scierror(999, _("%s: Unable to export variable \'%s\' in file \'%s\'.\n"), fname.data(), var.first.data(), filename.data());
202             return types::Function::Error;
203         }
204     }
205
206     //add or update scilab version and file version in hdf5 file
207     if (updateScilabVersion(iH5File) < 0)
208     {
209         closeHDF5File(iH5File);
210         Scierror(999, _("%s: Unable to update Scilab version in \"%s\"."), fname.data(), filename.data());
211         return types::Function::Error;
212     }
213
214     if (updateFileVersion(iH5File) < 0)
215     {
216         closeHDF5File(iH5File);
217         Scierror(999, _("%s: Unable to update HDF5 format version in \"%s\"."), fname.data(), filename.data());
218         return types::Function::Error;
219     }
220
221     //close hdf5 file
222     closeHDF5File(iH5File);
223     return types::Function::OK;
224 }
225 /*--------------------------------------------------------------------------*/
226 static bool isVarExist(int _iFile, const char* _pstVarName)
227 {
228     //check if variable already exists
229     int iNbItem = getVariableNames6(_iFile, NULL);
230     if (iNbItem)
231     {
232         char **pstVarNameList = (char **)MALLOC(sizeof(char *) * iNbItem);
233
234         iNbItem = getVariableNames6(_iFile, pstVarNameList);
235
236         //import all data
237         for (int i = 0; i < iNbItem; i++)
238         {
239             if (strcmp(pstVarNameList[i], _pstVarName) == 0)
240             {
241                 freeArrayOfString(pstVarNameList, iNbItem);
242                 return true;
243             }
244         }
245
246         freeArrayOfString(pstVarNameList, iNbItem);
247     }
248
249     return false;
250 }
251 /*--------------------------------------------------------------------------*/
252 int export_data(int parent, const std::string& name, types::InternalType* data)
253 {
254     int dataset = -1;
255     switch (data->getType())
256     {
257         case types::InternalType::ScilabDouble:
258             dataset = export_double(parent, name, data->getAs<types::Double>());
259             break;
260         case types::InternalType::ScilabString:
261             dataset = export_string(parent, name, data->getAs<types::String>());
262             break;
263         case types::InternalType::ScilabBool:
264             dataset = export_boolean(parent, name, data->getAs<types::Bool>());
265             break;
266         case types::InternalType::ScilabTList:
267         case types::InternalType::ScilabList:
268         case types::InternalType::ScilabMList:
269             dataset = export_list(parent, name, data->getAs<types::List>());
270             break;
271         case types::InternalType::ScilabInt8:
272             dataset = export_int(parent, name, H5T_NATIVE_INT8, "8", data->getAs<types::Int8>());
273             break;
274         case types::InternalType::ScilabInt16:
275             dataset = export_int(parent, name, H5T_NATIVE_INT16, "16", data->getAs<types::Int16>());
276             break;
277         case types::InternalType::ScilabInt32:
278             dataset = export_int(parent, name, H5T_NATIVE_INT32, "32", data->getAs<types::Int32>());
279             break;
280         case types::InternalType::ScilabInt64:
281             dataset = export_int(parent, name, H5T_NATIVE_INT64, "64", data->getAs<types::Int64>());
282             break;
283         case types::InternalType::ScilabUInt8:
284             dataset = export_int(parent, name, H5T_NATIVE_UINT8, "u8", data->getAs<types::UInt8>());
285             break;
286         case types::InternalType::ScilabUInt16:
287             dataset = export_int(parent, name, H5T_NATIVE_UINT16, "u16", data->getAs<types::UInt16>());
288             break;
289         case types::InternalType::ScilabUInt32:
290             dataset = export_int(parent, name, H5T_NATIVE_UINT32, "u32", data->getAs<types::UInt32>());
291             break;
292         case types::InternalType::ScilabUInt64:
293             dataset = export_int(parent, name, H5T_NATIVE_UINT64, "u64", data->getAs<types::UInt64>());
294             break;
295         case types::InternalType::ScilabStruct:
296             dataset = export_struct(parent, name, data->getAs<types::Struct>());
297             break;
298         case types::InternalType::ScilabPolynom:
299             dataset = export_poly(parent, name, data->getAs<types::Polynom>());
300             break;
301         case types::InternalType::ScilabSparse:
302             dataset = export_sparse(parent, name, data->getAs<types::Sparse>());
303             break;
304         case types::InternalType::ScilabSparseBool :
305             dataset = export_boolean_sparse(parent, name, data->getAs<types::SparseBool>());
306             break;
307         case types::InternalType::ScilabCell:
308             dataset = export_cell(parent, name, data->getAs<types::Cell>());
309             break;
310         case types::InternalType::ScilabVoid:
311             dataset = export_void(parent, name);
312             break;
313         case types::InternalType::ScilabListUndefinedOperation:
314             dataset = export_undefined(parent, name);
315             break;
316         case types::InternalType::ScilabMacro:
317             dataset = export_macro(parent, name, data->getAs<types::Macro>());
318             break;
319         case types::InternalType::ScilabMacroFile:
320         {
321             types::MacroFile* pMF = data->getAs<types::MacroFile>();
322             dataset = export_macro(parent, name, pMF->getMacro());
323             break;
324         }
325         case types::InternalType::ScilabHandle:
326             dataset = export_handles(parent, name, data->getAs<types::GraphicHandle>());
327             break;
328         case types::InternalType::ScilabUserType:
329             dataset = export_usertype(parent, name, data->getAs<types::UserType>());
330             break;
331         default:
332         {
333             break;
334         }
335     }
336
337     return dataset;
338 }
339
340 /*--------------------------------------------------------------------------*/
341 static int export_list(int parent, const std::string& name, types::List* data)
342 {
343     int size = data->getSize();
344
345     const char* type = nullptr;
346     switch (data->getType())
347     {
348         case types::InternalType::ScilabMList:
349             type = g_SCILAB_CLASS_MLIST;
350             break;
351         case types::InternalType::ScilabTList:
352             type = g_SCILAB_CLASS_TLIST;
353             break;
354         case types::InternalType::ScilabList:
355             type = g_SCILAB_CLASS_LIST;
356             break;
357         default:
358             return -1;
359     }
360
361     //create node with list name
362     int dset = openList6(parent, name.data(), type);
363
364     for (int i = 0; i < size; ++i)
365     {
366         if (export_data(dset, std::to_string(i).data(), data->get(i)) == -1)
367         {
368             closeList6(dset);
369             return -1;
370         }
371     }
372
373     if (closeList6(dset) == -1)
374     {
375         return -1;
376     }
377     return dset;
378 }
379 /*--------------------------------------------------------------------------*/
380 static int export_double(int parent, const std::string& name, types::Double* data)
381 {
382     int dataset = -1;
383
384     if (data->isComplex())
385     {
386         dataset = writeDoubleComplexMatrix6(parent, name.data(), data->getDims(), data->getDimsArray(), data->get(), data->getImg());
387     }
388     else
389     {
390         dataset = writeDoubleMatrix6(parent, name.data(), data->getDims(), data->getDimsArray(), data->get());
391     }
392
393     return dataset;
394 }
395 /*--------------------------------------------------------------------------*/
396 template <class T>
397 static int export_int(int parent, const std::string& name, int type, const char* prec, T* data)
398 {
399     return writeIntegerMatrix6(parent, name.data(), type, prec, data->getDims(), data->getDimsArray(), data->get());
400 }
401 /*--------------------------------------------------------------------------*/
402 static int export_string(int parent, const std::string& name, types::String* data)
403 {
404     int size = data->getSize();
405     wchar_t** s = data->get();
406     std::vector<char*> v(size);
407
408     //convert UTF16 strings to UTF8
409     for (int i = 0; i < size; ++i)
410     {
411         v[i] = wide_string_to_UTF8(s[i]);
412     }
413
414     int dset = writeStringMatrix6(parent, name.data(), data->getDims(), data->getDimsArray(), v.data());
415
416     //release memory
417     for (int i = 0; i < size; ++i)
418     {
419         FREE(v[i]);
420     }
421
422     return dset;
423 }
424 /*--------------------------------------------------------------------------*/
425 static int export_boolean(int parent, const std::string& name, types::Bool* data)
426 {
427     return writeBooleanMatrix6(parent, name.data(), data->getDims(), data->getDimsArray(), data->get());
428 }
429 /*--------------------------------------------------------------------------*/
430 static int export_struct(int parent, const std::string& name, types::Struct* data, const char* type)
431 {
432     //create a group with struct name
433     int dset = openList6(parent, name.data(), type);
434     //store struct dimensions
435     std::vector<int> dims = {1, data->getDims()};
436     int ret = writeIntegerMatrix6(dset, "__dims__", H5T_NATIVE_INT32, "32", 2, dims.data(), data->getDimsArray());
437     if (ret < 0)
438     {
439         return -1;
440     }
441
442     int size = data->getSize();
443
444     if (size == 0)
445     {
446         if (closeList6(dset) == -1)
447         {
448             return -1;
449         }
450
451         return dset;
452     }
453
454     //create a node for fields references
455     int refs = openList6(dset, "__refs__", g_SCILAB_CLASS_STRUCT);
456     if (refs < 0)
457     {
458         return -1;
459     }
460
461     types::String* fields = data->getFieldNames();
462     int fieldCount = fields->getSize();
463     wchar_t** pfields = fields->get();
464
465
466     std::vector<hobj_ref_t> vrefs(size);
467     //fill main group with struct field name
468     for (int i = 0; i < fieldCount; ++i)
469     {
470         char* cfield = wide_string_to_UTF8(pfields[i]);
471         for (int j = 0; j < size; ++j)
472         {
473             //get data
474             types::InternalType* val = data->get(j)->get(pfields[i]);
475             //create ref name
476             std::string refname(cfield);
477             refname += "_" + std::to_string(j);
478             //export data in refs group
479             int ref = export_data(refs, refname, val);
480             //create reference of data
481             ret = addItemStruct6(refs, vrefs.data(), j, refname.data());
482             if (ret)
483             {
484                 return -1;
485             }
486         }
487
488         ret = writeStructField6(dset, cfield, data->getDims(), data->getDimsArray(), vrefs.data());
489         FREE(cfield);
490         if (ret < 0)
491         {
492             return -1;
493         }
494     }
495
496     if (closeList6(refs) == -1)
497     {
498         return -1;
499     }
500
501     if (closeList6(dset) == -1)
502     {
503         return -1;
504     }
505
506     return dset;
507 }
508 /*--------------------------------------------------------------------------*/
509 static int export_void(int parent, const std::string& name)
510 {
511     return writeVoid6(parent, name.data());
512 }
513 /*--------------------------------------------------------------------------*/
514 static int export_undefined(int parent, const std::string& name)
515 {
516     return writeUndefined6(parent, name.data());
517 }
518 /*--------------------------------------------------------------------------*/
519 static int export_poly(int parent, const std::string& name, types::Polynom* data)
520 {
521     //create a group with struct name
522     int dset = openList6(parent, name.data(), g_SCILAB_CLASS_POLY);
523     //store struct dimensions
524     std::vector<int> dims = {1, data->getDims()};
525     int ret = writeIntegerMatrix6(dset, "__dims__", H5T_NATIVE_INT32, "32", 2, dims.data(), data->getDimsArray());
526     if (ret < 0)
527     {
528         return -1;
529     }
530
531     //store variable name
532     std::vector<int> vardims = {1, 1};
533     char* varname = wide_string_to_UTF8(data->getVariableName().data());
534     ret = writeStringMatrix6(dset, "__varname__", 2, vardims.data(), &varname);
535     FREE(varname);
536     if (ret < 0)
537     {
538         return -1;
539     }
540
541     //create a node for fields references
542     int refs = openList6(dset, "__refs__", g_SCILAB_CLASS_POLY);
543     if (refs < 0)
544     {
545         return -1;
546     }
547
548     bool complex = data->isComplex();
549     int size = data->getSize();
550     std::vector<hobj_ref_t> vrefs(size);
551     types::SinglePoly** ss = data->get();
552     //fill main group with struct field name
553     for (int j = 0; j < size; ++j)
554     {
555         //get data
556         types::SinglePoly* val = ss[j];
557         //export data in refs group
558         std::vector<int> ssdims = {1, val->getSize()};
559         std::string polyname(std::to_string(j));
560         if (complex)
561         {
562             writeDoubleComplexMatrix6(refs, polyname.data(), 2, ssdims.data(), val->get(), val->getImg());
563         }
564         else
565         {
566             writeDoubleMatrix6(refs, polyname.data(), 2, ssdims.data(), val->get());
567         }
568
569         //create reference of data
570         ret = addItemStruct6(refs, vrefs.data(), j, polyname.data());
571         if (ret)
572         {
573             return -1;
574         }
575     }
576
577
578     if (closeList6(refs) == -1)
579     {
580         return -1;
581     }
582
583     if (closeList6(dset) == -1)
584     {
585         return -1;
586     }
587
588     return dset;
589 }
590 /*--------------------------------------------------------------------------*/
591 static int export_sparse(int parent, const std::string& name, types::Sparse* data)
592 {
593     int nnz = static_cast<int>(data->nonZeros());
594     int row = data->getRows();
595     //create a group with sparse name
596     int dset = openList6(parent, name.data(), g_SCILAB_CLASS_SPARSE);
597     //store sparse dimensions
598     std::vector<int> dims = {1, data->getDims()};
599     int ret = writeIntegerMatrix6(dset, "__dims__", H5T_NATIVE_INT32, "32", 2, dims.data(), data->getDimsArray());
600     if (ret < 0)
601     {
602         return -1;
603     }
604
605     //store numbers of non zero by rows.
606     std::vector<int> dimsnnz = {1, 1};
607     ret = writeIntegerMatrix6(dset, "__nnz__", H5T_NATIVE_INT32, "32", 2, dimsnnz.data(), &nnz);
608     if (ret < 0)
609     {
610         return -1;
611     }
612
613     //store inner vector
614     int innercount = 0;
615     int* inner = data->getInnerPtr(&innercount);
616     std::vector<int> dimsinner = {1, nnz};
617     ret = writeIntegerMatrix6(dset, "__inner__", H5T_NATIVE_INT32, "32", 2, dimsinner.data(), inner);
618     if (ret < 0)
619     {
620         return -1;
621     }
622
623     int outercount = 0;
624     int* outer = data->getOuterPtr(&outercount);
625     std::vector<int> dimsouter = {1, outercount + 1};
626     ret = writeIntegerMatrix6(dset, "__outer__", H5T_NATIVE_INT32, "32", 2, dimsouter.data(), outer);
627     if (ret < 0)
628     {
629         return -1;
630     }
631
632     if (data->isComplex())
633     {
634         double* real = new double[nnz];
635         double* img = new double[nnz];
636         std::complex<double>* d = data->getImg();
637         for (int i = 0; i < nnz; ++i)
638         {
639             real[i] = d[i].real();
640             img[i] = d[i].imag();
641         }
642
643
644         std::vector<int> dimsdata = {1, nnz};
645         ret = writeDoubleComplexMatrix6(dset, "__data__", 2, dimsdata.data(), real, img);
646         delete[] real;
647         delete[] img;
648         if (ret < 0)
649         {
650             return -1;
651         }
652     }
653     else
654     {
655         std::vector<int> dimsdata = {1, nnz};
656         ret = writeDoubleMatrix6(dset, "__data__", 2, dimsdata.data(), data->get());
657         if (ret < 0)
658         {
659             return -1;
660         }
661     }
662
663     if (closeList6(dset) == -1)
664     {
665         return -1;
666     }
667
668     return dset;
669
670 }
671 /*--------------------------------------------------------------------------*/
672 static int export_boolean_sparse(int parent, const std::string& name, types::SparseBool* data)
673 {
674     int nnz = static_cast<int>(data->nbTrue());
675     int row = data->getRows();
676     //create a group with sparse name
677     int dset = openList6(parent, name.data(), g_SCILAB_CLASS_BSPARSE);
678     //store sparse dimensions
679     std::vector<int> dims = {1, data->getDims()};
680     int ret = writeIntegerMatrix6(dset, "__dims__", H5T_NATIVE_INT32, "32", 2, dims.data(), data->getDimsArray());
681     if (ret < 0)
682     {
683         return -1;
684     }
685
686     //store numbers of non zero by rows.
687     std::vector<int> dimsnnz = {1, 1};
688     ret = writeIntegerMatrix6(dset, "__nnz__", H5T_NATIVE_INT32, "32", 2, dimsnnz.data(), &nnz);
689     if (ret < 0)
690     {
691         return -1;
692     }
693
694     //store inner vector
695     int innercount = 0;
696     int* inner = data->getInnerPtr(&innercount);
697     std::vector<int> dimsinner = {1, nnz};
698     ret = writeIntegerMatrix6(dset, "__inner__", H5T_NATIVE_INT32, "32", 2, dimsinner.data(), inner);
699     if (ret < 0)
700     {
701         return -1;
702     }
703
704     int outercount = 0;
705     int* outer = data->getOuterPtr(&outercount);
706     std::vector<int> dimsouter = {1, outercount + 1};
707     ret = writeIntegerMatrix6(dset, "__outer__", H5T_NATIVE_INT32, "32", 2, dimsouter.data(), outer);
708     if (ret < 0)
709     {
710         return -1;
711     }
712
713     if (closeList6(dset) == -1)
714     {
715         return -1;
716     }
717
718     return dset;
719 }
720 /*--------------------------------------------------------------------------*/
721 static int export_cell(int parent, const std::string& name, types::Cell* data)
722 {
723     //create a group with cell name
724     int dset = openList6(parent, name.data(), g_SCILAB_CLASS_CELL);
725     //store cell dimensions
726     std::vector<int> dims = {1, data->getDims()};
727     int ret = writeIntegerMatrix6(dset, "__dims__", H5T_NATIVE_INT32, "32", 2, dims.data(), data->getDimsArray());
728     if (ret < 0)
729     {
730         return -1;
731     }
732
733     //create a node for fields references
734     int refs = openList6(dset, "__refs__", g_SCILAB_CLASS_CELL);
735     if (refs < 0)
736     {
737         return -1;
738     }
739
740     int size = data->getSize();
741     types::InternalType** it = data->get();
742     std::vector<hobj_ref_t> vrefs(size);
743     for (int i = 0; i < size; ++i)
744     {
745         std::string refname(std::to_string(i));
746         int ref = export_data(refs, refname, it[i]);
747     }
748
749
750     if (closeList6(refs) == -1)
751     {
752         return -1;
753     }
754
755     if (closeList6(dset) == -1)
756     {
757         return -1;
758     }
759
760     return dset;
761 }
762
763 static int export_handles(int parent, const std::string& name, types::GraphicHandle* data)
764 {
765     //create a group with cell name
766     int dset = openList6(parent, name.data(), g_SCILAB_CLASS_HANDLE);
767     //store cell dimensions
768     std::vector<int> dims = {1, data->getDims()};
769     int ret = writeIntegerMatrix6(dset, "__dims__", H5T_NATIVE_INT32, "32", 2, dims.data(), data->getDimsArray());
770     if (ret < 0)
771     {
772         return -1;
773     }
774
775     //create a node for fields references
776     int refs = openList6(dset, "__refs__", g_SCILAB_CLASS_HANDLE);
777     if (refs < 0)
778     {
779         closeList6(dset);
780         return -1;
781     }
782
783     int size = data->getSize();
784     long long* ll = data->get();
785     std::vector<hobj_ref_t> vrefs(size);
786     for (int i = 0; i < size; ++i)
787     {
788         //get handle uid
789         int hl = getObjectFromHandle(static_cast<long>(ll[i]));
790         std::string refname(std::to_string(i));
791         if (export_handle(refs, refname, hl) == false)
792         {
793             closeList6(refs);
794             closeList6(dset);
795             return -1;
796         }
797     }
798
799     closeList6(refs);
800     closeList6(dset);
801     return dset;
802 }
803
804 static int export_macro(int parent, const std::string& name, types::Macro* data)
805 {
806     int dims[2];
807
808     //create a group with macro name
809     int dset = openList6(parent, name.data(), g_SCILAB_CLASS_MACRO);
810
811     //inputs
812     std::vector<char*> inputNames;
813     auto inputs = data->getInputs();
814     for (auto& input : *inputs)
815     {
816         inputNames.push_back(wide_string_to_UTF8(input->getSymbol().getName().data()));
817     }
818
819     dims[0] = 1;
820     dims[1] = static_cast<int>(inputNames.size());
821     writeStringMatrix6(dset, "inputs", 2, dims, inputNames.data());
822
823     for (auto& in : inputNames)
824     {
825         FREE(in);
826     }
827
828     //outputs
829     std::vector<char*> outputNames;
830     auto outputs = data->getOutputs();
831     for (auto& output : *outputs)
832     {
833         outputNames.push_back(wide_string_to_UTF8(output->getSymbol().getName().data()));
834     }
835
836     dims[0] = 1;
837     dims[1] = static_cast<int>(outputNames.size());
838     writeStringMatrix6(dset, "outputs", 2, dims, outputNames.data());
839
840     for (auto& in : outputNames)
841     {
842         FREE(in);
843     }
844
845     //body
846     ast::Exp* pExp = data->getBody();
847     ast::SerializeVisitor serialMacro(pExp);
848
849     unsigned char* serialAst = serialMacro.serialize();
850     //size if the buffer ( unsigned int )
851     unsigned int size = *((unsigned int*)serialAst);
852
853     dims[0] = 1;
854     dims[1] = size;
855     writeIntegerMatrix6(dset, "body", H5T_NATIVE_UINT8, "u8", 2, dims, serialAst);
856     free(serialAst);
857
858     closeList6(dset);
859     return dset;
860 }
861
862 static int export_usertype(int parent, const std::string& name, types::UserType* data)
863 {
864     types::InternalType* it = data->save();
865     if (it == nullptr)
866     {
867         types::typed_list in;
868         in.push_back(data);
869
870         types::typed_list out;
871         //overload
872         ast::ExecVisitor exec;
873         // rational case
874         std::wstring wstFuncName = L"%" + data->getShortTypeStr() + L"_save";
875
876         try
877         {
878             types::Callable::ReturnValue ret = Overload::call(wstFuncName, in, 1, out, &exec);
879
880             if (ret != types::Callable::OK)
881             {
882                 return -1;
883             }
884
885             if (out.size() != 1)
886             {
887                 for (auto& i : out)
888                 {
889                     i->killMe();
890                 }
891                 return -1;
892             }
893
894             it = out[0];
895         }
896         catch (ast::ScilabError& /*se*/)
897         {
898             //overload does not exist
899             return -1;
900         }
901
902     }
903
904     if (it->isUserType())
905     {
906         it->killMe();
907         return -1;
908     }
909
910     //create a struct around "usertype" to be able to restore it.
911     types::Struct* str = new types::Struct(1, 1);
912     types::SingleStruct* ss = str->get()[0];
913
914     //add fields
915     ss->addField(L"type");
916     ss->addField(L"data");
917
918     //assign values to new fields
919     ss->set(L"type", new types::String(data->getShortTypeStr().data()));
920     ss->set(L"data", it);
921
922     int ret = export_struct(parent, name, str, g_SCILAB_CLASS_USERTYPE);
923
924     //protect data against delete
925     it->IncreaseRef();
926     delete str;
927     it->DecreaseRef();
928
929     return ret;
930 }