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