[memleak] scicos => var2vec leak fixed about List and Struct
[scilab.git] / scilab / modules / scicos / src / cpp / vec2var.cpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2015 - Scilab Enterprises - Paul Bignier
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 <vector>
14 #include <string>
15 #include <cwchar>
16 #include <cstring>
17
18 #include "vec2var.hxx"
19
20 #include "types.hxx"
21 #include "internal.hxx"
22 #include "double.hxx"
23 #include "int.hxx"
24 #include "bool.hxx"
25 #include "string.hxx"
26 #include "list.hxx"
27 #include "tlist.hxx"
28 #include "mlist.hxx"
29 #include "struct.hxx"
30
31 extern "C"
32 {
33 #include "Scierror.h"
34 #include "localization.h"
35 }
36
37 static const std::string vec2varName = "vec2var";
38
39 /**
40  * Calculate the length increment depending on the type of the Scilab type
41  *
42  * @param T Scilab type
43  * @param v the instance on the Scilab type
44  * @return the number of double used to store the data
45  */
46 template<typename T>
47 size_t required_length(T* v)
48 {
49     const size_t sizeof_double = sizeof(double);
50     if (sizeof(typename T::type) >= sizeof_double)
51     {
52         return v->getSize() * sizeof(typename T::type) / sizeof_double;
53     }
54     else
55     {
56         // Increase the size to contain enough space, manage the size_t rounding issue
57         return (v->getSize() * sizeof(typename T::type) + (sizeof_double - 1)) / sizeof_double;
58     }
59 }
60
61 template<typename T>
62 int decode(const double* const tab, const int tabSize, const int iDims, const int offset, T* &res)
63 {
64     int  iElements = 1;
65     int* pDims = new int[iDims];
66     for (int i = 0; i < iDims; ++i)
67     {
68         pDims[i] = static_cast<int>(tab[i]);
69         iElements *= pDims[i];
70     }
71
72     res = new T(iDims, pDims);
73     delete[] pDims;
74
75     const int numberOfDoubleNeeded = static_cast<int>(required_length(res));
76     if (tabSize < numberOfDoubleNeeded + 2 + iDims)
77     {
78         // Error case: the input doesn't have enough elements
79         Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, numberOfDoubleNeeded + 2 + iDims + offset, 1);
80         res->killMe();
81         return -1;
82     }
83
84     //Use a buffer to prevent copying only parts of integers
85     double* buffer = new double[numberOfDoubleNeeded];
86     memcpy(buffer, tab + iDims, numberOfDoubleNeeded * sizeof(double));
87     memcpy(res->get(), buffer, iElements * sizeof(typename T::type));
88     delete[] buffer;
89
90     return 2 + iDims + numberOfDoubleNeeded;
91 }
92
93 template<>
94 int decode(const double* const tab, const int tabSize, const int iDims, const int offset, types::Double* &res)
95 {
96     int  iElements = 1;
97     int* pDims = new int[iDims];
98     for (int i = 0; i < iDims; ++i)
99     {
100         pDims[i] = static_cast<int>(tab[i]);
101         iElements *= pDims[i];
102     }
103     if (tabSize < iElements + 3 + iDims)
104     {
105         // Error case: the input doesn't have enough elements
106         delete[] pDims;
107         Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, iElements + 3 + iDims + offset, 1);
108         return -1;
109     }
110     if (iElements == 0)
111     {
112         res = types::Double::Empty();
113         delete[] pDims;
114         return 5;
115     }
116     const bool isComplex = (tab[iDims] == 1);
117
118     res = new types::Double(iDims, pDims, isComplex);
119     delete[] pDims;
120
121     res->set(tab + iDims + 1);
122     if (isComplex == true)
123     {
124         res->setImg(tab + iDims + 1 + iElements);
125         iElements *= 2;
126     }
127
128     return 2 + iDims + 1 + iElements;
129 }
130
131 template<>
132 int decode(const double* const tab, const int tabSize, const int iDims, const int offset, types::String* &res)
133 {
134     int  iElements = 1;
135     int* pDims = new int[iDims];
136     for (int i = 0; i < iDims; ++i)
137     {
138         pDims[i] = static_cast<int>(tab[i]);
139         iElements *= pDims[i];
140     }
141     if (tabSize < iElements * 2 + 2 + iDims)
142     {
143         // Error case: the input doesn't have enough elements
144         delete[] pDims;
145         Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, iElements * 2 + 2 + iDims + offset, 1);
146         return -1;
147     }
148
149     res = new types::String(iDims, pDims);
150     delete[] pDims;
151
152     // Retrieving the first value pointer
153     double* strData = const_cast<double*>(tab + iDims + iElements);
154
155     res->set(0, (char*) & (*strData));
156     strData += static_cast<size_t>(tab[iDims]);
157     int stringOffset = static_cast<int>(tab[iDims]);
158     for (int i = 1; i < iElements; i++)
159     {
160         res->set(i, (char*) & (*strData));
161
162         // Increment the value pointer by the number of elements
163         const size_t numberOfElem = static_cast<size_t>(tab[iDims + i]) - static_cast<size_t>(tab[iDims + i - 1]);
164         strData += numberOfElem;
165         stringOffset += static_cast<int>(numberOfElem);
166     }
167
168     return 2 + iDims + iElements + stringOffset;
169 }
170
171 static bool readElement(const double* const input, const int iType, const int iDims, const int inputRows, int &offset, types::InternalType* &res)
172 {
173     switch (iType)
174     {
175         case types::InternalType::ScilabDouble :
176         {
177             if (inputRows < 5)
178             {
179                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 5, 1);
180                 return false;
181             }
182
183             types::Double* pDouble = nullptr;
184             const int resSize = decode<types::Double>(input + 2, inputRows, iDims, offset, pDouble);
185             if (resSize < 0)
186             {
187                 return false;
188             }
189             res = pDouble;
190             offset += resSize;
191             break;
192         }
193
194         case types::InternalType::ScilabInt8   :
195         {
196             if (inputRows < 4)
197             {
198                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
199                 return false;
200             }
201
202             types::Int8* pInt8 = nullptr;
203             const int resSize = decode<types::Int8>(input + 2, inputRows, iDims, offset, pInt8);
204             if (resSize < 0)
205             {
206                 return false;
207             }
208             res = pInt8;
209             offset += resSize;
210             break;
211         }
212         case types::InternalType::ScilabUInt8  :
213         {
214             if (inputRows < 4)
215             {
216                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
217                 return false;
218             }
219
220             types::UInt8* pUInt8 = nullptr;
221             const int resSize = decode<types::UInt8>(input + 2, inputRows, iDims, offset, pUInt8);
222             if (resSize < 0)
223             {
224                 return false;
225             }
226             res = pUInt8;
227             offset += resSize;
228             break;
229         }
230         case types::InternalType::ScilabInt16  :
231         {
232             if (inputRows < 4)
233             {
234                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
235                 return false;
236             }
237
238             types::Int16* pInt16 = nullptr;
239             const int resSize = decode<types::Int16>(input + 2, inputRows, iDims, offset, pInt16);
240             if (resSize < 0)
241             {
242                 return false;
243             }
244             res = pInt16;
245             offset += resSize;
246             break;
247         }
248         case types::InternalType::ScilabUInt16 :
249         {
250             if (inputRows < 4)
251             {
252                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
253                 return false;
254             }
255
256             types::UInt16* pUInt16 = nullptr;
257             const int resSize = decode<types::UInt16>(input + 2, inputRows, iDims, offset, pUInt16);
258             if (resSize < 0)
259             {
260                 return false;
261             }
262             res = pUInt16;
263             offset += resSize;
264             break;
265         }
266         case types::InternalType::ScilabInt32  :
267         {
268             if (inputRows < 4)
269             {
270                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
271                 return false;
272             }
273
274             types::Int32* pInt32 = nullptr;
275             const int resSize = decode<types::Int32>(input + 2, inputRows, iDims, offset, pInt32);
276             if (resSize < 0)
277             {
278                 return false;
279             }
280             res = pInt32;
281             offset += resSize;
282             break;
283         }
284         case types::InternalType::ScilabUInt32 :
285         {
286             if (inputRows < 4)
287             {
288                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
289                 return false;
290             }
291
292             types::UInt32* pUInt32 = nullptr;
293             const int resSize = decode<types::UInt32>(input + 2, inputRows, iDims, offset, pUInt32);
294             if (resSize < 0)
295             {
296                 return false;
297             }
298             res = pUInt32;
299             offset += resSize;
300             break;
301         }
302         case types::InternalType::ScilabInt64  :
303         {
304             if (inputRows < 4)
305             {
306                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
307                 return false;
308             }
309
310             types::Int64* pInt64 = nullptr;
311             const int resSize = decode<types::Int64>(input + 2, inputRows, iDims, offset, pInt64);
312             if (resSize < 0)
313             {
314                 return false;
315             }
316             res = pInt64;
317             offset += resSize;
318             break;
319         }
320         case types::InternalType::ScilabUInt64 :
321         {
322             if (inputRows < 4)
323             {
324                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
325                 return false;
326             }
327
328             types::UInt64* pUInt64 = nullptr;
329             const int resSize = decode<types::UInt64>(input + 2, inputRows, iDims, offset, pUInt64);
330             if (resSize < 0)
331             {
332                 return false;
333             }
334             res = pUInt64;
335             offset += resSize;
336             break;
337         }
338         case types::InternalType::ScilabBool   :
339         {
340             if (inputRows < 4)
341             {
342                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
343                 return false;
344             }
345
346             types::Bool* pBool = nullptr;
347             const int resSize = decode<types::Bool>(input + 2, inputRows, iDims, offset, pBool);
348             if (resSize < 0)
349             {
350                 return false;
351             }
352             res = pBool;
353             offset += resSize;
354             break;
355         }
356
357         case types::InternalType::ScilabString :
358         {
359             if (inputRows < 4)
360             {
361                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
362                 return false;
363             }
364
365             types::String* pString = nullptr;
366             const int resSize = decode<types::String>(input + 2, inputRows, iDims, offset, pString);
367             if (resSize < 0)
368             {
369                 return false;
370             }
371             res = pString;
372             offset += resSize;
373             break;
374         }
375
376         case types::InternalType::ScilabList   :
377         case types::InternalType::ScilabTList  :
378         case types::InternalType::ScilabMList  :
379         {
380             if (inputRows < 2)
381             {
382                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 2, 1);
383                 return false;
384             }
385
386             types::List* pList = nullptr;
387             if (iType == types::InternalType::ScilabList)
388             {
389                 pList = new types::List();
390             }
391             else if (iType == types::InternalType::ScilabTList)
392             {
393                 pList = new types::TList();
394             }
395             else
396             {
397                 pList = new types::MList();
398             }
399
400             int offsetSave = 0;
401             if (offset == 0)
402             {
403                 offset += 2;
404             }
405             else
406             {
407                 // If reading a sublist, start off with a new offset
408                 offsetSave = offset;
409                 offset = 2;
410             }
411
412             for (int i = 0; i < iDims; ++i)
413             {
414                 if (inputRows < 2 + offset)
415                 {
416                     delete pList;
417                     Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 2, 1);
418                     return false;
419                 }
420                 // Extract the list elements infos and recursively call readElement
421                 int elementType = static_cast<int>(*(input + offset));
422                 int elementDims = static_cast<int>(*(input + offset + 1));
423                 types::InternalType* element;
424                 if (!readElement(input + offset, elementType, elementDims, inputRows - offset, offset, element))
425                 {
426                     delete pList;
427                     return false;
428                 }
429
430                 pList->append(element);
431                 if (element->isList())
432                 {
433                     element->killMe();
434                 }
435             }
436             offset += offsetSave;
437             res = pList;
438             break;
439         }
440
441         case types::InternalType::ScilabStruct :
442         {
443             if (inputRows < 2)
444             {
445                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 2, 1);
446                 return false;
447             }
448
449             if (iDims <= 0)
450             {
451                 res = new types::Struct();
452                 offset += 2;
453                 break;
454             }
455
456             int offsetSave = 0;
457             if (offset == 0)
458             {
459                 offset += 2;
460             }
461             else
462             {
463                 // If reading a sublist, start off with a new offset
464                 offsetSave = offset;
465                 offset = 2;
466             }
467             // Read the header...
468             int elementType = static_cast<int>(*(input + offset));
469             if (elementType != types::InternalType::ScilabString)
470             {
471                 Scierror(999, _("%s: Wrong value for input argument #%d: %d (String) expected.\n"), vec2varName.c_str(), 1, 11);
472                 return false;
473             }
474             int elementDims = static_cast<int>(*(input + offset + 1));
475             types::InternalType* element;
476             if (!readElement(input + offset, elementType, elementDims, inputRows - offset, offset, element))
477             {
478                 return false;
479             }
480
481             types::Struct* pStruct = new types::Struct(1, 1);
482             types::String* header = element->getAs<types::String>();
483             // ... and copy it in 'pStruct'
484             for (int i = 0; i < header->getSize(); ++i)
485             {
486                 pStruct->get(0)->addField(header->get(i));
487             }
488
489             for (int i = 1; i < iDims + 1; ++i)
490             {
491                 if (inputRows < 2 + offset)
492                 {
493                     delete pStruct;
494                     Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 2, 1);
495                     return false;
496                 }
497                 // Extract the fields content infos and recursively call readElement
498                 elementType = static_cast<int>(*(input + offset));
499                 elementDims = static_cast<int>(*(input + offset + 1));
500                 if (!readElement(input + offset, elementType, elementDims, inputRows - offset, offset, element))
501                 {
502                     delete pStruct;
503                     return false;
504                 }
505                 pStruct->get(0)->set(header->get(i - 1), element);
506             }
507
508             header->killMe();
509             offset += offsetSave;
510             res = pStruct;
511             break;
512         }
513
514         default :
515             Scierror(999, _("%s: Wrong value for element #%d of input argument #%d: Unknown type.\n"), vec2varName.c_str(), offset + 1, 1);
516             return false;
517     }
518
519     return true;
520 }
521
522 bool vec2var(const std::vector<double> in, types::InternalType* &out)
523 {
524     const int iType = static_cast<int>(in[0]);
525     const int iDims = static_cast<int>(in[1]);
526
527     int offset = 0;
528     if (!readElement(&in[0], iType, iDims, static_cast<int>(in.size()), offset, out))
529     {
530         return false;
531     }
532
533     return true;
534 }