Scicos: fix crash on invalid extract
[scilab.git] / scilab / modules / data_structures / sci_gateway / cpp / sci_getfield.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2013 - 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 /*--------------------------------------------------------------------------*/
17 #include "data_structures_gw.hxx"
18 #include "internal.hxx"
19 #include "function.hxx"
20 #include "double.hxx"
21 #include "int.hxx"
22 #include "string.hxx"
23 #include "list.hxx"
24 #include "mlist.hxx"
25 #include "tlist.hxx"
26 #include "struct.hxx"
27 #include "user.hxx"
28
29 extern "C"
30 {
31 #include "Scierror.h"
32 #include "sci_malloc.h"
33 #include "localization.h"
34 #include "freeArrayOfString.h"
35 }
36
37 static types::Function::ReturnValue sci_getfieldStruct(types::typed_list &in, int _iRetCount, types::typed_list &out);
38 static types::Function::ReturnValue sci_getfieldUserType(types::typed_list &in, int _iRetCount, types::typed_list &out);
39
40 /*-----------------------------------------------------------------------------------*/
41 types::Function::ReturnValue sci_getfield(types::typed_list &in, int _iRetCount, types::typed_list &out)
42 {
43     if (in.size() != 2)
44     {
45         Scierror(77, _("%s: Wrong number of input argument(s): %d expected.\n"), "getfield", 2);
46         return types::Function::Error;
47     }
48
49     //special case for struct
50     if (in[1]->isStruct())
51     {
52         return sci_getfieldStruct(in, _iRetCount, out);
53     }
54
55     //special case for UserType
56     if (in[1]->isUserType())
57     {
58         return sci_getfieldUserType(in, _iRetCount, out);
59     }
60
61     _iRetCount = std::max(_iRetCount, 1);
62
63     types::InternalType* pIndex = in[0];
64     if (in[1]->isList() == false && in[1]->isMList() == false && in[1]->isTList() == false)
65     {
66         Scierror(999, _("%s: Wrong type for input argument #%d: List expected.\n"), "getfield", 2);
67         return types::Function::Error;
68     }
69
70     types::List* pL = in[1]->getAs<types::List>();
71     types::InternalType* pITOut = NULL;
72
73     if (pIndex->isString())
74     {
75         //extraction by fieldnames
76         if (pL->isMList() == false && pL->isTList() == false)
77         {
78             Scierror(999, _("%s: Soft coded field names not yet implemented.\n"), "getfield");
79             return types::Function::Error;
80         }
81
82         types::TList* pT = pL->getAs<types::TList>();
83         types::String* pS = pIndex->getAs<types::String>();
84
85         std::list<std::wstring> stFields;
86
87         //check output arguments count
88         for (int i = 0 ; i < pS->getSize() ; i++)
89         {
90             std::wstring wst = pS->get(i);
91             if (pT->exists(wst) == false)
92             {
93                 Scierror(999, _("%s: Invalid index.\n"), "getfield");
94                 return types::Function::Error;
95             }
96
97             stFields.push_back(pS->get(i));
98         }
99
100         pITOut = pT->extractStrings(stFields);
101     }
102     else
103     {
104         //extraction by index
105         types::typed_list Args;
106         Args.push_back(pIndex);
107         pITOut = pL->extract(&Args);
108     }
109
110     if (pITOut == NULL)
111     {
112         Scierror(999, _("Invalid index.\n"));
113         return types::Function::Error;
114     }
115
116     types::List* pList = pITOut->getAs<types::List>();
117     int iListSize = pList->getSize();
118
119     if (_iRetCount < iListSize)
120     {
121         Scierror(78, _("%s: Wrong number of output argument(s): %d expected.\n"), "getfield", iListSize);
122         return types::Function::Error;
123     }
124
125     int iIndex = 0;
126     for (int i = 0; i < iListSize; i++)
127     {
128         if (pList->get(i)->isVoid())
129         {
130             switch (pIndex->getType())
131             {
132                 case types::InternalType::ScilabType::ScilabDouble:
133                 {
134                     iIndex = (int)pIndex->getAs<types::Double>()->get(i);
135                 }
136                 break;
137                 case types::InternalType::ScilabType::ScilabInt8:
138                 {
139                     iIndex = (int)pIndex->getAs<types::Int8>()->get(i);
140                 }
141                 break;
142                 case types::InternalType::ScilabType::ScilabUInt8:
143                 {
144                     iIndex = (int)pIndex->getAs<types::UInt8>()->get(i);
145                 }
146                 break;
147                 case types::InternalType::ScilabType::ScilabInt16:
148                 {
149                     iIndex = (int)pIndex->getAs<types::Int16>()->get(i);
150                 }
151                 break;
152                 case types::InternalType::ScilabType::ScilabUInt16:
153                 {
154                     iIndex = (int)pIndex->getAs<types::UInt16>()->get(i);
155                 }
156                 break;
157                 case types::InternalType::ScilabType::ScilabInt32:
158                 {
159                     iIndex = pIndex->getAs<types::Int32>()->get(i);
160                 }
161                 break;
162                 case types::InternalType::ScilabType::ScilabUInt32:
163                 {
164                     iIndex = (int)pIndex->getAs<types::UInt32>()->get(i);
165                 }
166                 break;
167                 case types::InternalType::ScilabType::ScilabInt64:
168                 {
169                     iIndex = (int)pIndex->getAs<types::Int64>()->get(i);
170                 }
171                 break;
172                 case types::InternalType::ScilabType::ScilabUInt64:
173                 {
174                     iIndex = (int)pIndex->getAs<types::UInt64>()->get(i);
175                 }
176                 break;
177                 case types::InternalType::ScilabType::ScilabString:
178                 {
179                     std::wstring wField(pIndex->getAs<types::String>()->get(i));
180                     iIndex = pL->getAs<types::TList>()->getIndexFromString(wField);
181                     // The type (the first field) is not counted
182                     iIndex++;
183                 }
184                 break;
185                 default:
186                     break;
187             }
188
189             pList->killMe();
190             Scierror(999, _("List element number %d is Undefined.\n"), iIndex);
191             return types::Function::Error;
192         }
193     }
194
195     for (int i = 0 ; i < iListSize ; i++)
196     {
197         out.push_back(pList->get(i));
198     }
199
200     pList->killMe();
201
202     return types::Function::OK;
203 }
204 /*-----------------------------------------------------------------------------------*/
205
206 static types::Function::ReturnValue sci_getfieldStruct(types::typed_list &in, int _iRetCount, types::typed_list &out)
207 {
208     types::InternalType* pIndex = in[0];
209     types::Struct* pSt = in[1]->getAs<types::Struct>();
210     types::typed_list vectResult;
211
212     if (pIndex->isString())
213     {
214         types::String* pFields = pIndex->getAs<types::String>();
215         std::vector<std::wstring> wstFields;
216
217         for (int i = 0 ; i < pFields->getSize() ; i++)
218         {
219             wstFields.push_back(pFields->get(i));
220         }
221
222         vectResult = pSt->extractFields(wstFields);
223     }
224     else
225     {
226         //extraction by index
227         // do not extract myself of myself
228         types::typed_list input;
229         input.push_back(in[0]);
230         vectResult = pSt->extractFields(&input);
231     }
232
233     if (vectResult.size() == 0)
234     {
235         Scierror(78, _("%s: Invalid index.\n"), "getfield");
236         return types::Function::Error;
237     }
238
239     if (_iRetCount != static_cast<int>(vectResult.size()))
240     {
241         Scierror(78, _("%s: Wrong number of output argument(s): %d expected.\n"), "getfield", vectResult.size());
242         return types::Function::Error;
243     }
244
245     for (int i = 0 ; i < _iRetCount ; i++)
246     {
247         out.push_back(vectResult[i]);
248     }
249
250     return types::Function::OK;
251 }
252 /*-----------------------------------------------------------------------------------*/
253
254 static types::Function::ReturnValue sci_getfieldUserType(types::typed_list &in, int /*_iRetCount*/, types::typed_list &out)
255 {
256     types::UserType* pUT = in[1]->getAs<types::UserType>();
257
258     if (in[0]->isDouble())
259     {
260         types::Double* pIndex = in[0]->getAs<types::Double>();
261
262         // Extract the properties
263         types::typed_list one (1, new types::Double(1));
264         types::InternalType* properties = pUT->extract(&one);
265         if (!properties || !properties->isString())
266         {
267             Scierror(999, _("%s: Could not read the argument #%d properties.\n"), "getfield", 2);
268             one[0]->killMe();
269             return types::Function::Error;
270         }
271         one[0]->killMe();
272
273         types::String* propertiesStr = properties->getAs<types::String>();
274
275         // Checking the index validity
276         int index = pIndex->get(0);
277         if (floor(index) != index)
278         {
279             Scierror(999, _("%s: Wrong value for input argument #%d: An integer value expected.\n"), "getfield", 1);
280             properties->killMe();
281             return types::Function::Error;
282         }
283         if (index < 1 || index > 1 + propertiesStr->getSize())
284         {
285             Scierror(999, _("%s: Wrong value for input argument #%d: At most %d expected.\n"), "getfield", 1, 1 + propertiesStr->getSize());
286             properties->killMe();
287             return types::Function::Error;
288         }
289
290         if (index == 1)
291         {
292             // Return the properties
293             types::String* ret = new types::String(1, 1 + propertiesStr->getSize());
294             ret->set(0, pUT->getTypeStr().c_str());
295             for (int i = 0; i < propertiesStr->getSize(); ++i)
296             {
297                 ret->set(i + 1, propertiesStr->get(i));
298             }
299             out.push_back(ret);
300         }
301         else
302         {
303             // Return property number 'index-2'
304             types::InternalType* field;
305             pUT->extract(propertiesStr->get(index - 2), field);
306             out.push_back(field);
307         }
308
309         properties->killMe();
310         return types::Function::OK;
311     }
312     else
313     {
314         Scierror(999, _("%s: Wrong type for input argument #%d: Integer expected.\n"), "getfield", 1);
315         return types::Function::Error;
316     }
317 }
318 /*-----------------------------------------------------------------------------------*/