comparison base64.c @ 1:5afdb14df924

sci: add support for storing results
author David Demelier <markand@malikania.fr>
date Tue, 08 Jun 2021 08:40:01 +0200
parents
children
comparison
equal deleted inserted replaced
0:f1de39079243 1:5afdb14df924
1 /*
2 * base64.h -- base64 encoding and decoding
3 *
4 * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <assert.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <string.h>
23
24 #include "base64.h"
25
26 int
27 b64_isbase64(unsigned char ch)
28 {
29 return isalnum(ch) || ch == '+' || ch == '-' || ch == '_' || ch == '/';
30 }
31
32 int
33 b64_isvalid(unsigned char ch)
34 {
35 return b64_isbase64(ch) || ch == '=';
36 }
37
38 unsigned char
39 b64_lookup(unsigned char value)
40 {
41 assert(value < 64);
42
43 static const char *table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
44
45 return table[value];
46 }
47
48 unsigned char
49 b64_rlookup(unsigned char ch)
50 {
51 assert(b64_isbase64(ch));
52
53 if (ch >= '0' && ch <= '9')
54 return ch + 4;
55 if (ch >= 'A' && ch <= 'Z')
56 return ch - 65;
57 if (ch >= 'a' && ch <= 'z')
58 return ch - 71;
59
60 /* '-' is base64url support. */
61 return ch == '+' || ch == '-' ? 62U : 63U;
62 }
63
64 size_t
65 b64_encode(const char *src, size_t srcsz, char *dst, size_t dstsz)
66 {
67 assert(src);
68 assert(dst);
69
70 size_t nwritten = 0;
71
72 if (srcsz == (size_t)-1)
73 srcsz = strlen(src);
74
75 while (srcsz && dstsz) {
76 char inputbuf[3] = {0};
77 int count = 0;
78
79 while (srcsz && count < 3) {
80 inputbuf[count++] = *src++;
81 --srcsz;
82 }
83
84 if (dstsz < 4) {
85 errno = ERANGE;
86 return -1;
87 }
88
89 *dst++ = b64_lookup(inputbuf[0] >> 2 & 0x3f);
90 *dst++ = b64_lookup((inputbuf[0] << 4 & 0x3f) | (inputbuf[1] >> 4 & 0x0f));
91
92 if (count < 2)
93 *dst++ = '=';
94 else
95 *dst++ = b64_lookup((inputbuf[1] << 2 & 0x3c) | (inputbuf[2] >> 6 & 0x03));
96
97 if (count < 3)
98 *dst++ = '=';
99 else
100 *dst++ = b64_lookup(inputbuf[2] & 0x3f);
101
102 nwritten += 4;
103 dstsz -= 4;
104 }
105
106 /* Not enough room to store '\0'. */
107 if (dstsz == 0) {
108 errno = ERANGE;
109 return -1;
110 }
111
112 *dst = '\0';
113
114 return nwritten;
115 }
116
117 size_t
118 b64_decode(const char *src, size_t srcsz, char *dst, size_t dstsz)
119 {
120 assert(src);
121 assert(dst);
122
123 size_t nwritten = 0;
124
125 if (srcsz == (size_t)-1)
126 srcsz = strlen(src);
127
128 while (srcsz && dstsz) {
129 int i = 0, r = 3;
130 unsigned int inputbuf[4] = {0};
131
132 for (; srcsz && i < 4; i++) {
133 if (*src == '=') {
134 /*
135 * '=' is only allowed in last 2 characters,
136 * otherwise it means we need less data.
137 */
138 if (i <= 1)
139 goto eilseq;
140
141 /* Less data required. */
142 --r;
143 } else if (!b64_isvalid(*src))
144 goto eilseq;
145
146 if (b64_isbase64(*src))
147 inputbuf[i] = b64_rlookup(*src);
148
149 ++src;
150 --srcsz;
151 }
152
153 /* Make sure we haven't seen AB=Z as well. */
154 if (i != 4 || (src[-2] == '=' && src[-1] != '='))
155 goto eilseq;
156 if ((size_t)r >= dstsz)
157 goto erange;
158
159 *dst++ = ((inputbuf[0] << 2) & 0xfc) |
160 ((inputbuf[1] >> 4) & 0x03);
161
162 if (r >= 2)
163 *dst++ = ((inputbuf[1] << 4) & 0xf0) | ((inputbuf[2] >> 2) & 0x0f);
164 if (r >= 3)
165 *dst++ = ((inputbuf[2] << 6) & 0xc0) | (inputbuf[3] & 0x3f);
166
167 nwritten += r;
168 dstsz -= r;
169 }
170
171 /* Not enough room to store '\0'. */
172 if (dstsz == 0)
173 goto erange;
174
175 *dst = '\0';
176
177 return nwritten;
178
179 eilseq:
180 errno = EILSEQ;
181 return -1;
182
183 erange:
184 errno = ERANGE;
185 return -1;
186 }