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