23d87eafc72debf91ee2203b238f06d0df2171ea
[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         Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, iElements + 3 + iDims + offset, 1);
107         return -1;
108     }
109     if (iElements == 0)
110     {
111         res = types::Double::Empty();
112         delete[] pDims;
113         return 5;
114     }
115     const bool isComplex = (tab[iDims] == 1);
116
117     res = new types::Double(iDims, pDims, isComplex);
118     delete[] pDims;
119
120     res->set(tab + iDims + 1);
121     if (isComplex == true)
122     {
123         res->setImg(tab + iDims + 1 + iElements);
124         iElements *= 2;
125     }
126
127     return 2 + iDims + 1 + iElements;
128 }
129
130 template<>
131 int decode(const double* const tab, const int tabSize, const int iDims, const int offset, types::String* &res)
132 {
133     int  iElements = 1;
134     int* pDims = new int[iDims];
135     for (int i = 0; i < iDims; ++i)
136     {
137         pDims[i] = static_cast<int>(tab[i]);
138         iElements *= pDims[i];
139     }
140     if (tabSize < iElements * 2 + 2 + iDims)
141     {
142         // Error case: the input doesn't have enough elements
143         delete[] pDims;
144         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);
145         return -1;
146     }
147
148     res = new types::String(iDims, pDims);
149     delete[] pDims;
150
151     // Retrieving the first value pointer
152     double* strData = const_cast<double*>(tab + iDims + iElements);
153
154     res->set(0, (char*) & (*strData));
155     strData += static_cast<size_t>(tab[iDims]);
156     int stringOffset = static_cast<int>(tab[iDims]);
157     for (int i = 1; i < iElements; i++)
158     {
159         res->set(i, (char*) & (*strData));
160
161         // Increment the value pointer by the number of elements
162         const size_t numberOfElem = static_cast<size_t>(tab[iDims + i]) - static_cast<size_t>(tab[iDims + i - 1]);
163         strData += numberOfElem;
164         stringOffset += static_cast<int>(numberOfElem);
165     }
166
167     return 2 + iDims + iElements + stringOffset;
168 }
169
170 static bool readElement(const double* const input, const int iType, const int iDims, const int inputRows, int &offset, types::InternalType* &res)
171 {
172     switch (iType)
173     {
174         case types::InternalType::ScilabDouble :
175         {
176             if (inputRows < 5)
177             {
178                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 5, 1);
179                 return false;
180             }
181
182             types::Double* pDouble = nullptr;
183             const int resSize = decode<types::Double>(input + 2, inputRows, iDims, offset, pDouble);
184             if (resSize < 0)
185             {
186                 return false;
187             }
188             res = pDouble;
189             offset += resSize;
190             break;
191         }
192
193         case types::InternalType::ScilabInt8   :
194         {
195             if (inputRows < 4)
196             {
197                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
198                 return false;
199             }
200
201             types::Int8* pInt8 = nullptr;
202             const int resSize = decode<types::Int8>(input + 2, inputRows, iDims, offset, pInt8);
203             if (resSize < 0)
204             {
205                 return false;
206             }
207             res = pInt8;
208             offset += resSize;
209             break;
210         }
211         case types::InternalType::ScilabUInt8  :
212         {
213             if (inputRows < 4)
214             {
215                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
216                 return false;
217             }
218
219             types::UInt8* pUInt8 = nullptr;
220             const int resSize = decode<types::UInt8>(input + 2, inputRows, iDims, offset, pUInt8);
221             if (resSize < 0)
222             {
223                 return false;
224             }
225             res = pUInt8;
226             offset += resSize;
227             break;
228         }
229         case types::InternalType::ScilabInt16  :
230         {
231             if (inputRows < 4)
232             {
233                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
234                 return false;
235             }
236
237             types::Int16* pInt16 = nullptr;
238             const int resSize = decode<types::Int16>(input + 2, inputRows, iDims, offset, pInt16);
239             if (resSize < 0)
240             {
241                 return false;
242             }
243             res = pInt16;
244             offset += resSize;
245             break;
246         }
247         case types::InternalType::ScilabUInt16 :
248         {
249             if (inputRows < 4)
250             {
251                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
252                 return false;
253             }
254
255             types::UInt16* pUInt16 = nullptr;
256             const int resSize = decode<types::UInt16>(input + 2, inputRows, iDims, offset, pUInt16);
257             if (resSize < 0)
258             {
259                 return false;
260             }
261             res = pUInt16;
262             offset += resSize;
263             break;
264         }
265         case types::InternalType::ScilabInt32  :
266         {
267             if (inputRows < 4)
268             {
269                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
270                 return false;
271             }
272
273             types::Int32* pInt32 = nullptr;
274             const int resSize = decode<types::Int32>(input + 2, inputRows, iDims, offset, pInt32);
275             if (resSize < 0)
276             {
277                 return false;
278             }
279             res = pInt32;
280             offset += resSize;
281             break;
282         }
283         case types::InternalType::ScilabUInt32 :
284         {
285             if (inputRows < 4)
286             {
287                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
288                 return false;
289             }
290
291             types::UInt32* pUInt32 = nullptr;
292             const int resSize = decode<types::UInt32>(input + 2, inputRows, iDims, offset, pUInt32);
293             if (resSize < 0)
294             {
295                 return false;
296             }
297             res = pUInt32;
298             offset += resSize;
299             break;
300         }
301         case types::InternalType::ScilabInt64  :
302         {
303             if (inputRows < 4)
304             {
305                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
306                 return false;
307             }
308
309             types::Int64* pInt64 = nullptr;
310             const int resSize = decode<types::Int64>(input + 2, inputRows, iDims, offset, pInt64);
311             if (resSize < 0)
312             {
313                 return false;
314             }
315             res = pInt64;
316             offset += resSize;
317             break;
318         }
319         case types::InternalType::ScilabUInt64 :
320         {
321             if (inputRows < 4)
322             {
323                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
324                 return false;
325             }
326
327             types::UInt64* pUInt64 = nullptr;
328             const int resSize = decode<types::UInt64>(input + 2, inputRows, iDims, offset, pUInt64);
329             if (resSize < 0)
330             {
331                 return false;
332             }
333             res = pUInt64;
334             offset += resSize;
335             break;
336         }
337         case types::InternalType::ScilabBool   :
338         {
339             if (inputRows < 4)
340             {
341                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
342                 return false;
343             }
344
345             types::Bool* pBool = nullptr;
346             const int resSize = decode<types::Bool>(input + 2, inputRows, iDims, offset, pBool);
347             if (resSize < 0)
348             {
349                 return false;
350             }
351             res = pBool;
352             offset += resSize;
353             break;
354         }
355
356         case types::InternalType::ScilabString :
357         {
358             if (inputRows < 4)
359             {
360                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
361                 return false;
362             }
363
364             types::String* pString = nullptr;
365             const int resSize = decode<types::String>(input + 2, inputRows, iDims, offset, pString);
366             if (resSize < 0)
367             {
368                 return false;
369             }
370             res = pString;
371             offset += resSize;
372             break;
373         }
374
375         case types::InternalType::ScilabList   :
376         case types::InternalType::ScilabTList  :
377         case types::InternalType::ScilabMList  :
378         {
379             if (inputRows < 2)
380             {
381                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 2, 1);
382                 return false;
383             }
384
385             types::List* pList = nullptr;
386             if (iType == types::InternalType::ScilabList)
387             {
388                 pList = new types::List();
389             }
390             else if (iType == types::InternalType::ScilabTList)
391             {
392                 pList = new types::TList();
393             }
394             else
395             {
396                 pList = new types::MList();
397             }
398
399             int offsetSave = 0;
400             if (offset == 0)
401             {
402                 offset += 2;
403             }
404             else
405             {
406                 // If reading a sublist, start off with a new offset
407                 offsetSave = offset;
408                 offset = 2;
409             }
410             for (int i = 0; i < iDims; ++i)
411             {
412                 if (inputRows < 2 + offset)
413                 {
414                     delete pList;
415                     Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 2, 1);
416                     return false;
417                 }
418                 // Extract the list elements infos and recursively call readElement
419                 int elementType = static_cast<int>(*(input + offset));
420                 int elementDims = static_cast<int>(*(input + offset + 1));
421                 types::InternalType* element;
422                 if (!readElement(input + offset, elementType, elementDims, inputRows - offset, offset, element))
423                 {
424                     delete pList;
425                     return false;
426                 }
427                 pList->append(element);
428             }
429             offset += offsetSave;
430             res = pList;
431             break;
432         }
433
434         case types::InternalType::ScilabStruct :
435         {
436             if (inputRows < 2)
437             {
438                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 2, 1);
439                 return false;
440             }
441
442             if (iDims <= 0)
443             {
444                 res = new types::Struct();
445                 offset += 2;
446                 break;
447             }
448
449             types::Struct* pStruct = new types::Struct(1, 1);
450
451             int offsetSave = 0;
452             if (offset == 0)
453             {
454                 offset += 2;
455             }
456             else
457             {
458                 // If reading a sublist, start off with a new offset
459                 offsetSave = offset;
460                 offset = 2;
461             }
462             // Read the header...
463             int elementType = static_cast<int>(*(input + offset));
464             if (elementType != types::InternalType::ScilabString)
465             {
466                 Scierror(999, _("%s: Wrong value for input argument #%d: %d (String) expected.\n"), vec2varName.c_str(), 1, 11);
467                 return false;
468             }
469             int elementDims = static_cast<int>(*(input + offset + 1));
470             types::InternalType* element;
471             if (!readElement(input + offset, elementType, elementDims, inputRows - offset, offset, element))
472             {
473                 return false;
474             }
475             types::String* header = element->getAs<types::String>();
476             // ... and copy it in 'pStruct'
477             for (int i = 0; i < header->getSize(); ++i)
478             {
479                 pStruct->get(0)->addField(header->get(i));
480             }
481
482             for (int i = 1; i < iDims + 1; ++i)
483             {
484                 if (inputRows < 2 + offset)
485                 {
486                     Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 2, 1);
487                     return false;
488                 }
489                 // Extract the fields content infos and recursively call readElement
490                 elementType = static_cast<int>(*(input + offset));
491                 elementDims = static_cast<int>(*(input + offset + 1));
492                 if (!readElement(input + offset, elementType, elementDims, inputRows - offset, offset, element))
493                 {
494                     return false;
495                 }
496                 pStruct->get(0)->set(header->get(i - 1), element);
497             }
498             offset += offsetSave;
499             res = pStruct;
500             break;
501         }
502
503         default :
504             Scierror(999, _("%s: Wrong value for element #%d of input argument #%d: Unknown type.\n"), vec2varName.c_str(), offset + 1, 1);
505             return false;
506     }
507
508     return true;
509 }
510
511 bool vec2var(const std::vector<double> in, types::InternalType* &out)
512 {
513     const int iType = static_cast<int>(in[0]);
514     const int iDims = static_cast<int>(in[1]);
515
516     int offset = 0;
517     if (!readElement(&in[0], iType, iDims, static_cast<int>(in.size()), offset, out))
518     {
519         return false;
520     }
521
522     return true;
523 }