0be60a2055f688307ea560621f159f48cf1d578f
[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     //save fields list in vector to keep order
466     export_string(dset, "__fields__", fields);
467
468
469     std::vector<hobj_ref_t> vrefs(size);
470     //fill main group with struct field name
471     for (int i = 0; i < fieldCount; ++i)
472     {
473         char* cfield = wide_string_to_UTF8(pfields[i]);
474         for (int j = 0; j < size; ++j)
475         {
476             //get data
477             types::InternalType* val = data->get(j)->get(pfields[i]);
478             //create ref name
479             std::string refname(cfield);
480             refname += "_" + std::to_string(j);
481             //export data in refs group
482             int ref = export_data(refs, refname, val);
483             //create reference of data
484             ret = addItemStruct6(refs, vrefs.data(), j, refname.data());
485             if (ret)
486             {
487                 return -1;
488             }
489         }
490
491         ret = writeStructField6(dset, cfield, data->getDims(), data->getDimsArray(), vrefs.data());
492         FREE(cfield);
493         if (ret < 0)
494         {
495             return -1;
496         }
497     }
498
499     if (closeList6(refs) == -1)
500     {
501         return -1;
502     }
503
504     if (closeList6(dset) == -1)
505     {
506         return -1;
507     }
508
509     return dset;
510 }
511 /*--------------------------------------------------------------------------*/
512 static int export_void(int parent, const std::string& name)
513 {
514     return writeVoid6(parent, name.data());
515 }
516 /*--------------------------------------------------------------------------*/
517 static int export_undefined(int parent, const std::string& name)
518 {
519     return writeUndefined6(parent, name.data());
520 }
521 /*--------------------------------------------------------------------------*/
522 static int export_poly(int parent, const std::string& name, types::Polynom* data)
523 {
524     //create a group with struct name
525     int dset = openList6(parent, name.data(), g_SCILAB_CLASS_POLY);
526     //store struct dimensions
527     std::vector<int> dims = {1, data->getDims()};
528     int ret = writeIntegerMatrix6(dset, "__dims__", H5T_NATIVE_INT32, "32", 2, dims.data(), data->getDimsArray());
529     if (ret < 0)
530     {
531         return -1;
532     }
533
534     //store variable name
535     std::vector<int> vardims = {1, 1};
536     char* varname = wide_string_to_UTF8(data->getVariableName().data());
537     ret = writeStringMatrix6(dset, "__varname__", 2, vardims.data(), &varname);
538     FREE(varname);
539     if (ret < 0)
540     {
541         return -1;
542     }
543
544     //create a node for fields references
545     int refs = openList6(dset, "__refs__", g_SCILAB_CLASS_POLY);
546     if (refs < 0)
547     {
548         return -1;
549     }
550
551     bool complex = data->isComplex();
552     int size = data->getSize();
553     std::vector<hobj_ref_t> vrefs(size);
554     types::SinglePoly** ss = data->get();
555     //fill main group with struct field name
556     for (int j = 0; j < size; ++j)
557     {
558         //get data
559         types::SinglePoly* val = ss[j];
560         //export data in refs group
561         std::vector<int> ssdims = {1, val->getSize()};
562         std::string polyname(std::to_string(j));
563         if (complex)
564         {
565             writeDoubleComplexMatrix6(refs, polyname.data(), 2, ssdims.data(), val->get(), val->getImg());
566         }
567         else
568         {
569             writeDoubleMatrix6(refs, polyname.data(), 2, ssdims.data(), val->get());
570         }
571
572         //create reference of data
573         ret = addItemStruct6(refs, vrefs.data(), j, polyname.data());
574         if (ret)
575         {
576             return -1;
577         }
578     }
579
580
581     if (closeList6(refs) == -1)
582     {
583         return -1;
584     }
585
586     if (closeList6(dset) == -1)
587     {
588         return -1;
589     }
590
591     return dset;
592 }
593 /*--------------------------------------------------------------------------*/
594 static int export_sparse(int parent, const std::string& name, types::Sparse* data)
595 {
596     int nnz = static_cast<int>(data->nonZeros());
597     int row = data->getRows();
598     //create a group with sparse name
599     int dset = openList6(parent, name.data(), g_SCILAB_CLASS_SPARSE);
600     //store sparse dimensions
601     std::vector<int> dims = {1, data->getDims()};
602     int ret = writeIntegerMatrix6(dset, "__dims__", H5T_NATIVE_INT32, "32", 2, dims.data(), data->getDimsArray());
603     if (ret < 0)
604     {
605         return -1;
606     }
607
608     //store numbers of non zero by rows.
609     std::vector<int> dimsnnz = {1, 1};
610     ret = writeIntegerMatrix6(dset, "__nnz__", H5T_NATIVE_INT32, "32", 2, dimsnnz.data(), &nnz);
611     if (ret < 0)
612     {
613         return -1;
614     }
615
616     //store inner vector
617     int innercount = 0;
618     int* inner = data->getInnerPtr(&innercount);
619     std::vector<int> dimsinner = {1, nnz};
620     ret = writeIntegerMatrix6(dset, "__inner__", H5T_NATIVE_INT32, "32", 2, dimsinner.data(), inner);
621     if (ret < 0)
622     {
623         return -1;
624     }
625
626     int outercount = 0;
627     int* outer = data->getOuterPtr(&outercount);
628     std::vector<int> dimsouter = {1, outercount + 1};
629     ret = writeIntegerMatrix6(dset, "__outer__", H5T_NATIVE_INT32, "32", 2, dimsouter.data(), outer);
630     if (ret < 0)
631     {
632         return -1;
633     }
634
635     if (data->isComplex())
636     {
637         double* real = new double[nnz];
638         double* img = new double[nnz];
639         std::complex<double>* d = data->getImg();
640         for (int i = 0; i < nnz; ++i)
641         {
642             real[i] = d[i].real();
643             img[i] = d[i].imag();
644         }
645
646
647         std::vector<int> dimsdata = {1, nnz};
648         ret = writeDoubleComplexMatrix6(dset, "__data__", 2, dimsdata.data(), real, img);
649         delete[] real;
650         delete[] img;
651         if (ret < 0)
652         {
653             return -1;
654         }
655     }
656     else
657     {
658         std::vector<int> dimsdata = {1, nnz};
659         ret = writeDoubleMatrix6(dset, "__data__", 2, dimsdata.data(), data->get());
660         if (ret < 0)
661         {
662             return -1;
663         }
664     }
665
666     if (closeList6(dset) == -1)
667     {
668         return -1;
669     }
670
671     return dset;
672
673 }
674 /*--------------------------------------------------------------------------*/
675 static int export_boolean_sparse(int parent, const std::string& name, types::SparseBool* data)
676 {
677     int nnz = static_cast<int>(data->nbTrue());
678     int row = data->getRows();
679     //create a group with sparse name
680     int dset = openList6(parent, name.data(), g_SCILAB_CLASS_BSPARSE);
681     //store sparse dimensions
682     std::vector<int> dims = {1, data->getDims()};
683     int ret = writeIntegerMatrix6(dset, "__dims__", H5T_NATIVE_INT32, "32", 2, dims.data(), data->getDimsArray());
684     if (ret < 0)
685     {
686         return -1;
687     }
688
689     //store numbers of non zero by rows.
690     std::vector<int> dimsnnz = {1, 1};
691     ret = writeIntegerMatrix6(dset, "__nnz__", H5T_NATIVE_INT32, "32", 2, dimsnnz.data(), &nnz);
692     if (ret < 0)
693     {
694         return -1;
695     }
696
697     //store inner vector
698     int innercount = 0;
699     int* inner = data->getInnerPtr(&innercount);
700     std::vector<int> dimsinner = {1, nnz};
701     ret = writeIntegerMatrix6(dset, "__inner__", H5T_NATIVE_INT32, "32", 2, dimsinner.data(), inner);
702     if (ret < 0)
703     {
704         return -1;
705     }
706
707     int outercount = 0;
708     int* outer = data->getOuterPtr(&outercount);
709     std::vector<int> dimsouter = {1, outercount + 1};
710     ret = writeIntegerMatrix6(dset, "__outer__", H5T_NATIVE_INT32, "32", 2, dimsouter.data(), outer);
711     if (ret < 0)
712     {
713         return -1;
714     }
715
716     if (closeList6(dset) == -1)
717     {
718         return -1;
719     }
720
721     return dset;
722 }
723 /*--------------------------------------------------------------------------*/
724 static int export_cell(int parent, const std::string& name, types::Cell* data)
725 {
726     //create a group with cell name
727     int dset = openList6(parent, name.data(), g_SCILAB_CLASS_CELL);
728     //store cell dimensions
729     std::vector<int> dims = {1, data->getDims()};
730     int ret = writeIntegerMatrix6(dset, "__dims__", H5T_NATIVE_INT32, "32", 2, dims.data(), data->getDimsArray());
731     if (ret < 0)
732     {
733         return -1;
734     }
735
736     //create a node for fields references
737     int refs = openList6(dset, "__refs__", g_SCILAB_CLASS_CELL);
738     if (refs < 0)
739     {
740         return -1;
741     }
742
743     int size = data->getSize();
744     types::InternalType** it = data->get();
745     std::vector<hobj_ref_t> vrefs(size);
746     for (int i = 0; i < size; ++i)
747     {
748         std::string refname(std::to_string(i));
749         int ref = export_data(refs, refname, it[i]);
750     }
751
752
753     if (closeList6(refs) == -1)
754     {
755         return -1;
756     }
757
758     if (closeList6(dset) == -1)
759     {
760         return -1;
761     }
762
763     return dset;
764 }
765
766 static int export_handles(int parent, const std::string& name, types::GraphicHandle* data)
767 {
768     //create a group with cell name
769     int dset = openList6(parent, name.data(), g_SCILAB_CLASS_HANDLE);
770     //store cell dimensions
771     std::vector<int> dims = {1, data->getDims()};
772     int ret = writeIntegerMatrix6(dset, "__dims__", H5T_NATIVE_INT32, "32", 2, dims.data(), data->getDimsArray());
773     if (ret < 0)
774     {
775         return -1;
776     }
777
778     //create a node for fields references
779     int refs = openList6(dset, "__refs__", g_SCILAB_CLASS_HANDLE);
780     if (refs < 0)
781     {
782         closeList6(dset);
783         return -1;
784     }
785
786     int size = data->getSize();
787     long long* ll = data->get();
788     std::vector<hobj_ref_t> vrefs(size);
789     for (int i = 0; i < size; ++i)
790     {
791         //get handle uid
792         int hl = getObjectFromHandle(static_cast<long>(ll[i]));
793         std::string refname(std::to_string(i));
794         if (export_handle(refs, refname, hl) == false)
795         {
796             closeList6(refs);
797             closeList6(dset);
798             return -1;
799         }
800     }
801
802     closeList6(refs);
803     closeList6(dset);
804     return dset;
805 }
806
807 static int export_macro(int parent, const std::string& name, types::Macro* data)
808 {
809     int dims[2];
810
811     //create a group with macro name
812     int dset = openList6(parent, name.data(), g_SCILAB_CLASS_MACRO);
813
814     //inputs
815     std::vector<char*> inputNames;
816     auto inputs = data->getInputs();
817     for (auto& input : *inputs)
818     {
819         inputNames.push_back(wide_string_to_UTF8(input->getSymbol().getName().data()));
820     }
821
822     dims[0] = 1;
823     dims[1] = static_cast<int>(inputNames.size());
824     writeStringMatrix6(dset, "inputs", 2, dims, inputNames.data());
825
826     for (auto& in : inputNames)
827     {
828         FREE(in);
829     }
830
831     //outputs
832     std::vector<char*> outputNames;
833     auto outputs = data->getOutputs();
834     for (auto& output : *outputs)
835     {
836         outputNames.push_back(wide_string_to_UTF8(output->getSymbol().getName().data()));
837     }
838
839     dims[0] = 1;
840     dims[1] = static_cast<int>(outputNames.size());
841     writeStringMatrix6(dset, "outputs", 2, dims, outputNames.data());
842
843     for (auto& in : outputNames)
844     {
845         FREE(in);
846     }
847
848     //body
849     ast::Exp* pExp = data->getBody();
850     ast::SerializeVisitor serialMacro(pExp);
851
852     unsigned char* serialAst = serialMacro.serialize();
853     //size if the buffer ( unsigned int )
854     unsigned int size = *((unsigned int*)serialAst);
855
856     dims[0] = 1;
857     dims[1] = size;
858     writeIntegerMatrix6(dset, "body", H5T_NATIVE_UINT8, "u8", 2, dims, serialAst);
859     free(serialAst);
860
861     closeList6(dset);
862     return dset;
863 }
864
865 static int export_usertype(int parent, const std::string& name, types::UserType* data)
866 {
867     types::InternalType* it = data->save();
868     if (it == nullptr)
869     {
870         types::typed_list in;
871         in.push_back(data);
872
873         types::typed_list out;
874         //overload
875         ast::ExecVisitor exec;
876         // rational case
877         std::wstring wstFuncName = L"%" + data->getShortTypeStr() + L"_save";
878
879         try
880         {
881             types::Callable::ReturnValue ret = Overload::call(wstFuncName, in, 1, out, &exec);
882
883             if (ret != types::Callable::OK)
884             {
885                 return -1;
886             }
887
888             if (out.size() != 1)
889             {
890                 for (auto& i : out)
891                 {
892                     i->killMe();
893                 }
894                 return -1;
895             }
896
897             it = out[0];
898         }
899         catch (ast::ScilabMessage& /*se*/)
900         {
901             //overload does not exist
902             return -1;
903         }
904
905     }
906
907     if (it->isUserType())
908     {
909         it->killMe();
910         return -1;
911     }
912
913     //create a struct around "usertype" to be able to restore it.
914     types::Struct* str = new types::Struct(1, 1);
915     types::SingleStruct* ss = str->get()[0];
916
917     //add fields
918     ss->addField(L"type");
919     ss->addField(L"data");
920
921     //assign values to new fields
922     ss->set(L"type", new types::String(data->getShortTypeStr().data()));
923     ss->set(L"data", it);
924
925     int ret = export_struct(parent, name, str, g_SCILAB_CLASS_USERTYPE);
926
927     //protect data against delete
928     it->IncreaseRef();
929     delete str;
930     it->DecreaseRef();
931
932     return ret;
933 }