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