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