Bug fix #15302: Wrong load() calling sequence can crash Scilab
[scilab.git] / scilab / modules / hdf5 / sci_gateway / cpp / sci_hdf5_load.cpp
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2015 - Scilab Enterprises - 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 <hdf5.h>
17 #include "hdf5_gw.hxx"
18 #include "function.hxx"
19 #include "string.hxx"
20 #include "list.hxx"
21 #include "overload.hxx"
22 #include "loadlib.hxx"
23 #include "context.hxx"
24
25 extern "C"
26 {
27 #include "sci_malloc.h"
28 #include "Scierror.h"
29 #include "FileExist.h"
30 #include "expandPathVariable.h"
31 #include "h5_fileManagement.h"
32 #include "h5_attributeConstants.h"
33 #include "h5_readDataFromFile.h"
34 }
35
36 static const std::string fname("load");
37
38 types::Function::ReturnValue sci_hdf5_load(types::typed_list &in, int _iRetCount, types::typed_list& out)
39 {
40     int rhs = static_cast<int>(in.size());
41     if (rhs < 1)
42     {
43         Scierror(999, _("%s: Wrong number of input argument(s): at least %d expected.\n"), fname.data(), 1);
44         return types::Function::Error;
45     }
46
47     for (int i = 0; i < in.size(); ++i)
48     {
49         if (in[i]->isString() == false)
50         {
51             Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), fname.data(), i+1);
52             return types::Function::Error;
53         }
54
55         if (in[i]->getAs<types::String>()->isScalar() == false)
56         {
57             Scierror(999, _("%s: Wrong size for input argument #%d: string expected.\n"), fname.data(), i + 1);
58             return types::Function::Error;
59         }
60     }
61
62     wchar_t* wcfilename = expandPathVariableW(in[0]->getAs<types::String>()->get()[0]);
63     char* cfilename = wide_string_to_UTF8(wcfilename);
64     std::string filename(cfilename);
65     std::wstring wfilename(wcfilename);
66     FREE(cfilename);
67     FREE(wcfilename);
68
69     if (FileExistW(wfilename.data()) == FALSE)
70     {
71         Scierror(999, _("%s: Unable to open file: '%s'.\n"), fname.data(), filename.data());
72         return types::Function::Error;
73     }
74
75     //library ?
76     if (isHDF5File(filename.data()) == false)
77     {
78         //lib file
79         int err = 0;
80         types::Library* lib = loadlib(in[0]->getAs<types::String>()->get()[0], &err);
81
82         switch (err)
83         {
84             case 0:
85                 break;
86             case 2:
87                 Scierror(999, "%s: %s", fname.data(), _("Redefining permanent variable.\n"));
88                 return types::Function::Error;
89             default:
90                 Scierror(999, _("%s: %s is not a valid lib file.\n"), fname.data(), filename.data());
91                 return types::Function::Error;
92         }
93
94         lib->killMe();
95         return types::Function::OK;
96     }
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     std::wstring wstFuncName;
106     //manage version information
107     int version = getSODFormatAttribute(iFile);
108     closeHDF5File(iFile);
109
110     bool needReprocess = false;
111     switch (version)
112     {
113         case -1:
114         case 1:
115         {
116             wstFuncName = L"hdf5_load_v1";
117             needReprocess = true;
118             break;
119         }
120         case 2:
121         {
122             wstFuncName = L"hdf5_load_v2";
123             needReprocess = true;
124             break;
125         }
126         case 3:
127         {
128             wstFuncName = L"hdf5_load_v3";
129             break;
130         }
131         default :
132         {
133             Scierror(999, _("%s: Wrong SOD file format version. Max Expected: %d Found: %d\n"), fname.data(), SOD_FILE_VERSION, version);
134             return types::Function::Error;
135         }
136     }
137
138     types::typed_list out1;
139     types::Function::ReturnValue ret = Overload::call(wstFuncName, in, _iRetCount, out1);
140
141     if (ret != types::Function::OK)
142     {
143         return types::Function::Error;
144     }
145
146     if (needReprocess)
147     {
148         //call %sodload
149         types::String* vars = out1[0]->getAs<types::String>();
150         vars->IncreaseRef();
151         int size = vars->getSize();
152         types::typed_list in2(1, vars);
153         types::typed_list out2;
154         std::wstring wstFuncName = L"%_sodload";
155         ret = Overload::call(wstFuncName, in2, size, out2);
156         vars->DecreaseRef();
157
158         symbol::Context* ctx = symbol::Context::getInstance();
159         wchar_t** names = vars->get();
160
161         //update context with values return by %_sodload
162         for (int i = 0; i < size; ++i)
163         {
164             ctx->put(symbol::Symbol(names[i]), out2[i]);
165         }
166
167         vars->killMe();
168     }
169     else
170     {
171         out.push_back(out1.front());
172     }
173
174     return ret;
175 }