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