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