Fix a compilation issue
[scilab.git] / scilab / modules / hdf5 / sci_gateway / cpp / sci_hdf5_listvar_v3.cpp
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2012 - DIGITEO - Antoine ELIAS
4 *
5 * This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution.  The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10 *
11 */
12
13 #include <vector>
14 #include "function.hxx"
15 #include "string.hxx"
16 #include "double.hxx"
17 #include "list.hxx"
18 #include "hdf5_gw.hxx"
19 #include "configvariable.hxx"
20
21 extern "C"
22 {
23 #include <hdf5.h>
24 #include "sci_types.h" //sci_matrix, sci_ints, ...
25 #include "sci_malloc.h"
26 #include "Scierror.h"
27 #include "localization.h"
28 #include "sciprint.h"
29 #include "h5_fileManagement.h"
30 #include "h5_readDataFromFile.h"
31 #include "h5_writeDataToFile.h"
32 #include "h5_attributeConstants.h"
33 #include "expandPathVariable.h"
34 }
35
36 typedef struct __VAR_INFO6__
37 {
38     char info[128];
39     std::string name;
40     std::string ctype;
41     int type;
42     int size;
43     int dims;
44     std::vector<int> pdims;
45 } VarInfo6;
46
47 static bool read_data(int dataset, VarInfo6& info);
48 static bool read_short_data(int dataset, VarInfo6& info);
49 static bool read_double(int dataset, VarInfo6& info);
50 static bool read_string(int dataset, VarInfo6& info);
51 static bool read_boolean(int dataset, VarInfo6& info);
52 static bool read_integer(int dataset, VarInfo6& info);
53 static bool read_sparse(int dataset, VarInfo6& info);
54 static bool read_boolean_sparse(int dataset, VarInfo6& info);
55 static bool read_poly(int dataset, VarInfo6& info);
56 static bool read_list(int dataset, VarInfo6& info, std::string type);
57 static bool read_void(int dataset, VarInfo6& info);
58 static bool read_undefined(int dataset, VarInfo6& info);
59 static bool read_struct(int dataset, VarInfo6& info);
60 static bool read_cell(int dataset, VarInfo6& info);
61 static bool read_handles(int dataset, VarInfo6& info);
62 static bool read_macro(int dataset, VarInfo6& info);
63
64 static void generateInfo(VarInfo6& info);
65 static int getDimsNode(int dataset, int* complex, std::vector<int>& dims);
66
67 static const std::string fname("hdf5_listvar");
68
69 types::Function::ReturnValue sci_hdf5_listvar_v3(types::typed_list &in, int _iRetCount, types::typed_list &out)
70 {
71     int rhs = static_cast<int>(in.size());
72     if (rhs != 1)
73     {
74         Scierror(999, _("%s: Wrong number of input argument(s): %d expected.\n"), fname.data(), 1);
75         return types::Function::Error;
76     }
77
78     if (_iRetCount < 1 && _iRetCount > 4)
79     {
80         Scierror(999, _("%s: Wrong number of output argument(s): %d to %d expected.\n"), fname.data(), 1, 4);
81         return types::Function::Error;
82     }
83
84     //get filename
85     if (in[0]->getId() != types::InternalType::IdScalarString)
86     {
87         Scierror(999, _("%s: Wrong size for input argument #%d: A string expected.\n"), fname.data(), 1);
88         return types::Function::Error;
89     }
90
91     //open hdf5 file
92     wchar_t* wfilename = expandPathVariableW(in[0]->getAs<types::String>()->get()[0]);
93     char* cfilename = wide_string_to_UTF8(wfilename);
94     std::string filename = cfilename;
95     FREE(wfilename);
96     FREE(cfilename);
97
98     int iFile = openHDF5File(filename.data(), 0);
99     if (iFile < 0)
100     {
101         Scierror(999, _("%s: Unable to open file: %s\n"), fname.data(), filename.data());
102         return types::Function::Error;
103     }
104
105     //manage version information
106     int iVersion = getSODFormatAttribute(iFile);
107     if (iVersion != SOD_FILE_VERSION)
108     {
109         //can't read file with version newer that me !
110         closeHDF5File(iFile);
111         Scierror(999, _("%s: Wrong SOD file format version. Max Expected: %d Found: %d\n"), fname.data(), SOD_FILE_VERSION, iVersion);
112         return types::Function::Error;
113     }
114
115     int items = getVariableNames6(iFile, nullptr);
116     std::vector<VarInfo6> info(items);
117     if (items != 0)
118     {
119         std::vector<char*> vars(items);
120         items = getVariableNames6(iFile, vars.data());
121
122         if (_iRetCount == 1)
123         {
124             sciprint("Name                     Type           Size            Bytes\n");
125             sciprint("-------------------------------------------------------------\n");
126         }
127
128         for (int i = 0; i < items; i++)
129         {
130             info[i].name = vars[i];
131             info[i].size = 0;
132
133             int dset = getDataSetIdFromName(iFile, vars[i]);
134             if (dset == 0)
135             {
136                 break;
137             }
138
139
140             if (_iRetCount != 2)
141             {
142                 if (read_data(dset, info[i]) == false)
143                 {
144                     break;
145                 }
146
147                 if (_iRetCount == 1)
148                 {
149                     sciprint("%s\n", info[i].info);
150                 }
151             }
152             else // == 2
153             {
154                 if (read_short_data(dset, info[i]) == false)
155                 {
156                     break;
157                 }
158             }
159         }
160     }
161     else
162     {
163         //no variable returms [] for each Lhs
164         for (int i = 0; i < _iRetCount; i++)
165         {
166             out.push_back(types::Double::Empty());
167         }
168
169         return types::Function::OK;
170     }
171
172     closeHDF5File(iFile);
173
174     //1st Lhs
175     types::String* out1 = new types::String(items, 1);
176     for (int i = 0; i < items; i++)
177     {
178         out1->set(i, info[i].name.data());
179     }
180
181     out.push_back(out1);
182
183     //2nd
184     if (_iRetCount > 1)
185     {
186         types::Double* out2 = new types::Double(items, 1);
187         double* pout2 = out2->get();
188         for (int i = 0; i < items; i++)
189         {
190             pout2[i] = info[i].type;
191         }
192
193         out.push_back(out2);
194     }
195
196     if (_iRetCount > 2)
197     {
198         //3rd Lhs
199         types::List* out3 = new types::List();
200         for (int i = 0; i < items; i++)
201         {
202             int dims = info[i].dims;
203             types::Double* item = new types::Double(1, dims);
204             double* pitem = item->get();
205             for (int j = 0; j < dims; j++)
206             {
207                 pitem[j] = static_cast<double>(info[i].pdims[j]);
208             }
209
210             out3->append(item);
211         }
212
213         out.push_back(out3);
214     }
215
216     if (_iRetCount > 3)
217     {
218         //4th Lhs
219         types::Double* out4 = new types::Double(items, 1);
220         double* pout4 = out4->get();
221         for (int i = 0; i < items; i++)
222         {
223             pout4[i] = info[i].size;
224         }
225
226         out.push_back(out4);
227     }
228
229     return types::Function::OK;
230 }
231
232 static bool read_short_data(int dataset, VarInfo6& info)
233 {
234     char* ctype = getScilabTypeFromDataSet6(dataset);
235     std::string type(ctype);
236     FREE(ctype);
237     info.ctype = type;
238
239     if (type == g_SCILAB_CLASS_DOUBLE)
240     {
241         info.type = sci_matrix;
242     }
243     else if (type == g_SCILAB_CLASS_STRING)
244     {
245         info.type = sci_strings;
246     }
247     else if (type == g_SCILAB_CLASS_LIST)
248     {
249         info.type = sci_list;
250     }
251     else if (type == g_SCILAB_CLASS_TLIST)
252     {
253         info.type = sci_tlist;
254     }
255     else if (type == g_SCILAB_CLASS_MLIST)
256     {
257         info.type = sci_mlist;
258     }
259     else if (type == g_SCILAB_CLASS_BOOLEAN)
260     {
261         info.type = sci_boolean;
262     }
263     else if (type == g_SCILAB_CLASS_POLY)
264     {
265         info.type = sci_poly;
266     }
267     else if (type == g_SCILAB_CLASS_INT)
268     {
269         info.type = sci_ints;
270     }
271     else if (type == g_SCILAB_CLASS_SPARSE)
272     {
273         info.type = sci_sparse;
274     }
275     else if (type == g_SCILAB_CLASS_BSPARSE)
276     {
277         info.type = sci_boolean_sparse;
278     }
279     else if (type == g_SCILAB_CLASS_VOID)
280     {
281         info.type = sci_void;
282     }
283     else if (type == g_SCILAB_CLASS_UNDEFINED)
284     {
285         info.type = sci_undefined;
286     }
287     else if (type == g_SCILAB_CLASS_STRUCT)
288     {
289         info.type = sci_mlist;
290     }
291     else if (type == g_SCILAB_CLASS_CELL)
292     {
293         info.type = sci_mlist;
294     }
295     else if (type == g_SCILAB_CLASS_HANDLE)
296     {
297         info.type = sci_handles;
298     }
299     else if (type == g_SCILAB_CLASS_MACRO)
300     {
301         info.type = sci_c_function;
302     }
303     else if (type == g_SCILAB_CLASS_USERTYPE)
304     {
305         info.type = sci_pointer;
306     }
307     else
308     {
309         Scierror(999, _("%s: Invalid HDF5 Scilab format.\n"), "listvar_in_hdf5");
310         return false;
311     }
312
313     return true;
314 }
315
316 static bool read_data(int dataset, VarInfo6& info)
317 {
318     bool bRet = false;
319
320     char* ctype = getScilabTypeFromDataSet6(dataset);
321     std::string type(ctype);
322     FREE(ctype);
323     info.ctype = type;
324
325     if (type == g_SCILAB_CLASS_DOUBLE)
326     {
327         info.type = sci_matrix;
328         return read_double(dataset, info);
329     }
330
331     if (type == g_SCILAB_CLASS_STRING)
332     {
333         info.type = sci_strings;
334         return read_string(dataset, info);
335     }
336
337     if (type == g_SCILAB_CLASS_LIST)
338     {
339         info.type = sci_list;
340         return read_list(dataset, info, "list");
341     }
342
343     if (type == g_SCILAB_CLASS_TLIST)
344     {
345         info.type = sci_tlist;
346         return read_list(dataset, info, "tlist");
347     }
348
349     if (type == g_SCILAB_CLASS_MLIST)
350     {
351         info.type = sci_mlist;
352         return read_list(dataset, info, "mlist");
353     }
354
355     if (type == g_SCILAB_CLASS_BOOLEAN)
356     {
357         info.type = sci_boolean;
358         return read_boolean(dataset, info);
359     }
360
361     if (type == g_SCILAB_CLASS_POLY)
362     {
363         info.type = sci_poly;
364         return read_poly(dataset, info);
365     }
366
367     if (type == g_SCILAB_CLASS_INT)
368     {
369         info.type = sci_ints;
370         return read_integer(dataset, info);
371     }
372
373     if (type == g_SCILAB_CLASS_SPARSE)
374     {
375         info.type = sci_sparse;
376         return read_sparse(dataset, info);
377     }
378
379     if (type == g_SCILAB_CLASS_BSPARSE)
380     {
381         info.type = sci_boolean_sparse;
382         return read_boolean_sparse(dataset, info);
383     }
384
385     if (type == g_SCILAB_CLASS_VOID)
386     {
387         info.type = sci_void;
388         return read_void(dataset, info);
389     }
390
391     if (type == g_SCILAB_CLASS_UNDEFINED)
392     {
393         info.type = sci_undefined;
394         return read_undefined(dataset, info);
395     }
396
397     if (type == g_SCILAB_CLASS_STRUCT)
398     {
399         info.type = sci_mlist;
400         return read_struct(dataset, info);
401     }
402
403     if (type == g_SCILAB_CLASS_CELL)
404     {
405         info.type = sci_mlist;
406         return read_cell(dataset, info);
407     }
408
409     if (type == g_SCILAB_CLASS_HANDLE)
410     {
411         info.type = sci_handles;
412         return read_handles(dataset, info);
413     }
414
415     if (type == g_SCILAB_CLASS_MACRO)
416     {
417         info.type = sci_c_function;
418         return read_macro(dataset, info);
419     }
420
421     Scierror(999, _("%s: Invalid HDF5 Scilab format.\n"), "listvar_in_hdf5");
422     return false;
423 }
424
425 static bool read_double(int dataset, VarInfo6& info)
426 {
427     int complex = 0;
428     int ret = getDatasetInfo(dataset, &complex, &info.dims, NULL);
429     if (ret < 0)
430     {
431         closeDataSet(dataset);
432         return false;
433     }
434
435     info.pdims.resize(info.dims);
436     int size = getDatasetInfo(dataset, &complex, &info.dims, info.pdims.data());
437     info.size = size * (complex + 1) * sizeof(double);
438
439     generateInfo(info);
440     closeDataSet(dataset);
441     return true;
442 }
443
444 static bool read_string(int dataset, VarInfo6& info)
445 {
446     int complex = 0;
447     int ret = getDatasetInfo(dataset, &complex, &info.dims, NULL);
448     if (ret < 0)
449     {
450         closeDataSet(dataset);
451         return false;
452     }
453
454     info.pdims.resize(info.dims);
455     int size = getDatasetInfo(dataset, &complex, &info.dims, info.pdims.data());
456
457     std::vector<char*> str(size);
458     ret = readStringMatrix(dataset, str.data());
459
460     for (int i = 0; i < size; i++)
461     {
462         info.size += (int)strlen(str[i]) * sizeof(wchar_t);
463     }
464
465     freeStringMatrix(dataset, str.data());
466
467     generateInfo(info);
468     return true;
469 }
470
471 static bool read_boolean(int dataset, VarInfo6& info)
472 {
473     int complex = 0;
474     int ret = getDatasetInfo(dataset, &complex, &info.dims, NULL);
475     if (ret < 0)
476     {
477         closeDataSet(dataset);
478         return false;
479     }
480
481     info.pdims.resize(info.dims);
482     int size = getDatasetInfo(dataset, &complex, &info.dims, info.pdims.data());
483     info.size = size * sizeof(int);
484
485     generateInfo(info);
486     closeDataSet(dataset);
487     return true;
488 }
489
490 static bool read_integer(int dataset, VarInfo6& info)
491 {
492     int complex = 0;
493     int ret = getDatasetInfo(dataset, &complex, &info.dims, NULL);
494     if (ret < 0)
495     {
496         closeDataSet(dataset);
497         return false;
498     }
499
500     info.pdims.resize(info.dims);
501     int size = getDatasetInfo(dataset, &complex, &info.dims, info.pdims.data());
502
503     int prec = 0;
504     getDatasetPrecision(dataset, &prec);
505
506     info.size = size * (prec % 10);
507
508     generateInfo(info);
509     closeDataSet(dataset);
510     return true;
511 }
512
513 static bool read_sparse(int dataset, VarInfo6& info)
514 {
515     int complex = 0;
516     std::vector<int> pdims;
517     int size = getDimsNode(dataset, &complex, pdims);
518
519     //get non zeros count
520     int nnz = 0;
521     int datannz = getDataSetIdFromName(dataset, "__nnz__");
522     readInteger32Matrix(datannz, &nnz);
523
524     info.dims = 2;
525     info.pdims.resize(2);
526     info.pdims[0] = pdims[0];
527     info.pdims[1] = pdims[1];
528     //nnz(double) + rows(int) + nnz(int)
529     info.size = sizeof(double) * nnz * (complex + 1) + info.pdims[0] * sizeof(int) + nnz * sizeof(int);
530
531     generateInfo(info);
532     closeList6(dataset);
533     return true;
534 }
535
536 static bool read_boolean_sparse(int dataset, VarInfo6& info)
537 {
538     int complex = 0;
539     std::vector<int> pdims;
540     int size = getDimsNode(dataset, &complex, pdims);
541
542     //get non zeros count
543     int nnz = 0;
544     int datannz = getDataSetIdFromName(dataset, "__nnz__");
545     readInteger32Matrix(datannz, &nnz);
546
547     info.dims = 2;
548     info.pdims[0] = pdims[0];
549     info.pdims[1] = pdims[1];
550     //rows(int) + nnz(int)
551     info.size = info.pdims[0] * sizeof(int) + nnz * sizeof(int);
552
553     generateInfo(info);
554     closeList6(dataset);
555     return true;
556 }
557
558 static bool read_poly(int dataset, VarInfo6& info)
559 {
560     int complex = 0;
561     int size = getDimsNode(dataset, &complex, info.pdims);
562     info.size = 0;
563
564     //open __refs__ node
565     int refs = getDataSetIdFromName(dataset, "__refs__");
566
567     for (int i = 0; i < size; ++i)
568     {
569         std::string polyname(std::to_string(i));
570         int poly = getDataSetIdFromName(refs, polyname.data());
571
572         //get dims
573         complex = 0;
574         int dims = 0;
575         int ret = getDatasetInfo(poly, &complex, &dims, NULL);
576         if (ret < 0)
577         {
578             return false;
579         }
580
581         std::vector<int> d(dims);
582         int datasize = getDatasetInfo(poly, &complex, &dims, d.data());
583         info.size += datasize * sizeof(double) * (complex + 1);
584     }
585
586     closeList6(refs);
587     closeList6(dataset);
588
589     generateInfo(info);
590     return true;
591 }
592
593 static bool read_list(int dataset, VarInfo6& info, std::string type)
594 {
595     int ret = 0;
596     int items = 0;
597
598     ret = getListDims6(dataset, &items);
599     if (ret)
600     {
601         return false;
602     }
603
604     info.dims = 1;
605     info.pdims.resize(1);
606     info.pdims[0] = items;
607     info.size = 0;
608
609     for (int i = 0; i < items; i++)
610     {
611         int data = getDataSetIdFromName(dataset, std::to_string(i).data());
612         if (data <= 0)
613         {
614             closeList6(dataset);
615             return false;
616         }
617
618
619         VarInfo6 info2;
620         bool bRet = read_data(data, info2);
621         if (bRet == false)
622         {
623             return false;
624         }
625
626         info.size += info2.size;
627     }
628
629     closeList6(dataset);
630     generateInfo(info);
631     return true;
632 }
633
634 static bool read_void(int dataset, VarInfo6& info)
635 {
636     info.size = 0;
637     closeDataSet(dataset);
638     return true;
639 }
640
641 static bool read_undefined(int dataset, VarInfo6& info)
642 {
643     info.size = 0;
644     closeDataSet(dataset);
645     return true;
646 }
647
648 static bool read_struct(int dataset, VarInfo6& info)
649 {
650     int complex = 0;
651     int size = getDimsNode(dataset, &complex, info.pdims);
652     info.dims = static_cast<int>(info.pdims.size());
653     info.size = 0;
654
655     if (size == 0)
656     {
657         generateInfo(info);
658         closeList6(dataset);
659         return true;
660     }
661     int fieldCount = 0;
662     int ret = getListDims6(dataset, &fieldCount);
663     if (ret < 0)
664     {
665         closeList6(dataset);
666         return false;
667     }
668
669     //open __refs__ node
670     int refs = getDataSetIdFromName(dataset, "__refs__");
671     H5O_info_t oinfo;
672     for (int i = 0; i < fieldCount; ++i)
673     {
674         H5Oget_info_by_idx(dataset, ".", H5_INDEX_NAME, H5_ITER_NATIVE, i, &oinfo, H5P_DEFAULT);
675         ssize_t len = H5Lget_name_by_idx(dataset, ".", H5_INDEX_NAME, H5_ITER_INC, i, 0, 0, H5P_DEFAULT) + 1;
676         char* name = (char*)MALLOC(sizeof(char) * len);
677         H5Lget_name_by_idx(dataset, ".", H5_INDEX_NAME, H5_ITER_INC, i, name, len, H5P_DEFAULT);
678         std::string cname(name);
679         FREE(name);
680
681         if (cname != "__dims__" && cname != "__refs__")
682         {
683             int dataref = getDataSetIdFromName(dataset, cname.data());
684             if (dataref < 0)
685             {
686                 closeList6(dataset);
687                 return false;
688             }
689
690             int refdim = 0;
691             getDatasetInfo(dataref, &complex, &refdim, NULL);
692             std::vector<int> refdims(refdim);
693             int refcount = getDatasetInfo(dataref, &complex, &refdim, refdims.data());
694             std::vector<hobj_ref_t> vrefs(refcount);
695             ret = H5Dread(dataref, H5T_STD_REF_OBJ, H5S_ALL, H5S_ALL, H5P_DEFAULT, vrefs.data());
696             if (ret < 0)
697             {
698                 return false;
699             }
700
701
702             //import field
703             for (int j = 0; j < refcount; ++j)
704             {
705                 int data = H5Rdereference(refs, H5R_OBJECT, &vrefs[j]);
706                 if (data < 0)
707                 {
708                     return false;
709                 }
710
711                 VarInfo6 info2;
712                 ret = read_data(data, info2);
713                 if (ret == false)
714                 {
715                     return false;
716                 }
717
718                 info.size += info2.size;
719
720             }
721
722             closeDataSet(dataref);
723         }
724     }
725
726     generateInfo(info);
727     closeList6(refs);
728     closeList6(dataset);
729     return true;
730 }
731
732 static bool read_cell(int dataset, VarInfo6& info)
733 {
734     //get cell dimensions
735     int complex = 0;
736     int size = getDimsNode(dataset, &complex, info.pdims);
737     info.dims = static_cast<int>(info.pdims.size());
738
739     if (size == 0)
740     {
741         info.size = 0;
742         generateInfo(info);
743         closeList6(dataset);
744         return true;
745     }
746
747     //open __refs__ node
748     int refs = getDataSetIdFromName(dataset, "__refs__");
749     for (int i = 0; i < size; ++i)
750     {
751         int ref = getDataSetIdFromName(refs, std::to_string(i).data());
752         VarInfo6 info2;
753         if (read_data(ref, info2) == false)
754         {
755             closeList6(refs);
756             closeList6(dataset);
757             return false;
758         }
759
760         info.size += info2.size;
761     }
762
763     closeList6(refs);
764     closeList6(dataset);
765
766     generateInfo(info);
767     return true;
768 }
769
770 static bool read_handles(int dataset, VarInfo6& info)
771 {
772     //get cell dimensions
773     int complex = 0;
774     int size = getDimsNode(dataset, &complex, info.pdims);
775     info.dims = static_cast<int>(info.pdims.size());
776
777     if (size == 0)
778     {
779         info.size = 0;
780         generateInfo(info);
781         closeList6(dataset);
782         return true;
783     }
784
785     closeList6(dataset);
786
787     generateInfo(info);
788     return true;
789 }
790
791 static bool read_macro(int dataset, VarInfo6& info)
792 {
793     info.size = 0;
794     info.dims = 2;
795     info.pdims = {1, 1};
796     closeList6(dataset);
797     generateInfo(info);
798     return true;
799 }
800
801
802 static void generateInfo(VarInfo6& info)
803 {
804     std::ostringstream ostr;
805
806     if (info.dims != 0)
807     {
808         ostr << info.pdims[0];
809         for (int i = 1; i < info.dims; ++i)
810         {
811             ostr << " by " << info.pdims[i];
812         }
813     }
814
815     sprintf(info.info, "%-*s%-*s%-*s%-*d", 25, info.name.data(), 15, info.ctype.data(), 16, ostr.str().data(), 10, info.size);
816 }
817
818 static int getDimsNode(int dataset, int* complex, std::vector<int>& dims)
819 {
820     dims.clear();
821     int id = getDataSetIdFromName(dataset, "__dims__");
822     if (id < 0)
823     {
824         return 0;
825     }
826
827     //get dims dimension count
828     int dim = 0;
829     getDatasetInfo(id, complex, &dim, NULL);
830     //get dims dimension
831     std::vector<int> d(dim);
832     int size = getDatasetInfo(id, complex, &dim, d.data());
833
834     //get dims value
835     dims.resize(size);
836     readInteger32Matrix(id, dims.data());
837
838     size = dims[0];
839     for (int i = 1; i < dims.size(); ++i)
840     {
841         size *= dims[i];
842     }
843     return size;
844 }
845