Instrument Neutral Distributed Interface INDI  2.0.2
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 <esr@snark.thyrsus.com>
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  */
63 int 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 
77 int 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  */
114 int 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 
122 int 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 
199 int 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>
276 u#include <cstring>
277 
278 static 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 
285 int 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 
361 int 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
Namespace to encapsulate INDI client, drivers, and mediator classes.
int main(int, char *[])