|
1 /* |
|
2 * base64.c - Base 64 encoding/decoding implementation |
|
3 * Copyright (C) 2006 Collabora Ltd. |
|
4 * |
|
5 * This library is free software; you can redistribute it and/or |
|
6 * modify it under the terms of the GNU Lesser General Public |
|
7 * License as published by the Free Software Foundation; either |
|
8 * version 2.1 of the License, or (at your option) any later version. |
|
9 * |
|
10 * This library is distributed in the hope that it will be useful, |
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 * Lesser General Public License for more details. |
|
14 * |
|
15 * You should have received a copy of the GNU Lesser General Public |
|
16 * License along with this library; if not, write to the Free Software |
|
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|
18 */ |
|
19 |
|
20 #include <ctype.h> |
|
21 #include <string.h> |
|
22 |
|
23 #include <glib.h> |
|
24 |
|
25 #include "base64.h" |
|
26 |
|
27 /* |
|
28 |AAAA AABB|BBBB CCCC|CCDD DDDD| |
|
29 |
|
30 0xFC = 1111 1100 |
|
31 0x03 = 0000 0011 |
|
32 0xF0 = 1111 0000 |
|
33 0x0F = 0000 1111 |
|
34 0xC0 = 1100 0000 |
|
35 0x3F = 0011 1111 |
|
36 |
|
37 3 input bytes = 4 output bytes; |
|
38 2 input bytes = 2 output bytes; |
|
39 1 input byte = 1 output byte. |
|
40 */ |
|
41 |
|
42 |
|
43 #ifdef EMULATOR |
|
44 #include "libloudmouth_wsd_solution.h" |
|
45 |
|
46 GET_STATIC_ARRAY_FROM_TLS(encoding, lm_base64, gchar) |
|
47 #define encoding (GET_WSD_VAR_NAME(encoding, lm_base64, s)()) |
|
48 |
|
49 #else |
|
50 |
|
51 static const gchar *encoding = |
|
52 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
|
53 |
|
54 #endif |
|
55 |
|
56 |
|
57 |
|
58 static const guint decoding[256] = |
|
59 { |
|
60 /* ... */ |
|
61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
63 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
64 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
65 0, 0, 0, |
|
66 /* + */ |
|
67 62, |
|
68 /* ... */ |
|
69 0, 0, 0, |
|
70 /* / , 0-9 */ |
|
71 63, |
|
72 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, |
|
73 /* ... */ |
|
74 0, 0, 0, 0, 0, 0, 0, |
|
75 /* A */ |
|
76 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, |
|
77 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, |
|
78 /* ... */ |
|
79 0, 0, 0, 0, 0, 0, |
|
80 /* a */ |
|
81 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, |
|
82 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 |
|
83 }; |
|
84 |
|
85 #define GET_6_BITS_0(s) (((s)[0] & 0xFC) >> 2) |
|
86 #define GET_6_BITS_1(s) (((s)[0] & 0x03) << 4) | \ |
|
87 (((s)[1] & 0xF0) >> 4) |
|
88 #define GET_6_BITS_2(s) (((s)[1] & 0x0F) << 2) | \ |
|
89 (((s)[2] & 0xC0) >> 6) |
|
90 #define GET_6_BITS_3(s) (((s)[2] & 0x3F) << 0) |
|
91 |
|
92 #define GET_BYTE_0(s) (((decoding[(guchar)(s)[0]] & 0x3F) << 2) | \ |
|
93 ((decoding[(guchar)(s)[1]] & 0x30) >> 4)) |
|
94 #define GET_BYTE_1(s) (((decoding[(guchar)(s)[1]] & 0x0F) << 4) | \ |
|
95 ((decoding[(guchar)(s)[2]] & 0x3C) >> 2)) |
|
96 #define GET_BYTE_2(s) (((decoding[(guchar)(s)[2]] & 0x03) << 6) | \ |
|
97 ((decoding[(guchar)(s)[3]] & 0xFF) << 0)) |
|
98 |
|
99 gchar *_lm_base64_encode (const gchar *txt, gsize n) |
|
100 { |
|
101 guint i; |
|
102 guint len; |
|
103 GString *tmp; |
|
104 GString *str = g_string_new_len (txt, n); |
|
105 |
|
106 len = str->len; |
|
107 /* TODO: calculate requisite output string length and allocate that big a |
|
108 * GString */ |
|
109 tmp = g_string_new (""); |
|
110 |
|
111 for (i = 0; i < len; i += 3) |
|
112 { |
|
113 guint c1, c2, c3, c4; |
|
114 |
|
115 switch (i + 3 - len) |
|
116 { |
|
117 case 1: |
|
118 c1 = encoding[GET_6_BITS_0 (str->str + i)]; |
|
119 c2 = encoding[GET_6_BITS_1 (str->str + i)]; |
|
120 c3 = encoding[GET_6_BITS_2 (str->str + i)]; |
|
121 c4 = '='; |
|
122 break; |
|
123 case 2: |
|
124 c1 = encoding[GET_6_BITS_0 (str->str + i)]; |
|
125 c2 = encoding[GET_6_BITS_1 (str->str + i)]; |
|
126 c3 = '='; |
|
127 c4 = '='; |
|
128 break; |
|
129 default: |
|
130 c1 = encoding[GET_6_BITS_0 (str->str + i)]; |
|
131 c2 = encoding[GET_6_BITS_1 (str->str + i)]; |
|
132 c3 = encoding[GET_6_BITS_2 (str->str + i)]; |
|
133 c4 = encoding[GET_6_BITS_3 (str->str + i)]; |
|
134 } |
|
135 |
|
136 g_string_append_printf (tmp, "%c%c%c%c", c1, c2, c3, c4); |
|
137 } |
|
138 |
|
139 return g_string_free (tmp, FALSE); |
|
140 } |
|
141 |
|
142 gchar *_lm_base64_decode (const gchar *str, gsize *len) |
|
143 { |
|
144 guint i; |
|
145 GString *tmp; |
|
146 char group[4]; |
|
147 guint filled = 0; |
|
148 |
|
149 *len = 0; |
|
150 |
|
151 for (i = 0; str[i]; i++) |
|
152 { |
|
153 if (str[i] != 'A' && |
|
154 str[i] != '=' && |
|
155 !isspace(str[i]) && |
|
156 decoding[(guchar) str[i]] == 0) |
|
157 { |
|
158 g_debug ("bad character %x at byte %u", (guchar)str[i], i); |
|
159 return NULL; |
|
160 } |
|
161 } |
|
162 |
|
163 tmp = g_string_new (""); |
|
164 |
|
165 for (i = 0; str[i]; i++) |
|
166 { |
|
167 if (isspace(str[i])) |
|
168 continue; |
|
169 |
|
170 group[filled++] = str[i]; |
|
171 |
|
172 if (filled == 4) |
|
173 { |
|
174 if (group[3] == '=') |
|
175 { |
|
176 if (group[2] == '=') |
|
177 { |
|
178 g_string_append_c (tmp, GET_BYTE_0(group)); |
|
179 } |
|
180 else |
|
181 { |
|
182 g_string_append_c (tmp, GET_BYTE_0(group)); |
|
183 g_string_append_c (tmp, GET_BYTE_1(group)); |
|
184 } |
|
185 } |
|
186 else |
|
187 { |
|
188 g_string_append_c (tmp, GET_BYTE_0(group)); |
|
189 g_string_append_c (tmp, GET_BYTE_1(group)); |
|
190 g_string_append_c (tmp, GET_BYTE_2(group)); |
|
191 } |
|
192 filled = 0; |
|
193 } |
|
194 } |
|
195 |
|
196 if (filled) |
|
197 { |
|
198 g_debug ("insufficient padding at end of base64 string:\n%s", str); |
|
199 g_string_free (tmp, TRUE); |
|
200 return NULL; |
|
201 } |
|
202 |
|
203 *len = tmp->len; |
|
204 return g_string_free (tmp, FALSE); |
|
205 } |
|
206 |
|
207 |