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