Instrument Neutral Distributed Interface INDI 2.2.5
base64.c
Go to the documentation of this file.
1#if 0
2 INDI
3 Copyright (C) 2003 Elwood C. Downey
4
5 Complete rewrite of to64frombits() - gives 2x the performance
6 Complete rewrite of from64tobits_fast() - gives 3x the performance
7 Keeping from64tobits() for compatibility - gives 2.5x the performance
8 of the old implementation (Aug, 2016 by Rumen G.Bogdanovski)
9
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2.1 of the License, or (at your option) any later version.
14
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23
24 Adapted from code written by Eric S. Raymond <[email protected]>
25#endif
26
27/* Pair of functions to convert to/from base64.
28 * Also can be used to build a standalone utility and a loopback test.
29 * see http://www.faqs.org/rfcs/rfc3548.html
30 */
31
37#include <ctype.h>
38#include <stdint.h>
39#include "base64.h"
40#include "base64_luts.h"
41#include <stdio.h>
42
43/*
44 * as byteswap.h is not available on macos, add macro here
45 * Swap bytes in 16-bit value.
46 */
47//#define bswap_16(x) __builtin_bswap16 (x);
48#define bswap_16(x) ((uint16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)))
49
50#ifdef _WIN32
51#define IS_BIG_ENDIAN (!*(unsigned char *)&(uint16_t){1})
52#else
53#include <arpa/inet.h>
54#define IS_BIG_ENDIAN (1 == htons(1))
55#endif
56
57#define IS_LITTLE_ENDIAN (!IS_BIG_ENDIAN)
58
59/* convert inlen raw bytes at in to base64 string (NUL-terminated) at out.
60 * out size should be at least 4*inlen/3 + 4.
61 * return length of out (sans trailing NUL).
62 */
63int to64frombits_s(unsigned char *out, const unsigned char *in, int inlen, size_t outlen)
64{
65 size_t dlen = (((size_t)inlen + 2) / 3) * 4; /* 4/3, rounded up */
66
67 if (dlen > outlen) {
68 return 0;
69 }
70
71#pragma GCC diagnostic push
72#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
73 return to64frombits(out, in, inlen);
74#pragma GCC diagnostic pop
75}
76
77int to64frombits(unsigned char *out, const unsigned char *in, int inlen)
78{
79 uint16_t *b64lut = (uint16_t *)base64lut;
80 int dlen = ((inlen + 2) / 3) * 4; /* 4/3, rounded up */
81 uint16_t *wbuf = (uint16_t *)out;
82
83 for (; inlen > 2; inlen -= 3)
84 {
85 uint32_t n = in[0] << 16 | in[1] << 8 | in[2];
86
87 wbuf[0] = b64lut[n >> 12];
88 wbuf[1] = b64lut[n & 0x00000fff];
89
90 wbuf += 2;
91 in += 3;
92 }
93
94 out = (unsigned char *)wbuf;
95 if (inlen > 0)
96 {
97 unsigned char fragment;
98 *out++ = base64digits[in[0] >> 2];
99 fragment = (in[0] << 4) & 0x30;
100 if (inlen > 1)
101 fragment |= in[1] >> 4;
102 *out++ = base64digits[fragment];
103 *out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
104 *out++ = '=';
105 }
106 *out = 0; // NULL terminate
107 return dlen;
108}
109
110/* convert base64 at in to raw bytes out, returning count or <0 on error.
111 * base64 should not contain whitespaces.
112 * out should be at least 3/4 the length of in.
113 */
114int from64tobits(char *out, const char *in)
115{
116 char *cp = (char *)in;
117 while (*cp != 0)
118 cp += 4;
119 return from64tobits_fast(out, in, cp - in);
120}
121
122int from64tobits_fast(char *out, const char *in, int inlen)
123{
124 int outlen = 0;
125 uint8_t b1, b2, b3;
126 uint16_t s1, s2;
127 uint32_t n32;
128 int j;
129 int n = (inlen / 4) - 1;
130 uint16_t *inp = (uint16_t *)in;
131
132 for (j = 0; j < n; j++)
133 {
134 if (in[0] == '\n')
135 in++;
136 inp = (uint16_t *)in;
137
138 if IS_BIG_ENDIAN {
139 inp[0]=bswap_16(inp[0]);
140 inp[1]=bswap_16(inp[1]);
141 }
142 s1 = rbase64lut[inp[0]];
143 s2 = rbase64lut[inp[1]];
144
145 n32 = s1;
146 n32 <<= 10;
147 n32 |= s2 >> 2;
148
149 b3 = (n32 & 0x00ff);
150 n32 >>= 8;
151 b2 = (n32 & 0x00ff);
152 n32 >>= 8;
153 b1 = (n32 & 0x00ff);
154
155 out[0] = b1;
156 out[1] = b2;
157 out[2] = b3;
158
159 in += 4;
160 out += 3;
161 }
162 outlen = (inlen / 4 - 1) * 3;
163 if (in[0] == '\n')
164 in++;
165 inp = (uint16_t *)in;
166 if IS_BIG_ENDIAN {
167 inp[0]=bswap_16(inp[0]);
168 inp[1]=bswap_16(inp[1]);
169 }
170
171 s1 = rbase64lut[inp[0]];
172 s2 = rbase64lut[inp[1]];
173
174 n32 = s1;
175 n32 <<= 10;
176 n32 |= s2 >> 2;
177
178 b3 = (n32 & 0x00ff);
179 n32 >>= 8;
180 b2 = (n32 & 0x00ff);
181 n32 >>= 8;
182 b1 = (n32 & 0x00ff);
183
184 *out++ = b1;
185 outlen++;
186 if ((inp[1] & 0x00FF) != 0x003D)
187 {
188 *out++ = b2;
189 outlen++;
190 if ((inp[1] & 0xFF00) != 0x3D00)
191 {
192 *out++ = b3;
193 outlen++;
194 }
195 }
196 return outlen;
197}
198
199int from64tobits_fast_with_bug(char *out, const char *in, int inlen)
200{
201 int outlen = 0;
202 uint8_t b1, b2, b3;
203 uint16_t s1, s2;
204 uint32_t n32;
205 int j;
206 int n = (inlen / 4) - 1;
207 uint16_t *inp = (uint16_t *)in;
208
209 for (j = 0; j < n; j++)
210 {
211 if (in[0] == '\n')
212 in++;
213 inp = (uint16_t *)in;
214
215 s1 = rbase64lut[inp[0]];
216 s2 = rbase64lut[inp[1]];
217
218 n32 = s1;
219 n32 <<= 10;
220 n32 |= s2 >> 2;
221
222 b3 = (n32 & 0x00ff);
223 n32 >>= 8;
224 b2 = (n32 & 0x00ff);
225 n32 >>= 8;
226 b1 = (n32 & 0x00ff);
227
228 out[0] = b1;
229 out[1] = b2;
230 out[2] = b3;
231
232 in += 4;
233 out += 3;
234 }
235 outlen = (inlen / 4 - 1) * 3;
236 if (in[0] == '\n')
237 in++;
238 inp = (uint16_t *)in;
239
240 s1 = rbase64lut[inp[0]];
241 s2 = rbase64lut[inp[1]];
242
243 n32 = s1;
244 n32 <<= 10;
245 n32 |= s2 >> 2;
246
247 b3 = (n32 & 0x00ff);
248 n32 >>= 8;
249 b2 = (n32 & 0x00ff);
250 n32 >>= 8;
251 b1 = (n32 & 0x00ff);
252
253 *out++ = b1;
254 outlen++;
255 if ((inp[1] & 0x00FF) != 0x003D)
256 {
257 *out++ = b2;
258 outlen++;
259 if ((inp[1] & 0xFF00) != 0x3D00)
260 {
261 *out++ = b3;
262 outlen++;
263 }
264 }
265 return outlen;
266}
267
268
269#ifdef BASE64_PROGRAM
270/* standalone program that converts to/from base64.
271 * cc -o base64 -DBASE64_PROGRAM base64.c
272 */
273
274#include <stdio.h>
275#include <stdlib.h>
276u#include <cstring>
277
278static void usage(char *me)
279{
280 fprintf(stderr, "Purpose: convert stdin to/from base64 on stdout\n");
281 fprintf(stderr, "Usage: %s {-t,-f}\n", me);
282 exit(1);
283}
284
285int main(int ac, char *av[])
286{
287 int to64 = 1;
288
289 /* decide whether to or from base64 */
290 if (ac == 2 && strcmp(av[1], "-f") == 0)
291 to64 = 0;
292 else if (ac != 1 && (ac != 2 || strcmp(av[1], "-t")))
293 usage(av[0]);
294
295 if (to64)
296 {
297 unsigned char *rawin, *b64;
298 int i, n, nrawin, nb64;
299
300 /* read raw on stdin until EOF */
301 rawin = malloc(4096);
302 nrawin = 0;
303 while ((n = fread(rawin + nrawin, 1, 4096, stdin)) > 0)
304 rawin = realloc(rawin, (nrawin += n) + 4096);
305
306 /* convert to base64 */
307 b64 = malloc(4 * nrawin / 3 + 4);
308 nb64 = to64frombits(b64, rawin, nrawin);
309
310 size_t written = 0;
311 size_t towrite = nb64;
312 while (written < nb64)
313 {
314 size_t wr = fwrite(b64 + written, 1, nb64, stdout);
315 if (wr > 0)
316 {
317 towrite -= wr;
318 written += wr;
319 }
320 }
321 }
322 else
323 {
324 unsigned char *raw, *b64;
325 int n, nraw, nb64;
326
327 /* read base64 on stdin until EOF */
328 b64 = malloc(4096);
329 nb64 = 0;
330 while ((n = fread(b64 + nb64, 1, 4096, stdin)) > 0)
331 b64 = realloc(b64, (nb64 += n) + 4096);
332 b64[nb64] = '\0';
333
334 /* convert to raw */
335 raw = malloc(3 * nb64 / 4);
336 nraw = from64tobits_fast(raw, b64, nb64);
337 if (nraw < 0)
338 {
339 fprintf(stderr, "base64 conversion error: %d\n", nraw);
340 return (1);
341 }
342
343 /* write */
344 fwrite(raw, 1, nraw, stdout);
345 }
346
347 return (0);
348}
349
350#endif
351
352#ifdef LOOPBACK_TEST
353/* standalone test that reads binary on stdin, converts to base64 and back,
354 * then compares. exit 0 if compares the same else 1
355 */
356
357#include <stdio.h>
358#include <stdlib.h>
359#include <cstring>
360
361int main(int ac, char *av[])
362{
363 unsigned char *rawin, *b64, *rawback;
364 int n, nrawin, nrawback, nb64;
365
366 /* read raw on stdin until EOF */
367 rawin = malloc(4096);
368 nrawin = 0;
369 while ((n = fread(rawin + nrawin, 1, 4096, stdin)) > 0)
370 rawin = realloc(rawin, (nrawin += n) + 4096);
371
372 /* convert to base64 */
373 b64 = malloc(4 * nrawin * 3 + 4);
374 nb64 = to64frombits(b64, rawin, nrawin);
375
376 /* convert back to raw */
377 rawback = malloc(3 * nb64 / 4);
378 nrawback = from64tobits_fast(rawback, b64, nrawin);
379 if (nrawback < 0)
380 {
381 fprintf(stderr, "base64 error: %d\n", nrawback);
382 return (1);
383 }
384 if (nrawback != nrawin)
385 {
386 fprintf(stderr, "base64 back length %d != %d\n", nrawback, nrawin);
387 return (1);
388 }
389
390 /* compare */
391 if (memcmp(rawback, rawin, nrawin))
392 {
393 fprintf(stderr, "compare error\n");
394 return (1);
395 }
396
397 /* success */
398 return (0);
399}
400#endif
#define IS_BIG_ENDIAN
Definition base64.c:54
int from64tobits(char *out, const char *in)
Convert base64 to bytes array.
Definition base64.c:114
int to64frombits_s(unsigned char *out, const unsigned char *in, int inlen, size_t outlen)
Convert bytes array to base64.
Definition base64.c:63
int to64frombits(unsigned char *out, const unsigned char *in, int inlen)
Definition base64.c:77
int from64tobits_fast_with_bug(char *out, const char *in, int inlen)
Definition base64.c:199
int from64tobits_fast(char *out, const char *in, int inlen)
Definition base64.c:122
#define bswap_16(x)
Definition base64.c:48
int main()
char * me
Definition indidriver.c:50
void usage(void)
Namespace to encapsulate INDI client, drivers, and mediator classes.