5a2028fb86117e86a9caf03aea92f41a9bea51c3
[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             for (int i = 0; i < iDims; ++i)
412             {
413                 if (inputRows < 2 + offset)
414                 {
415                     delete pList;
416                     Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 2, 1);
417                     return false;
418                 }
419                 // Extract the list elements infos and recursively call readElement
420                 int elementType = static_cast<int>(*(input + offset));
421                 int elementDims = static_cast<int>(*(input + offset + 1));
422                 types::InternalType* element;
423                 if (!readElement(input + offset, elementType, elementDims, inputRows - offset, offset, element))
424                 {
425                     delete pList;
426                     return false;
427                 }
428                 pList->append(element);
429             }
430             offset += offsetSave;
431             res = pList;
432             break;
433         }
434
435         case types::InternalType::ScilabStruct :
436         {
437             if (inputRows < 2)
438             {
439                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 2, 1);
440                 return false;
441             }
442
443             if (iDims <= 0)
444             {
445                 res = new types::Struct();
446                 offset += 2;
447                 break;
448             }
449
450             types::Struct* pStruct = new types::Struct(1, 1);
451
452             int offsetSave = 0;
453             if (offset == 0)
454             {
455                 offset += 2;
456             }
457             else
458             {
459                 // If reading a sublist, start off with a new offset
460                 offsetSave = offset;
461                 offset = 2;
462             }
463             // Read the header...
464             int elementType = static_cast<int>(*(input + offset));
465             if (elementType != types::InternalType::ScilabString)
466             {
467                 Scierror(999, _("%s: Wrong value for input argument #%d: %d (String) expected.\n"), vec2varName.c_str(), 1, 11);
468                 return false;
469             }
470             int elementDims = static_cast<int>(*(input + offset + 1));
471             types::InternalType* element;
472             if (!readElement(input + offset, elementType, elementDims, inputRows - offset, offset, element))
473             {
474                 return false;
475             }
476             types::String* header = element->getAs<types::String>();
477             // ... and copy it in 'pStruct'
478             for (int i = 0; i < header->getSize(); ++i)
479             {
480                 pStruct->get(0)->addField(header->get(i));
481             }
482
483             for (int i = 1; i < iDims + 1; ++i)
484             {
485                 if (inputRows < 2 + offset)
486                 {
487                     Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 2, 1);
488                     return false;
489                 }
490                 // Extract the fields content infos and recursively call readElement
491                 elementType = static_cast<int>(*(input + offset));
492                 elementDims = static_cast<int>(*(input + offset + 1));
493                 if (!readElement(input + offset, elementType, elementDims, inputRows - offset, offset, element))
494                 {
495                     return false;
496                 }
497                 pStruct->get(0)->set(header->get(i - 1), element);
498             }
499             offset += offsetSave;
500             res = pStruct;
501             break;
502         }
503
504         default :
505             Scierror(999, _("%s: Wrong value for element #%d of input argument #%d: Unknown type.\n"), vec2varName.c_str(), offset + 1, 1);
506             return false;
507     }
508
509     return true;
510 }
511
512 bool vec2var(const std::vector<double> in, types::InternalType* &out)
513 {
514     const int iType = static_cast<int>(in[0]);
515     const int iDims = static_cast<int>(in[1]);
516
517     int offset = 0;
518     if (!readElement(&in[0], iType, iDims, static_cast<int>(in.size()), offset, out))
519     {
520         return false;
521     }
522
523     return true;
524 }