fix hdf5 locked file by listvar_in_hdf5 and import_from_hdf5 functions
[scilab.git] / scilab / modules / hdf5 / sci_gateway / cpp / sci_listvar_in_hdf5.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-en.txt
10 *
11 */
12
13 #include <hdf5.h>
14 extern "C"
15 {
16 #include <string.h>
17 #include "gw_hdf5.h"
18 #include "MALLOC.h"
19 #include "Scierror.h"
20 #include "localization.h"
21 #include "sciprint.h"
22 #include "api_scilab.h"
23 #include "../../../call_scilab/includes/call_scilab.h"
24 #include "h5_fileManagement.h"
25 #include "h5_readDataFromFile.h"
26 #include "h5_attributeConstants.h"
27 #include "expandPathVariable.h"
28 }
29
30 #include "listvar_in_hdf5_v1.hxx"
31 #include <vector>
32
33 typedef struct __VAR_INFO__
34 {
35     char pstInfo[128];
36     char varName[128];
37     int iType;
38     int iSize;
39     int iDims;
40     int piDims[2];
41
42     __VAR_INFO__() : iType(0), iSize(0), iDims(0) {}
43 } VarInfo;
44
45 static bool read_data(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo);
46 static bool read_double(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo);
47 static bool read_string(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo);
48 static bool read_boolean(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo);
49 static bool read_integer(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo);
50 static bool read_sparse(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo);
51 static bool read_boolean_sparse(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo);
52 static bool read_poly(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo);
53 static bool read_list(int _iDatasetId, int _iVarType, int _iItemPos, int *_piAddress, VarInfo* _pInfo);
54 static bool read_void(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo);
55 static bool read_undefined(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo);
56
57 static void generateInfo(VarInfo* _pInfo, const char* _pstType);
58
59 int sci_listvar_in_hdf5(char *fname, unsigned long fname_len)
60 {
61     SciErr sciErr;
62     int *piAddr     = NULL;
63     char* pstFile   = NULL;
64     int iFile       = 0;
65     int iNbItem     = 0;
66     VarInfo* pInfo  = NULL;
67
68     CheckRhs(1, 1);
69     CheckLhs(1, 4);
70
71     sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr);
72     if (sciErr.iErr)
73     {
74         printError(&sciErr, 0);
75         return 1;
76     }
77
78     if (getAllocatedSingleString(pvApiCtx, piAddr, &pstFile))
79     {
80         Scierror(999, _("%s: Wrong size for input argument #%d: A string expected.\n"), fname, 1);
81         return 1;
82     }
83
84     char* pstFileName = expandPathVariable(pstFile);
85     iFile = openHDF5File(pstFileName, 0);
86     if (iFile < 0)
87     {
88         Scierror(999, _("%s: Unable to open file: %s\n"), fname, pstFile);
89         FREE(pstFileName);
90         FREE(pstFile);
91         return 1;
92     }
93
94     FREE(pstFileName);
95     FREE(pstFile);
96
97     //manage version information
98     int iVersion = getSODFormatAttribute(iFile);
99     if (iVersion != SOD_FILE_VERSION)
100     {
101         if (iVersion > SOD_FILE_VERSION)
102         {
103             //can't read file with version newer that me !
104             closeHDF5File(iFile);
105             Scierror(999, _("%s: Wrong SOD file format version. Max Expected: %d Found: %d\n"), fname, SOD_FILE_VERSION, iVersion);
106             return 1;
107         }
108         else
109         {
110             //call older import functions and exit or ... EXIT !
111             if (iVersion == 1 || iVersion == -1)
112             {
113                 //sciprint("old sci_listvar_in_hdf5_v1\n");
114                 return sci_listvar_in_hdf5_v1(fname, fname_len);
115             }
116         }
117     }
118
119     iNbItem = getVariableNames(iFile, NULL);
120     if (iNbItem != 0)
121     {
122         char** pstVarNameList = (char**)MALLOC(sizeof(char*) * iNbItem);
123         pInfo = (VarInfo*)MALLOC(iNbItem * sizeof(VarInfo));
124         int b;
125
126         if (Lhs == 1)
127         {
128             sciprint("Name                     Type           Size            Bytes\n");
129             sciprint("---------------------------------------------------------------\n");
130         }
131
132         iNbItem = getVariableNames(iFile, pstVarNameList);
133         for (int i = 0; i < iNbItem; i++)
134         {
135             int iDataSetId = getDataSetIdFromName(iFile, pstVarNameList[i]);
136             if (iDataSetId == 0)
137             {
138                 break;
139             }
140
141             strcpy(pInfo[i].varName, pstVarNameList[i]);
142             FREE(pstVarNameList[i]);
143             b = read_data(iDataSetId, 0, NULL, &pInfo[i]) == false;
144             if (b)
145             {
146                 break;
147             }
148
149             if (Lhs == 1)
150             {
151                 sciprint("%s\n", pInfo[i].pstInfo);
152             }
153         }
154     }
155     else
156     {
157         //no variable returms [] for each Lhs
158         for (int i = 0 ; i < Lhs ; i++)
159         {
160             createEmptyMatrix(pvApiCtx, Rhs + i + 1);
161             LhsVar(i + 1) = Rhs + i + 1;
162         }
163
164         PutLhsVar();
165         return 0;
166     }
167
168     closeHDF5File(iFile);
169
170     //1st Lhs
171     char** pstVarName = (char**)MALLOC(sizeof(char*) * iNbItem);
172     for (int i = 0 ; i < iNbItem ; i++)
173     {
174         pstVarName[i] = pInfo[i].varName;
175     }
176
177     sciErr = createMatrixOfString(pvApiCtx, Rhs + 1, iNbItem, 1, pstVarName);
178     FREE(pstVarName);
179     if (sciErr.iErr)
180     {
181         printError(&sciErr, 0);
182         return 1;
183     }
184
185     LhsVar(1) = Rhs + 1;
186
187     if (Lhs > 1)
188     {
189         //2nd Lhs
190         double* pdblType;
191         sciErr = allocMatrixOfDouble(pvApiCtx, Rhs + 2, iNbItem, 1, &pdblType);
192         if (sciErr.iErr)
193         {
194             printError(&sciErr, 0);
195             return 1;
196         }
197
198         for (int i = 0 ; i < iNbItem ; i++)
199         {
200             pdblType[i] = pInfo[i].iType;
201         }
202
203         LhsVar(2) = Rhs + 2;
204
205         if (Lhs > 2)
206         {
207             //3rd Lhs
208             int* pList = NULL;
209             sciErr = createList(pvApiCtx, Rhs + 3, iNbItem, &pList);
210             for (int i = 0 ; i < iNbItem ; i++)
211             {
212                 double* pdblDims = NULL;
213                 allocMatrixOfDoubleInList(pvApiCtx, Rhs + 3, pList, i + 1, 1, pInfo[i].iDims, &pdblDims);
214                 for (int j = 0 ; j < pInfo[i].iDims ; j++)
215                 {
216                     pdblDims[j] = pInfo[i].piDims[j];
217                 }
218             }
219
220             LhsVar(3) = Rhs + 3;
221         }
222
223         if (Lhs > 3)
224         {
225             //4th Lhs
226             double* pdblSize;
227             sciErr = allocMatrixOfDouble(pvApiCtx, Rhs + 4, iNbItem, 1, &pdblSize);
228             for (int i = 0 ; i < iNbItem ; i++)
229             {
230                 pdblSize[i] = pInfo[i].iSize;
231             }
232
233             LhsVar(4) = Rhs + 4;
234         }
235
236     }
237
238     FREE(pInfo);
239     PutLhsVar();
240     return 0;
241 }
242
243 static bool read_data(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo)
244 {
245     bool bRet = false;
246
247     _pInfo->iType = getScilabTypeFromDataSet(_iDatasetId);
248     switch (_pInfo->iType)
249     {
250         case sci_matrix:
251         {
252             bRet = read_double(_iDatasetId, _iItemPos, _piAddress, _pInfo);
253             break;
254         }
255         case sci_strings:
256         {
257             bRet = read_string(_iDatasetId, _iItemPos, _piAddress, _pInfo);
258             break;
259         }
260         case sci_list:
261         case sci_tlist:
262         case sci_mlist:
263         {
264             bRet = read_list(_iDatasetId, _pInfo->iType, _iItemPos, _piAddress, _pInfo);
265             break;
266         }
267         case sci_boolean:
268         {
269             bRet = read_boolean(_iDatasetId, _iItemPos, _piAddress, _pInfo);
270             break;
271         }
272         case sci_poly:
273         {
274             bRet = read_poly(_iDatasetId, _iItemPos, _piAddress, _pInfo);
275             break;
276         }
277         case sci_ints:
278         {
279             bRet = read_integer(_iDatasetId, _iItemPos, _piAddress, _pInfo);
280             break;
281         }
282         case sci_sparse:
283         {
284             bRet = read_sparse(_iDatasetId, _iItemPos, _piAddress, _pInfo);
285             break;
286         }
287         case sci_boolean_sparse:
288         {
289             bRet = read_boolean_sparse(_iDatasetId, _iItemPos, _piAddress, _pInfo);
290             break;
291         }
292         case sci_void:             //void item only on list variable
293         {
294             bRet = read_void(_iDatasetId, _iItemPos, _piAddress, _pInfo);
295             break;
296         }
297         case sci_undefined:        //undefined item only on list variable
298         {
299             bRet = read_undefined(_iDatasetId, _iItemPos, _piAddress, _pInfo);
300             break;
301         }
302         default:
303         {
304             Scierror(999, _("%s: Invalid HDF5 Scilab format.\n"), "listvar_in_hdf5");
305             break;
306         }
307     }
308
309     return bRet;
310 }
311
312 static bool read_double(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo)
313 {
314     int iSize = 0;
315     int iComplex = 0;
316
317     iSize = getDatasetInfo(_iDatasetId, &iComplex, &_pInfo->iDims, _pInfo->piDims);
318     _pInfo->iSize = (2 + (iSize * (iComplex + 1))) * 8;
319
320     generateInfo(_pInfo, "constant");
321     closeDataSet(_iDatasetId);
322     return true;
323 }
324
325 static bool read_string(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo)
326 {
327     int iRet = 0;
328     int iSize = 0;
329     int iComplex = 0;
330     char** pstData = NULL;
331
332     iSize = getDatasetInfo(_iDatasetId, &iComplex, &_pInfo->iDims, _pInfo->piDims);
333
334     pstData = (char **)MALLOC(iSize * sizeof(char *));
335     iRet = readStringMatrix(_iDatasetId, pstData);
336
337
338     for (int i = 0 ; i < _pInfo->piDims[0] * _pInfo->piDims[1] ; i++)
339     {
340         _pInfo->iSize += (int)strlen(pstData[i]) * 4;
341     }
342
343     FREE(pstData);
344     //always full double size
345     _pInfo->iSize += (8 - (_pInfo->iSize % 8));
346     //header + offset
347     _pInfo->iSize += 16 + (1 + iSize) * 4;
348
349     generateInfo(_pInfo, "string");
350     return true;
351 }
352
353 static bool read_boolean(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo)
354 {
355     int iSize = 0;
356     int iComplex = 0;
357
358     iSize = getDatasetInfo(_iDatasetId, &iComplex, &_pInfo->iDims, _pInfo->piDims);
359     _pInfo->iSize = (3 + iSize) * 4;
360
361     generateInfo(_pInfo, "boolean");
362     closeDataSet(_iDatasetId);
363     return true;
364 }
365
366 static bool read_integer(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo)
367 {
368     int iRet = 0;
369     int iPrec = 0;
370     int iSize = 0;
371     int iComplex = 0;
372
373     iSize = getDatasetInfo(_iDatasetId, &iComplex, &_pInfo->iDims, _pInfo->piDims);
374     getDatasetPrecision(_iDatasetId, &iPrec);
375
376     _pInfo->iSize = 16 + iSize * (iPrec % 10);
377
378     generateInfo(_pInfo, "integer");
379     closeDataSet(_iDatasetId);
380     return true;
381 }
382
383 static bool read_sparse(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo)
384 {
385     int iRet = 0;
386     int iRows = 0;
387     int iCols = 0;
388     int iNbItem = 0;
389     int iComplex = 0;
390
391     iRet = getSparseDimension(_iDatasetId, &iRows, &iCols, &iNbItem);
392     if (iRet)
393     {
394         return false;
395     }
396
397     iComplex = isComplexData(_iDatasetId);
398
399     _pInfo->iDims = 2;
400     _pInfo->piDims[0] = iRows;
401     _pInfo->piDims[1] = iCols;
402     _pInfo->iSize = 20 + iRows * 4 + iNbItem * 4 + (iNbItem * (iComplex + 1) * 8);
403
404     generateInfo(_pInfo, "sparse");
405     closeDataSet(_iDatasetId);
406     return true;
407 }
408
409 static bool read_boolean_sparse(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo)
410 {
411     int iRet = 0;
412     int iRows = 0;
413     int iCols = 0;
414     int iNbItem = 0;
415     int iComplex = 0;
416
417     iRet = getSparseDimension(_iDatasetId, &iRows, &iCols, &iNbItem);
418     if (iRet)
419     {
420         return false;
421     }
422
423     _pInfo->iDims = 2;
424     _pInfo->piDims[0] = iRows;
425     _pInfo->piDims[1] = iCols;
426     _pInfo->iSize = 20 + iRows * 4 + iNbItem * 4;
427
428     generateInfo(_pInfo, "boolean sparse");
429     closeDataSet(_iDatasetId);
430     return true;
431 }
432
433 static bool read_poly(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo)
434 {
435     int iRet = 0;
436     int iComplex = 0;
437     char pstVarName[64] = { 0 };
438     double **pdblReal = NULL;
439     double **pdblImg = NULL;
440     int *piNbCoef = NULL;
441     int iSize = 0;
442
443     iSize = getDatasetInfo(_iDatasetId, &iComplex, &_pInfo->iDims, _pInfo->piDims);
444     _pInfo->iSize = 8 * 4 + (iSize + 1) * 4;
445
446     if (iComplex)
447     {
448         piNbCoef = (int *)MALLOC(iSize * sizeof(int));
449         pdblReal = (double **)MALLOC(iSize * sizeof(double *));
450         pdblImg = (double **)MALLOC(iSize * sizeof(double *));
451         iRet = readPolyComplexMatrix(_iDatasetId, pstVarName, 2, _pInfo->piDims, piNbCoef, pdblReal, pdblImg);
452     }
453     else
454     {
455         piNbCoef = (int *)MALLOC(iSize * sizeof(int));
456         pdblReal = (double **)MALLOC(iSize * sizeof(double *));
457         iRet = readPolyMatrix(_iDatasetId, pstVarName, 2, _pInfo->piDims, piNbCoef, pdblReal);
458     }
459
460     for (int i = 0 ; i < iSize ; i++)
461     {
462         _pInfo->iSize += piNbCoef[i] * 8 * (iComplex + 1);
463         FREE(pdblReal[i]);
464         if (iComplex)
465         {
466             FREE(pdblImg[i]);
467         }
468     }
469
470     FREE(piNbCoef);
471     FREE(pdblReal);
472     if (iComplex)
473     {
474         FREE(pdblImg);
475     }
476
477     generateInfo(_pInfo, "polynomial");
478     return true;
479 }
480
481 static bool read_list(int _iDatasetId, int _iVarType, int _iItemPos, int *_piAddress, VarInfo* _pInfo)
482 {
483     int iRet = 0;
484     int iItems = 0;
485     int *piListAddr = NULL;
486     hobj_ref_t *piItemRef = NULL;
487
488     iRet = getListDims(_iDatasetId, &iItems);
489     if (iRet)
490     {
491         return false;
492     }
493
494     if (iItems == 0)
495     {
496         //special case for empty list
497     }
498     else
499     {
500         iRet = getListItemReferences(_iDatasetId, &piItemRef);
501         if (iRet)
502         {
503             return false;
504         }
505     }
506     //_pInfo = (VarInfo*)MALLOC(sizeof(VarInfo));
507     _pInfo->iDims = 1;
508     _pInfo->piDims[0] = iItems;
509     _pInfo->iSize = (2 + iItems + 1) * 4;
510
511     for (int i = 0; i < iItems; i++)
512     {
513         int iItemDataset = 0;
514
515         iRet = getListItemDataset(_iDatasetId, piItemRef, i, &iItemDataset);
516         if (iRet || iItemDataset == 0)
517         {
518             return false;
519         }
520         VarInfo info;
521         bool bRet = read_data(iItemDataset, i + 1, piListAddr, &info);
522         if (bRet == false)
523         {
524             return false;
525         }
526
527         _pInfo->iSize += info.iSize;
528     }
529
530     if (_iVarType == sci_list)
531     {
532         generateInfo(_pInfo, "list");
533     }
534     else if (_iVarType == sci_tlist)
535     {
536         generateInfo(_pInfo, "tlist");
537     }
538     else if (_iVarType == sci_mlist)
539     {
540         generateInfo(_pInfo, "mlist");
541     }
542
543     iRet = deleteListItemReferences(_iDatasetId, piItemRef);
544     if (iRet)
545     {
546         return false;
547     }
548
549
550     return true;
551 }
552
553 static bool read_void(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo)
554 {
555     _pInfo->iSize = 1;
556     closeDataSet(_iDatasetId);
557     return true;
558 }
559
560 static bool read_undefined(int _iDatasetId, int _iItemPos, int *_piAddress, VarInfo* _pInfo)
561 {
562     _pInfo->iSize = 1;
563     closeDataSet(_iDatasetId);
564     return true;
565 }
566
567 static void generateInfo(VarInfo* _pInfo, const char* _pstType)
568 {
569     char pstSize[17];
570
571     if (_pInfo->iDims == 2)
572     {
573         sprintf(pstSize, "%d by %d", _pInfo->piDims[0], _pInfo->piDims[1]);
574     }
575     else
576     {
577         sprintf(pstSize, "%d", _pInfo->piDims[0]);
578     }
579     sprintf(_pInfo->pstInfo, "%-*s%-*s%-*s%-*d", 25, _pInfo->varName, 15, _pstType, 16, pstSize, 10, _pInfo->iSize);
580 }