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