Instrument Neutral Distributed Interface INDI  1.9.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 <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 #include <arpa/inet.h>
51 #define IS_BIG_ENDIAN (1 == htons(1))
52 #define IS_LITTLE_ENDIAN (!IS_BIG_ENDIAN)
53 
54 /* convert inlen raw bytes at in to base64 string (NUL-terminated) at out.
55  * out size should be at least 4*inlen/3 + 4.
56  * return length of out (sans trailing NUL).
57  */
58 int to64frombits_s(unsigned char *out, const unsigned char *in, int inlen, size_t outlen)
59 {
60  size_t dlen = (((size_t)inlen + 2) / 3) * 4; /* 4/3, rounded up */
61 
62  if (dlen > outlen) {
63  return 0;
64  }
65 
66 #pragma GCC diagnostic push
67 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
68  return to64frombits(out, in, inlen);
69 #pragma GCC diagnostic pop
70 }
71 
72 int to64frombits(unsigned char *out, const unsigned char *in, int inlen)
73 {
74  uint16_t *b64lut = (uint16_t *)base64lut;
75  int dlen = ((inlen + 2) / 3) * 4; /* 4/3, rounded up */
76  uint16_t *wbuf = (uint16_t *)out;
77 
78  for (; inlen > 2; inlen -= 3)
79  {
80  uint32_t n = in[0] << 16 | in[1] << 8 | in[2];
81 
82  wbuf[0] = b64lut[n >> 12];
83  wbuf[1] = b64lut[n & 0x00000fff];
84 
85  wbuf += 2;
86  in += 3;
87  }
88 
89  out = (unsigned char *)wbuf;
90  if (inlen > 0)
91  {
92  unsigned char fragment;
93  *out++ = base64digits[in[0] >> 2];
94  fragment = (in[0] << 4) & 0x30;
95  if (inlen > 1)
96  fragment |= in[1] >> 4;
97  *out++ = base64digits[fragment];
98  *out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
99  *out++ = '=';
100  }
101  *out = 0; // NULL terminate
102  return dlen;
103 }
104 
105 /* convert base64 at in to raw bytes out, returning count or <0 on error.
106  * base64 should not contain whitespaces.
107  * out should be at least 3/4 the length of in.
108  */
109 int from64tobits(char *out, const char *in)
110 {
111  char *cp = (char *)in;
112  while (*cp != 0)
113  cp += 4;
114  return from64tobits_fast(out, in, cp - in);
115 }
116 
117 int from64tobits_fast(char *out, const char *in, int inlen)
118 {
119  int outlen = 0;
120  uint8_t b1, b2, b3;
121  uint16_t s1, s2;
122  uint32_t n32;
123  int j;
124  int n = (inlen / 4) - 1;
125  uint16_t *inp = (uint16_t *)in;
126 
127  for (j = 0; j < n; j++)
128  {
129  if (in[0] == '\n')
130  in++;
131  inp = (uint16_t *)in;
132 
133  if IS_BIG_ENDIAN {
134  inp[0]=bswap_16(inp[0]);
135  inp[1]=bswap_16(inp[1]);
136  }
137  s1 = rbase64lut[inp[0]];
138  s2 = rbase64lut[inp[1]];
139 
140  n32 = s1;
141  n32 <<= 10;
142  n32 |= s2 >> 2;
143 
144  b3 = (n32 & 0x00ff);
145  n32 >>= 8;
146  b2 = (n32 & 0x00ff);
147  n32 >>= 8;
148  b1 = (n32 & 0x00ff);
149 
150  out[0] = b1;
151  out[1] = b2;
152  out[2] = b3;
153 
154  in += 4;
155  out += 3;
156  }
157  outlen = (inlen / 4 - 1) * 3;
158  if (in[0] == '\n')
159  in++;
160  inp = (uint16_t *)in;
161  if IS_BIG_ENDIAN {
162  inp[0]=bswap_16(inp[0]);
163  inp[1]=bswap_16(inp[1]);
164  }
165 
166  s1 = rbase64lut[inp[0]];
167  s2 = rbase64lut[inp[1]];
168 
169  n32 = s1;
170  n32 <<= 10;
171  n32 |= s2 >> 2;
172 
173  b3 = (n32 & 0x00ff);
174  n32 >>= 8;
175  b2 = (n32 & 0x00ff);
176  n32 >>= 8;
177  b1 = (n32 & 0x00ff);
178 
179  *out++ = b1;
180  outlen++;
181  if ((inp[1] & 0x00FF) != 0x003D)
182  {
183  *out++ = b2;
184  outlen++;
185  if ((inp[1] & 0xFF00) != 0x3D00)
186  {
187  *out++ = b3;
188  outlen++;
189  }
190  }
191  return outlen;
192 }
193 
194 int from64tobits_fast_with_bug(char *out, const char *in, int inlen)
195 {
196  int outlen = 0;
197  uint8_t b1, b2, b3;
198  uint16_t s1, s2;
199  uint32_t n32;
200  int j;
201  int n = (inlen / 4) - 1;
202  uint16_t *inp = (uint16_t *)in;
203 
204  for (j = 0; j < n; j++)
205  {
206  if (in[0] == '\n')
207  in++;
208  inp = (uint16_t *)in;
209 
210  s1 = rbase64lut[inp[0]];
211  s2 = rbase64lut[inp[1]];
212 
213  n32 = s1;
214  n32 <<= 10;
215  n32 |= s2 >> 2;
216 
217  b3 = (n32 & 0x00ff);
218  n32 >>= 8;
219  b2 = (n32 & 0x00ff);
220  n32 >>= 8;
221  b1 = (n32 & 0x00ff);
222 
223  out[0] = b1;
224  out[1] = b2;
225  out[2] = b3;
226 
227  in += 4;
228  out += 3;
229  }
230  outlen = (inlen / 4 - 1) * 3;
231  if (in[0] == '\n')
232  in++;
233  inp = (uint16_t *)in;
234 
235  s1 = rbase64lut[inp[0]];
236  s2 = rbase64lut[inp[1]];
237 
238  n32 = s1;
239  n32 <<= 10;
240  n32 |= s2 >> 2;
241 
242  b3 = (n32 & 0x00ff);
243  n32 >>= 8;
244  b2 = (n32 & 0x00ff);
245  n32 >>= 8;
246  b1 = (n32 & 0x00ff);
247 
248  *out++ = b1;
249  outlen++;
250  if ((inp[1] & 0x00FF) != 0x003D)
251  {
252  *out++ = b2;
253  outlen++;
254  if ((inp[1] & 0xFF00) != 0x3D00)
255  {
256  *out++ = b3;
257  outlen++;
258  }
259  }
260  return outlen;
261 }
262 
263 
264 #ifdef BASE64_PROGRAM
265 /* standalone program that converts to/from base64.
266  * cc -o base64 -DBASE64_PROGRAM base64.c
267  */
268 
269 #include <stdio.h>
270 #include <stdlib.h>
271 u#include <cstring>
272 
273 static void usage(char *me)
274 {
275  fprintf(stderr, "Purpose: convert stdin to/from base64 on stdout\n");
276  fprintf(stderr, "Usage: %s {-t,-f}\n", me);
277  exit(1);
278 }
279 
280 int main(int ac, char *av[])
281 {
282  int to64 = 1;
283 
284  /* decide whether to or from base64 */
285  if (ac == 2 && strcmp(av[1], "-f") == 0)
286  to64 = 0;
287  else if (ac != 1 && (ac != 2 || strcmp(av[1], "-t")))
288  usage(av[0]);
289 
290  if (to64)
291  {
292  unsigned char *rawin, *b64;
293  int i, n, nrawin, nb64;
294 
295  /* read raw on stdin until EOF */
296  rawin = malloc(4096);
297  nrawin = 0;
298  while ((n = fread(rawin + nrawin, 1, 4096, stdin)) > 0)
299  rawin = realloc(rawin, (nrawin += n) + 4096);
300 
301  /* convert to base64 */
302  b64 = malloc(4 * nrawin / 3 + 4);
303  nb64 = to64frombits(b64, rawin, nrawin);
304 
305  size_t written = 0;
306  size_t towrite = nb64;
307  while (written < nb64)
308  {
309  size_t wr = fwrite(b64 + written, 1, nb64, stdout);
310  if (wr > 0)
311  {
312  towrite -= wr;
313  written += wr;
314  }
315  }
316  }
317  else
318  {
319  unsigned char *raw, *b64;
320  int n, nraw, nb64;
321 
322  /* read base64 on stdin until EOF */
323  b64 = malloc(4096);
324  nb64 = 0;
325  while ((n = fread(b64 + nb64, 1, 4096, stdin)) > 0)
326  b64 = realloc(b64, (nb64 += n) + 4096);
327  b64[nb64] = '\0';
328 
329  /* convert to raw */
330  raw = malloc(3 * nb64 / 4);
331  nraw = from64tobits_fast(raw, b64, nb64);
332  if (nraw < 0)
333  {
334  fprintf(stderr, "base64 conversion error: %d\n", nraw);
335  return (1);
336  }
337 
338  /* write */
339  fwrite(raw, 1, nraw, stdout);
340  }
341 
342  return (0);
343 }
344 
345 #endif
346 
347 #ifdef LOOPBACK_TEST
348 /* standalone test that reads binary on stdin, converts to base64 and back,
349  * then compares. exit 0 if compares the same else 1
350  */
351 
352 #include <stdio.h>
353 #include <stdlib.h>
354 #include <cstring>
355 
356 int main(int ac, char *av[])
357 {
358  unsigned char *rawin, *b64, *rawback;
359  int n, nrawin, nrawback, nb64;
360 
361  /* read raw on stdin until EOF */
362  rawin = malloc(4096);
363  nrawin = 0;
364  while ((n = fread(rawin + nrawin, 1, 4096, stdin)) > 0)
365  rawin = realloc(rawin, (nrawin += n) + 4096);
366 
367  /* convert to base64 */
368  b64 = malloc(4 * nrawin * 3 + 4);
369  nb64 = to64frombits(b64, rawin, nrawin);
370 
371  /* convert back to raw */
372  rawback = malloc(3 * nb64 / 4);
373  nrawback = from64tobits_fast(rawback, b64, nrawin);
374  if (nrawback < 0)
375  {
376  fprintf(stderr, "base64 error: %d\n", nrawback);
377  return (1);
378  }
379  if (nrawback != nrawin)
380  {
381  fprintf(stderr, "base64 back length %d != %d\n", nrawback, nrawin);
382  return (1);
383  }
384 
385  /* compare */
386  if (memcmp(rawback, rawin, nrawin))
387  {
388  fprintf(stderr, "compare error\n");
389  return (1);
390  }
391 
392  /* success */
393  return (0);
394 }
395 #endif
to64frombits_s
int to64frombits_s(unsigned char *out, const unsigned char *in, int inlen, size_t outlen)
Convert bytes array to base64.
Definition: base64.c:58
bswap_16
#define bswap_16(x)
Definition: base64.c:48
Aux::ANY
@ ANY
Definition: celestronauxpacket.h:86
to64frombits
int to64frombits(unsigned char *out, const unsigned char *in, int inlen)
Definition: base64.c:72
IS_BIG_ENDIAN
#define IS_BIG_ENDIAN
Definition: base64.c:51
base64_luts.h
base64.h
from64tobits_fast_with_bug
int from64tobits_fast_with_bug(char *out, const char *in, int inlen)
Definition: base64.c:194
main
int main(int, char **)
Definition: tutorial_client.cpp:53
INDI
Namespace to encapsulate INDI client, drivers, and mediator classes.
Definition: AlignmentSubsystemForClients.cpp:11
me
char * me
Definition: indidriver.c:50
from64tobits_fast
int from64tobits_fast(char *out, const char *in, int inlen)
Definition: base64.c:117
from64tobits
int from64tobits(char *out, const char *in)
Convert base64 to bytes array.
Definition: base64.c:109