Xcos XMI format: fix exprs encoding
[scilab.git] / scilab / modules / scicos / src / cpp / base64.hxx
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2016 - Scilab Enterprises - Clement DAVID
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 #ifndef MODULES_SCICOS_SRC_CPP_BASE64_HXX_
17 #define MODULES_SCICOS_SRC_CPP_BASE64_HXX_
18
19 #include <array>
20 #include <vector>
21 #include <string>
22 #include <limits>
23 #include <cstdio> // for sprintf
24
25 namespace org_scilab_modules_scicos
26 {
27
28 /*
29  * Encode a string to a base64 encoded string.
30  *
31  * This implement the RFC 2045 Base64 variant. See https://tools.ietf.org/html/rfc2045
32  */
33 struct base64
34 {
35     template<typename T> inline
36     static std::string encode(const T& v);
37     template<typename T> inline
38     static T decode(const std::string& content);
39 };
40 template<> inline std::string base64::encode(const std::string& v);
41 template<> inline std::string base64::decode(const std::string& content);
42
43
44 template<> inline
45 std::string base64::encode<std::string>(const std::string& strValue)
46 {
47     const std::string Base64Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
48     const char Base64Pad = '=';
49
50     // tips given by :
51     //  * http://www.adp-gmbh.ch/cpp/common/base64.html
52     //  * http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c
53     std::string content;
54
55     int val = 0;
56     int val_byte = -6;
57     for (unsigned char c : strValue)
58     {
59         val = (val << 8) + c;
60         val_byte += 8;
61
62         while (val_byte >= 0)
63         {
64             content.push_back(Base64Alphabet[(val >> val_byte) & 0x3F]);
65             val_byte -= 6;
66         }
67     }
68     // the trailing part is left in val_byte
69     if (val_byte > -6)
70     {
71         content.push_back(Base64Alphabet[((val << 8) >> (val_byte + 8)) & 0x3F]);
72     }
73     // add padding if needed
74     while (content.size() % 4)
75     {
76         content.push_back(Base64Pad);
77     }
78
79     return content;
80 }
81
82 template<> inline
83 std::string base64::decode<std::string>(const std::string& content)
84 {
85     const std::string Base64Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
86
87     // inverse table (might be const or constexpr)
88     std::array<char, 255> T;
89     T.fill(255);
90     for (size_t i = 0; i < Base64Alphabet.length(); i++)
91     {
92         T[Base64Alphabet[i]] = i;
93     }
94
95     // decoding loop
96     std::string strValue;
97
98     int val = 0;
99     int val_byte = -8;
100     for (char c : content)
101     {
102         if (T[c] == std::numeric_limits<unsigned char>::max()) // not in the table, stop decoding
103         {
104             break;
105         }
106
107         val = (val << 6) + T[c];
108         val_byte += 6;
109         if (val_byte >= 0)
110         {
111             char c = (val >> val_byte) & 0xFF;
112             if (c < 0)
113             {
114                 break;
115             }
116             strValue.push_back(c);
117             val_byte -= 8;
118         }
119     }
120
121     return strValue;
122 }
123
124
125 template<> inline
126 std::string base64::encode(const std::vector<double>& v)
127 {
128     // convert to string components and compress using hexfloat conversion
129     std::string strValue;
130     char buf[std::numeric_limits<double>::digits + 2];
131     for (double const& d : v)
132     {
133         sprintf(buf, "%a ", d);
134         strValue.insert(strValue.size(), buf);
135     }
136
137     return encode<std::string>(strValue);
138 }
139
140 template<> inline
141 std::vector<double> base64::decode(const std::string& content)
142 {
143     std::string strValue = decode<std::string>(content);
144     std::vector<double> vector;
145
146     for (size_t pos = 0; pos < strValue.length(); pos = strValue.find(' ', pos) + 1)
147     {
148         vector.push_back(std::stod(strValue.data() + pos));
149     }
150     return vector;
151 }
152
153 } /* namespace org_scilab_modules_xcos */
154
155 #endif /* MODULES_SCICOS_SRC_CPP_BASE64_HXX_ */