Bug fix #15302: Wrong load() calling sequence can crash Scilab
[scilab.git] / scilab / modules / hdf5 / sci_gateway / cpp / sci_hdf5_load_v3.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 #include <list>
16 #include <unordered_map>
17
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 "list.hxx"
27 #include "tlist.hxx"
28 #include "mlist.hxx"
29 #include "polynom.hxx"
30 #include "sparse.hxx"
31 #include "graphichandle.hxx"
32 #include "macro.hxx"
33 #include "void.hxx"
34 #include "listundefined.hxx"
35 #include "context.hxx"
36 #include "handle_properties.hxx"
37 #include "deserializervisitor.hxx"
38 #include "overload.hxx"
39
40 std::unordered_map<int, Links::PathList> Links::paths;
41
42 extern "C"
43 {
44 #include "sci_malloc.h"
45 #include "Scierror.h"
46 #include "localization.h"
47 #include "freeArrayOfString.h"
48 #include "os_string.h"
49 #include "deleteafile.h"
50 #include "expandPathVariable.h"
51 #include "h5_fileManagement.h"
52 #include "h5_writeDataToFile.h"
53 #include "h5_readDataFromFile.h"
54 #include "h5_attributeConstants.h"
55 #include "HandleManagement.h"
56
57 }
58 /*--------------------------------------------------------------------------*/
59 static bool import_variable(int file, std::string& name);
60 types::InternalType* import_data(int dataset);
61 static types::InternalType* import_double(int dataset);
62 static types::InternalType* import_string(int dataset);
63 static types::InternalType* import_boolean(int dataset);
64 static types::InternalType* import_int(int dataset);
65 static types::InternalType* import_list(int dataset, types::List* lst);
66 static types::InternalType* import_struct(int dataset);
67 static types::InternalType* import_poly(int dataset);
68 static types::InternalType* import_cell(int dataset);
69 static types::InternalType* import_handles(int dataset);
70 static types::InternalType* import_sparse(int dataset);
71 static types::InternalType* import_boolean_sparse(int dataset);
72 static types::InternalType* import_macro(int dataset);
73 static types::InternalType* import_usertype(int dataset);
74
75
76 /*--------------------------------------------------------------------------*/
77 static const std::string fname("load");
78 /*--------------------------------------------------------------------------*/
79 types::Function::ReturnValue sci_hdf5_load_v3(types::typed_list &in, int _iRetCount, types::typed_list &out)
80 {
81     std::string filename;
82     int rhs = static_cast<int>(in.size());
83
84     if (rhs < 1)
85     {
86         Scierror(999, _("%s: Wrong number of input argument(s): at least %d expected.\n"), fname.data(), 1);
87         return types::Function::Error;
88     }
89
90     if (in[0]->getId() != types::InternalType::IdScalarString)
91     {
92         Scierror(999, _("%s: Wrong size for input argument #%d: string expected.\n"), fname.data(), 1);
93         return types::Function::Error;
94     }
95
96     wchar_t* wfilename = expandPathVariableW(in[0]->getAs<types::String>()->get()[0]);
97     char* cfilename = wide_string_to_UTF8(wfilename);
98     filename = cfilename;
99     FREE(wfilename);
100     FREE(cfilename);
101
102     int iFile = openHDF5File(filename.data(), 0);
103     if (iFile < 0)
104     {
105         Scierror(999, _("%s: Unable to open file: %s\n"), fname.data(), filename.data());
106         return types::Function::Error;
107     }
108
109     //manage version information
110     int iVersion = getSODFormatAttribute(iFile);
111     if (iVersion != SOD_FILE_VERSION)
112     {
113         //close the file
114         closeHDF5File(iFile);
115         //can't read file with version newer that me !
116         Scierror(999, _("%s: Wrong SOD file format version. Expected: %d Found: %d\n"), fname.data(), SOD_FILE_VERSION, iVersion);
117         return types::Function::Error;
118     }
119
120     if (rhs > 1)
121     {
122         for (int i = 1; i < rhs; ++i)
123         {
124             std::string var;
125             char* cvar = wide_string_to_UTF8(in[i]->getAs<types::String>()->get()[0]);
126             var = cvar;
127             FREE(cvar);
128
129             if (import_variable(iFile, var) == false)
130             {
131                 //close the file
132                 closeHDF5File(iFile);
133                 Scierror(999, _("%s: Unable to load \'%s\'.\n"), fname.data(), var.data());
134                 return types::Function::Error;
135             }
136         }
137     }
138     else
139     {
140         //restore all variables
141         int iNbItem = 0;
142         iNbItem = getVariableNames6(iFile, NULL);
143         if (iNbItem != 0)
144         {
145             std::vector<char*> vars(iNbItem);
146             iNbItem = getVariableNames6(iFile, vars.data());
147             for (auto & var : vars)
148             {
149                 std::string s(var);
150                 FREE(var);
151                 if (import_variable(iFile, s) == false)
152                 {
153                     //close the file
154                     closeHDF5File(iFile);
155                     Scierror(999, _("%s: Unable to load \'%s\'.\n"), fname.data(), s.data());
156                     return types::Function::Error;
157                 }
158             }
159         }
160     }
161
162     //close the file
163     closeHDF5File(iFile);
164
165     out.push_back(new types::Bool(1));
166     return types::Function::OK;
167 }
168
169 static bool import_variable(int file, std::string& name)
170 {
171     int dataset = getDataSetIdFromName(file, name.data());
172     if (dataset <= 0)
173     {
174         return false;
175     }
176
177     types::InternalType* data = import_data(dataset);
178     if (data != nullptr)
179     {
180         wchar_t* var = to_wide_string(name.data());
181         //update macro name
182         if (data->isMacro())
183         {
184             types::Macro* macro = data->getAs<types::Macro>();
185             macro->setName(var);
186             symbol::Context::getInstance()->addMacro(macro);
187         }
188         else
189         {
190             //add to context
191             symbol::Context::getInstance()->put(symbol::Symbol(var), data);
192         }
193         FREE(var);
194         return true;
195     }
196
197     return false;
198 }
199
200 types::InternalType* import_data(int dataset)
201 {
202     //get var type
203     char* ctype = getScilabTypeFromDataSet6(dataset);
204     std::string type(ctype);
205     FREE(ctype);
206
207     if (type == g_SCILAB_CLASS_DOUBLE)
208     {
209         return import_double(dataset);
210     }
211
212     if (type == g_SCILAB_CLASS_STRING)
213     {
214         return import_string(dataset);
215     }
216
217     if (type == g_SCILAB_CLASS_INT)
218     {
219         return import_int(dataset);
220     }
221
222     if (type == g_SCILAB_CLASS_BOOLEAN)
223     {
224         return import_boolean(dataset);
225     }
226
227     if (type == g_SCILAB_CLASS_LIST)
228     {
229         return import_list(dataset, new types::List());
230     }
231
232     if (type == g_SCILAB_CLASS_TLIST)
233     {
234         return import_list(dataset, new types::TList());
235     }
236
237     if (type == g_SCILAB_CLASS_MLIST)
238     {
239         return import_list(dataset, new types::MList());
240     }
241
242     if (type == g_SCILAB_CLASS_STRUCT)
243     {
244         return import_struct(dataset);
245     }
246
247     if (type == g_SCILAB_CLASS_POLY)
248     {
249         return import_poly(dataset);
250     }
251
252     if (type == g_SCILAB_CLASS_SPARSE)
253     {
254         return import_sparse(dataset);
255     }
256
257     if (type == g_SCILAB_CLASS_BSPARSE)
258     {
259         return import_boolean_sparse(dataset);
260     }
261
262     if (type == g_SCILAB_CLASS_CELL)
263     {
264         return import_cell(dataset);
265     }
266
267     if (type == g_SCILAB_CLASS_HANDLE)
268     {
269         return import_handles(dataset);
270     }
271
272     if (type == g_SCILAB_CLASS_MACRO)
273     {
274         return import_macro(dataset);
275     }
276
277     if (type == g_SCILAB_CLASS_VOID)
278     {
279         closeDataSet(dataset);
280         return new types::Void();
281     }
282
283     if (type == g_SCILAB_CLASS_UNDEFINED)
284     {
285         closeDataSet(dataset);
286         return new types::ListUndefined();
287     }
288
289     if (type == g_SCILAB_CLASS_USERTYPE)
290     {
291         return import_usertype(dataset);
292     }
293
294
295     return nullptr;
296 }
297
298 static types::InternalType* import_double(int dataset)
299 {
300     int complex = 0;
301     int dims = 0;
302     int ret = getDatasetInfo(dataset, &complex, &dims, NULL);
303     if (ret < 0)
304     {
305         closeDataSet(dataset);
306         return nullptr;
307     }
308
309     std::vector<int> d(dims);
310     int size = getDatasetInfo(dataset, &complex, &dims, d.data());
311
312
313     if (dims == 0 || size <= 0)
314     {
315         closeDataSet(dataset);
316         return types::Double::Empty();
317     }
318
319     types::Double* dbl = new types::Double(dims, d.data(), complex == 1);
320
321     double* real = dbl->get();
322     double* img = dbl->getImg();
323
324     if (complex)
325     {
326         readDoubleComplexMatrix(dataset, real, img);
327     }
328     else
329     {
330         readDoubleMatrix(dataset, real);
331     }
332     return dbl;
333 }
334
335 static types::InternalType* import_string(int dataset)
336 {
337     int complex = 0;
338     int dims = 0;
339     int ret = getDatasetInfo(dataset, &complex, &dims, NULL);
340     if (ret < 0)
341     {
342         closeDataSet(dataset);
343         return nullptr;
344     }
345
346
347     std::vector<int> d(dims);
348     int size = getDatasetInfo(dataset, &complex, &dims, d.data());
349
350
351     if (dims == 0 || size <= 0)
352     {
353         closeDataSet(dataset);
354         return types::Double::Empty();
355     }
356
357     std::vector<char*> s(size);
358     ret = readStringMatrix(dataset, s.data());
359
360     types::String* str = new types::String(dims, d.data());
361     wchar_t** pstr = str->get();
362
363     for (int i = 0; i < size; ++i)
364     {
365         pstr[i] = to_wide_string(s[i]);
366     }
367
368     freeStringMatrix(dataset, s.data());
369
370     return str;
371 }
372
373 static types::InternalType* import_boolean(int dataset)
374 {
375     int complex = 0;
376     int dims = 0;
377     int ret = getDatasetInfo(dataset, &complex, &dims, NULL);
378     if (ret < 0)
379     {
380         closeDataSet(dataset);
381         return nullptr;
382     }
383
384     std::vector<int> d(dims);
385     int size = getDatasetInfo(dataset, &complex, &dims, d.data());
386
387
388     if (dims == 0 || size <= 0)
389     {
390         closeDataSet(dataset);
391         return types::Double::Empty();
392     }
393
394     types::Bool* bools = new types::Bool(dims, d.data());
395
396     int* b = bools->get();
397     readBooleanMatrix(dataset, b);
398     return bools;
399 }
400
401 static types::InternalType* import_int(int dataset)
402 {
403     types::InternalType* pOut = nullptr;
404     int complex = 0;
405     int dims = 0;
406     int ret = getDatasetInfo(dataset, &complex, &dims, NULL);
407     if (ret < 0)
408     {
409         closeDataSet(dataset);
410         return nullptr;
411     }
412
413     std::vector<int> d(dims);
414     int size = getDatasetInfo(dataset, &complex, &dims, d.data());
415
416
417     if (dims == 0 || size <= 0)
418     {
419         closeDataSet(dataset);
420         return types::Double::Empty();
421     }
422
423     int prec = 0;
424     ret = getDatasetPrecision(dataset, &prec);
425     if (ret != 0)
426     {
427         closeDataSet(dataset);
428         return nullptr;
429     }
430
431     switch (prec)
432     {
433         case SCI_INT8:
434         {
435             types::Int8* pi = new types::Int8(dims, d.data());
436             ret = readInteger8Matrix(dataset, pi->get());
437             pOut = pi;
438             break;
439         }
440         case SCI_INT16:
441         {
442             types::Int16* pi = new types::Int16(dims, d.data());
443             ret = readInteger16Matrix(dataset, pi->get());
444             pOut = pi;
445             break;
446         }
447         case SCI_INT32:
448         {
449             types::Int32* pi = new types::Int32(dims, d.data());
450             ret = readInteger32Matrix(dataset, pi->get());
451             pOut = pi;
452             break;
453         }
454         case SCI_INT64:
455         {
456             types::Int64* pi = new types::Int64(dims, d.data());
457             ret = readInteger64Matrix(dataset, pi->get());
458             pOut = pi;
459             break;
460         }
461         case SCI_UINT8:
462         {
463             types::UInt8* pi = new types::UInt8(dims, d.data());
464             ret = readUnsignedInteger8Matrix(dataset, pi->get());
465             pOut = pi;
466             break;
467         }
468         case SCI_UINT16:
469         {
470             types::UInt16* pi = new types::UInt16(dims, d.data());
471             ret = readUnsignedInteger16Matrix(dataset, pi->get());
472             pOut = pi;
473             break;
474         }
475         case SCI_UINT32:
476         {
477             types::UInt32* pi = new types::UInt32(dims, d.data());
478             ret = readUnsignedInteger32Matrix(dataset, pi->get());
479             pOut = pi;
480             break;
481         }
482         case SCI_UINT64:
483         {
484             types::UInt64* pi = new types::UInt64(dims, d.data());
485             ret = readUnsignedInteger64Matrix(dataset, pi->get());
486             pOut = pi;
487             break;
488         }
489         default:
490             return nullptr;
491             break;
492     }
493
494     return pOut;
495 }
496
497 static types::InternalType* import_list(int dataset, types::List* lst)
498 {
499     int count = 0;
500     int ret  = getListDims6(dataset, &count);
501     if (ret)
502     {
503         closeList6(dataset);
504         delete lst;
505         return nullptr;
506     }
507
508     if (count == 0)
509     {
510         closeList6(dataset);
511         return lst;
512     }
513
514     //get children
515
516     for (int i = 0; i < count; ++i)
517     {
518         int data = getDataSetIdFromName(dataset, std::to_string(i).data());
519         if (data <= 0)
520         {
521             closeList6(dataset);
522             delete lst;
523             return nullptr;
524         }
525
526         types::InternalType* child = import_data(data);
527         if (child == nullptr)
528         {
529             closeList6(dataset);
530             delete lst;
531             return nullptr;
532         }
533
534         lst->append(child);
535         if (child->isList())
536         {
537             child->killMe();
538         }
539     }
540
541     closeList6(dataset);
542     return lst;
543 }
544
545 static int getDimsNode(int dataset, int* complex, std::vector<int>& dims)
546 {
547     dims.clear();
548     int id = getDataSetIdFromName(dataset, "__dims__");
549     if (id < 0)
550     {
551         return 0;
552     }
553
554     //get dims dimension count
555     int dim = 0;
556     getDatasetInfo(id, complex, &dim, NULL);
557     //get dims dimension
558     std::vector<int> d(dim);
559     int size = getDatasetInfo(id, complex, &dim, d.data());
560     if (size < 0)
561     {
562         return 0;
563     }
564
565     //get dims value
566     dims.resize(size);
567     readInteger32Matrix(id, dims.data());
568
569     size = dims[0];
570     for (int i = 1; i < dims.size(); ++i)
571     {
572         size *= dims[i];
573     }
574     return size;
575 }
576
577 static types::InternalType* import_struct(int dataset)
578 {
579     //get struct dims node
580     int complex = 0;
581     std::vector<int> pdims;
582     int size = getDimsNode(dataset, &complex, pdims);
583
584     types::Struct* str = new types::Struct(static_cast<int>(pdims.size()), pdims.data());
585     size = str->getSize();
586     if (size == 0)
587     {
588         //empty struct
589         closeList6(dataset);
590         delete str;
591         return new types::Struct();
592     }
593
594     types::SingleStruct** sstr = str->get();
595
596     int fieldCount = 0;
597     int ret = getListDims6(dataset, &fieldCount);
598     if (ret < 0)
599     {
600         closeList6(dataset);
601         return str;
602     }
603
604     //get fields name
605     int dfield = getDataSetIdFromName(dataset, "__fields__");
606     int dim = 0;
607     getDatasetInfo(dfield, &complex, &dim, NULL);
608     std::vector<int> d(dim);
609     size = getDatasetInfo(dfield, &complex, &dim, d.data());
610     if (size < 0)
611     {
612         closeList6(dataset);
613         delete str;
614         return nullptr;
615     }
616
617     //get dims value
618     std::vector<char*> fields(size);
619     readStringMatrix(dfield, fields.data());
620
621     //open __refs__ node
622     int refs = getDataSetIdFromName(dataset, "__refs__");
623
624     for (const auto & name : fields)
625     {
626         wchar_t* field = to_wide_string(name);
627         str->addField(field);
628
629         int dataref = getDataSetIdFromName(dataset, name);
630         if (dataref < 0)
631         {
632             closeList6(dataset);
633             freeStringMatrix(dfield, fields.data());
634             FREE(field);
635             delete str;
636             return nullptr;
637         }
638
639         int refdim = 0;
640         getDatasetInfo(dataref, &complex, &refdim, NULL);
641         std::vector<int> refdims(refdim);
642         int refcount = getDatasetInfo(dataref, &complex, &refdim, refdims.data());
643         std::vector<hobj_ref_t> vrefs(refcount);
644         ret = H5Dread(dataref, H5T_STD_REF_OBJ, H5S_ALL, H5S_ALL, H5P_DEFAULT, vrefs.data());
645         if (ret < 0)
646         {
647             freeStringMatrix(dfield, fields.data());
648             FREE(field);
649             delete str;
650             return nullptr;
651         }
652
653
654         //import field
655         for (int j = 0; j < refcount; ++j)
656         {
657             int data = H5Rdereference(refs, H5R_OBJECT, &vrefs[j]);
658             if (data < 0)
659             {
660                 freeStringMatrix(dfield, fields.data());
661                 FREE(field);
662                 delete str;
663                 return nullptr;
664             }
665
666             types::InternalType* val = import_data(data);
667             if (val == nullptr)
668             {
669                 freeStringMatrix(dfield, fields.data());
670                 FREE(field);
671                 delete str;
672                 return nullptr;
673             }
674
675             sstr[j]->set(field, val);
676
677         }
678
679         FREE(field);
680         closeDataSet(dataref);
681     }
682
683     freeStringMatrix(dfield, fields.data());
684     closeList6(refs);
685     closeList6(dataset);
686     return str;
687 }
688
689 static types::InternalType* import_poly(int dataset)
690 {
691     //get poly dims node
692     int complex = 0;
693     std::vector<int> pdims;
694     int size = getDimsNode(dataset, &complex, pdims);
695
696     //get variable name
697     char* var = NULL;
698     int varname = getDataSetIdFromName(dataset, "__varname__");
699     readStringMatrix(varname, &var);
700     wchar_t* wvar = to_wide_string(var);
701     std::wstring wvarname(wvar);
702     FREE(wvar);
703     freeStringMatrix(varname, &var);
704
705     types::Polynom* p = new types::Polynom(wvarname, static_cast<int>(pdims.size()), pdims.data());
706     types::SinglePoly** pss = p->get();
707
708     //open __refs__ node
709     int refs = getDataSetIdFromName(dataset, "__refs__");
710     size = p->getSize();
711
712     //loop on children
713     for (int i = 0; i < size; ++i)
714     {
715         //forge name
716         std::string polyname(std::to_string(i));
717         int poly = getDataSetIdFromName(refs, polyname.data());
718
719         //get dims
720         complex = 0;
721         int dims = 0;
722         int ret = getDatasetInfo(poly, &complex, &dims, NULL);
723         if (ret < 0)
724         {
725             return nullptr;
726         }
727
728         std::vector<int> d(dims);
729         int datasize = getDatasetInfo(poly, &complex, &dims, d.data());
730
731         types::SinglePoly* ss = NULL;
732
733         //get coef
734         if (dims == 0 || datasize <= 0)
735         {
736             ss = new types::SinglePoly();
737         }
738         else if (complex)
739         {
740             double* real = NULL;
741             double* img = NULL;
742             //create singlepoly
743             ss = new types::SinglePoly(&real, &img, datasize - 1);
744             readDoubleComplexMatrix(poly, real, img);
745         }
746         else
747         {
748             double* real = NULL;
749             ss = new types::SinglePoly(&real, datasize - 1);
750             readDoubleMatrix(poly, real);
751         }
752
753         pss[i] = ss;
754     }
755
756     closeList6(refs);
757     closeList6(dataset);
758     return p;
759 }
760
761 static types::InternalType* import_sparse(int dataset)
762 {
763     types::Sparse* sp = nullptr;
764     //get sparse dimensions
765     int complex = 0;
766     std::vector<int> pdims;
767     int size = getDimsNode(dataset, &complex, pdims);
768
769     //get non zeros count
770     int nnz = 0;
771     int datannz = getDataSetIdFromName(dataset, "__nnz__");
772     readInteger32Matrix(datannz, &nnz);
773
774     if (nnz == 0)
775     {
776         closeList6(dataset);
777         return new types::Sparse(pdims[0], pdims[1]);
778     }
779
780     //get inner vector
781     int datain = getDataSetIdFromName(dataset, "__inner__");
782     int dimin = 0;
783     int sizein = getDatasetInfo(datain, &complex, &dimin, NULL);
784     std::vector<int> dimsin(dimin);
785     sizein = getDatasetInfo(datain, &complex, &dimin, dimsin.data());
786     if (sizein < 0)
787     {
788         closeList6(dataset);
789         return nullptr;
790     }
791
792     std::vector<int> in(sizein);
793     int ret = readInteger32Matrix(datain, in.data());
794     if (ret < 0)
795     {
796         closeList6(dataset);
797         return nullptr;
798     }
799
800     //get outer vector
801     int dataout = getDataSetIdFromName(dataset, "__outer__");
802     int dimout = 0;
803     int sizeout = getDatasetInfo(dataout, &complex, &dimout, NULL);
804     std::vector<int> dimsout(dimout);
805     sizeout = getDatasetInfo(dataout, &complex, &dimout, dimsout.data());
806     if (sizeout < 0)
807     {
808         closeList6(dataset);
809         return nullptr;
810     }
811
812     std::vector<int> out(sizeout);
813     ret = readInteger32Matrix(dataout, out.data());
814     if (ret < 0)
815     {
816         closeList6(dataset);
817         return nullptr;
818     }
819
820     //get data
821     int ddata = getDataSetIdFromName(dataset, "__data__");
822     int dimdata = 0;
823     int sizedata = getDatasetInfo(ddata, &complex, &dimdata, NULL);
824     std::vector<int> dimsdata(dimdata);
825     sizedata = getDatasetInfo(ddata, &complex, &dimdata, dimsdata.data());
826     if (sizedata < 0)
827     {
828         closeList6(dataset);
829         return nullptr;
830     }
831
832     std::vector<double> real(sizedata);
833
834     if (complex)
835     {
836         std::vector<double> img(sizedata);
837         ret = readDoubleComplexMatrix(ddata, real.data(), img.data());
838         if (ret < 0)
839         {
840             closeList6(dataset);
841             return nullptr;
842         }
843
844         sp = new types::Sparse(pdims[0], pdims[1], nnz, in.data(), out.data(), real.data(), img.data());
845     }
846     else
847     {
848         ret = readDoubleMatrix(ddata, real.data());
849         if (ret < 0)
850         {
851             closeList6(dataset);
852             return nullptr;
853         }
854
855         sp = new types::Sparse(pdims[0], pdims[1], nnz, in.data(), out.data(), real.data(), nullptr);
856     }
857
858     closeList6(dataset);
859     return sp;
860 }
861
862 static types::InternalType* import_boolean_sparse(int dataset)
863 {
864     //get sparse dimensions
865     int complex = 0;
866     std::vector<int> pdims;
867     int size = getDimsNode(dataset, &complex, pdims);
868
869     //get non zeros count
870     int nnz = 0;
871     int datannz = getDataSetIdFromName(dataset, "__nnz__");
872     readInteger32Matrix(datannz, &nnz);
873
874     if (nnz == 0)
875     {
876         closeList6(dataset);
877         return new types::SparseBool(pdims[0], pdims[1]);
878     }
879
880     //get inner vector
881     int datain = getDataSetIdFromName(dataset, "__inner__");
882     int dimin = 0;
883     int sizein = getDatasetInfo(datain, &complex, &dimin, NULL);
884     std::vector<int> dimsin(dimin);
885     sizein = getDatasetInfo(datain, &complex, &dimin, dimsin.data());
886     if (sizein < 0)
887     {
888         closeList6(dataset);
889         return nullptr;
890     }
891
892     std::vector<int> in(sizein);
893     int ret = readInteger32Matrix(datain, in.data());
894     if (ret < 0)
895     {
896         closeList6(dataset);
897         return nullptr;
898     }
899
900     //get outer vector
901     int dataout = getDataSetIdFromName(dataset, "__outer__");
902     int dimout = 0;
903     int sizeout = getDatasetInfo(dataout, &complex, &dimout, NULL);
904     std::vector<int> dimsout(dimout);
905     sizeout = getDatasetInfo(dataout, &complex, &dimout, dimsout.data());
906     if (sizeout < 0)
907     {
908         closeList6(dataset);
909         return nullptr;
910     }
911
912     std::vector<int> out(sizeout);
913     ret = readInteger32Matrix(dataout, out.data());
914     if (ret < 0)
915     {
916         closeList6(dataset);
917         return nullptr;
918     }
919
920     closeList6(dataset);
921
922     return new types::SparseBool(pdims[0], pdims[1], nnz, in.data(), out.data());
923 }
924
925 static types::InternalType* import_cell(int dataset)
926 {
927     //get sparse dimensions
928     int complex = 0;
929     std::vector<int> pdims;
930     int size = getDimsNode(dataset, &complex, pdims);
931
932     if (size == 0)
933     {
934         closeList6(dataset);
935         return new types::Cell();
936     }
937
938     //open __refs__ node
939     int refs = getDataSetIdFromName(dataset, "__refs__");
940     std::vector<types::InternalType*> data(size);
941     for (int i = 0; i < size; ++i)
942     {
943         int ref = getDataSetIdFromName(refs, std::to_string(i).data());
944         types::InternalType* val = import_data(ref);
945         if (val == nullptr)
946         {
947             return nullptr;
948         }
949
950         data[i] = val;
951     }
952
953     types::Cell* cell = new types::Cell(static_cast<int>(pdims.size()), pdims.data(), data.data());
954
955     closeList6(refs);
956     closeList6(dataset);
957     return cell;
958 }
959
960 static types::InternalType* import_handles(int dataset)
961 {
962     //get sparse dimensions
963     int complex = 0;
964     std::vector<int> pdims;
965     int size = getDimsNode(dataset, &complex, pdims);
966
967     if (size == 0)
968     {
969         closeList6(dataset);
970         return nullptr;
971     }
972
973     //open __refs__ node
974     int refs = getDataSetIdFromName(dataset, "__refs__");
975     types::GraphicHandle* handles = new types::GraphicHandle(static_cast<int>(pdims.size()), pdims.data());
976     long long* h = handles->get();
977
978     if (size == 1)
979     {
980         //%h_copy
981         int ref = getDataSetIdFromName(refs, std::to_string(0).data());
982         int val = add_current_entity(ref);
983         if (val < 0)
984         {
985             return nullptr;
986         }
987
988         h[0] = getHandle(val);
989     }
990     else
991     {
992         for (int i = 0; i < size; ++i)
993         {
994             int ref = getDataSetIdFromName(refs, std::to_string(i).data());
995             int val = import_handle(ref, -1);
996             if (val < 0)
997             {
998                 return nullptr;
999             }
1000
1001             h[i] = getHandle(val);
1002         }
1003     }
1004     closeList6(refs);
1005     closeList6(dataset);
1006
1007
1008     //update links property of legend handle
1009     if (Links::count())
1010     {
1011         std::list<int> legends = Links::legends();
1012         for (auto & i : legends)
1013         {
1014             Links::PathList paths = Links::get(i);
1015             update_link_path(i, paths);
1016         }
1017     }
1018
1019     return handles;
1020 }
1021
1022 static types::InternalType* import_macro(int dataset)
1023 {
1024     int complex = 0;
1025     int dims = 0;
1026     int size = 0;
1027     std::vector<int> d(2);
1028
1029     std::list<symbol::Variable*>* inputList = new std::list<symbol::Variable*>();
1030     std::list<symbol::Variable*>* outputList = new std::list<symbol::Variable*>();
1031     ast::Exp* body = nullptr;
1032
1033     symbol::Context* ctx = symbol::Context::getInstance();
1034
1035     //inputs
1036     int inputNode = getDataSetIdFromName(dataset, "inputs");
1037     size = getDatasetInfo(inputNode, &complex, &dims, d.data());
1038     if (size < 0)
1039     {
1040         delete inputList;
1041         delete outputList;
1042         closeList6(dataset);
1043         return nullptr;
1044     }
1045     std::vector<char*> inputNames(size);
1046
1047     if (size != 0)
1048     {
1049         readStringMatrix(inputNode, inputNames.data());
1050
1051         for (auto & input : inputNames)
1052         {
1053             wchar_t* winput = to_wide_string(input);
1054             symbol::Variable* var = ctx->getOrCreate(symbol::Symbol(winput));
1055             FREE(winput);
1056             inputList->push_back(var);
1057         }
1058
1059         freeStringMatrix(inputNode, inputNames.data());
1060     }
1061     else
1062     {
1063         closeDataSet(inputNode);
1064     }
1065
1066     //outputs
1067     int outputNode = getDataSetIdFromName(dataset, "outputs");
1068     size = getDatasetInfo(outputNode, &complex, &dims, d.data());
1069     if (size < 0)
1070     {
1071         delete inputList;
1072         delete outputList;
1073         closeList6(dataset);
1074         return nullptr;
1075     }
1076     std::vector<char*> outputNames(size);
1077
1078     if (size != 0)
1079     {
1080         readStringMatrix(outputNode, outputNames.data());
1081
1082         for (auto & output : outputNames)
1083         {
1084             wchar_t* woutput = to_wide_string(output);
1085             symbol::Variable* var = ctx->getOrCreate(symbol::Symbol(woutput));
1086             FREE(woutput);
1087             outputList->push_back(var);
1088         }
1089
1090         freeStringMatrix(outputNode, outputNames.data());
1091     }
1092     else
1093     {
1094         closeDataSet(outputNode);
1095     }
1096
1097     //body
1098     int bodyNode = getDataSetIdFromName(dataset, "body");
1099     size = getDatasetInfo(bodyNode, &complex, &dims, d.data());
1100     if (size < 0)
1101     {
1102         delete inputList;
1103         delete outputList;
1104         closeList6(dataset);
1105         return nullptr;
1106     }
1107     std::vector<unsigned char> bodybin(size);
1108     readUnsignedInteger8Matrix(bodyNode, bodybin.data());
1109
1110     ast::DeserializeVisitor ds(bodybin.data());
1111     body = ds.deserialize();
1112
1113     //wname+1 is to remove "/" at the start of the var name from HDF5
1114     types::Macro* macro = new types::Macro(L"", *inputList, *outputList, *body->getAs<ast::SeqExp>(), L"script");
1115     delete body;
1116     closeList6(dataset);
1117     return macro;
1118 }
1119
1120 static types::InternalType* import_usertype(int dataset)
1121 {
1122     types::InternalType* it = import_struct(dataset);
1123     if (it == nullptr || it->isStruct() == false)
1124     {
1125         delete it;
1126         return nullptr;
1127     }
1128
1129
1130     types::Struct* str = it->getAs<types::Struct>();
1131
1132     if (str->isScalar() == false)
1133     {
1134         delete it;
1135         return nullptr;
1136     }
1137
1138     types::SingleStruct* ss = str->get()[0];
1139
1140     //extract type from struct
1141     types::InternalType* itType  = ss->get(L"type");
1142     if (itType == nullptr || itType->getId() != types::InternalType::IdScalarString)
1143     {
1144         delete it;
1145         return nullptr;
1146     }
1147
1148     types::String* s = it->getAs<types::String>();
1149     wchar_t* type = s->get()[0];
1150
1151     types::InternalType* data = ss->get(L"data");
1152     if (data == nullptr)
1153     {
1154         delete it;
1155         return nullptr;
1156     }
1157
1158     //call %yourtype_load overload
1159     types::typed_list in;
1160     in.push_back(data);
1161
1162     types::typed_list out;
1163     //overload
1164     // rational case
1165     std::wstring wstFuncName = L"%" + data->getShortTypeStr() + L"_load";
1166     types::Callable::ReturnValue ret = Overload::call(wstFuncName, in, 1, out);
1167
1168     //clean temporary variables
1169     delete it; //included type and data
1170
1171     if (ret != types::Callable::OK)
1172     {
1173         return nullptr;
1174     }
1175
1176     if (out.size() != 1)
1177     {
1178         for (auto & i : out)
1179         {
1180             i->killMe();
1181         }
1182
1183         return nullptr;
1184     }
1185
1186     return out[0];
1187 }