libacfutils
A general purpose library of utility functions designed to make it easier to develop addons for the X-Plane flight simulator.
Loading...
Searching...
No Matches
base64.c
1/*
2 * CDDL HEADER START
3 *
4 * This file and its contents are supplied under the terms of the
5 * Common Development and Distribution License ("CDDL"), version 1.0.
6 * You may only use this file in accordance with the terms of version
7 * 1.0 of the CDDL.
8 *
9 * A full copy of the text of the CDDL should have accompanied this
10 * source. A copy of the CDDL is also available via the Internet at
11 * http://www.illumos.org/license/CDDL.
12 *
13 * CDDL HEADER END
14 */
15/*
16 * Copyright 2018 Saso Kiselkov. All rights reserved.
17 */
18
19/*
20 * This is a simple and fast Base64 encoder/decoder implementation. In
21 * order to encode, call base64_encode. Conversely, to decode, use
22 * base64_decode. Be sure to use the base64_[ENC|DEC]_SIZE macros to prepare
23 * the buffers into which these functions write.
24 */
25
26#include <stdlib.h>
27#include <assert.h>
28#include <stdint.h>
29#include <sys/types.h>
30
31#include "acfutils/base64.h"
32
33/* Base64 encoding table */
34static const uint8_t *base64_enc_table = (uint8_t *)
35 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
36
37static const uint8_t *base64_enc_table_mod = (uint8_t *)
38 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.~";
39
45static uint8_t base64_dec_table[256] = {
46 'U', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
47 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
48 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
49 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
50 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
51 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
52 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
53 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
54 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
55 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
56 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
57 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
58 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
59 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
60 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
61 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
62 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
63 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
64 'x', 'x', 'x', 'x'
65};
66
67static uint8_t base64_dec_table_mod[256] = {
68 'U', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
69 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
70 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
71 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
72 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
73 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
74 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
75 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
76 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
77 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
78 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
79 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
80 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
81 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
82 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
83 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
84 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
85 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
86 'x', 'x', 'x', 'x'
87};
88
92size_t
93lacf_base64_encode(const uint8_t *raw, size_t raw_size, uint8_t *encoded)
94{
95 return (lacf_base64_encode2(raw, raw_size, encoded, 0));
96}
97
110size_t
111lacf_base64_encode2(const uint8_t *raw, size_t raw_size, uint8_t *encoded,
112 int mod)
113{
114 size_t i, j;
115 const uint8_t *enc_table = mod ? base64_enc_table_mod : base64_enc_table;
116 const char term_char = mod ? '-' : '=';
117
118 /* first encode all available full 3-byte blocks */
119 for (i = j = 0; i + 2 < raw_size; i+= 3, j += 4)
120 {
121 encoded[j] = enc_table[raw[i] >> 2];
122 encoded[j + 1] = enc_table[((raw[i] & 3) << 4) | (raw[i + 1] >> 4)];
123 encoded[j + 2] = enc_table[((raw[i + 1] & 0xf) << 2) | raw[i + 2] >> 6];
124 encoded[j + 3] = enc_table[(raw[i + 2] & 0x3f)];
125 }
126
127 /* now handle the special cases for the last block */
128 if (i + 1 < raw_size)
129 {
130 /* 2 bytes in the last block */
131 encoded[j] = enc_table[raw[i] >> 2];
132 encoded[j + 1] = enc_table[((raw[i] & 3) << 4) | (raw[i + 1] >> 4)];
133 encoded[j + 2] = enc_table[(raw[i + 1] & 0xf) << 2];
134 encoded[j + 3] = term_char;
135 j += 4;
136 }
137 else if (i < raw_size)
138 {
139 /* 1 byte in the last */
140 encoded[j] = enc_table[raw[i] >> 2];
141 encoded[j + 1] = enc_table[(raw[i] & 3) << 4];
142 encoded[j + 2] = term_char;
143 encoded[j + 3] = term_char;
144 j += 4;
145 }
146 /*
147 * In case the last block contained 3 bytes, it has been already taken
148 * care of in the main for loop above.
149 */
150
151 return j;
152}
153
163static inline void
164base64_init_dec_tables (void)
165{
166 int i;
167
168 for (i = 0; i < 64; i++)
169 base64_dec_table[base64_enc_table[i]] = i;
170 for (i = 0; i < 64; i++)
171 base64_dec_table_mod[base64_enc_table_mod[i]] = i;
172
173 // mark the tables as ready
174 base64_dec_table[0] = '|';
175 base64_dec_table_mod[0] = '|';
176}
177
181ssize_t
182lacf_base64_decode(const uint8_t *encoded, size_t encoded_size, uint8_t *raw)
183{
184 return (lacf_base64_decode2(encoded, encoded_size, raw, 0));
185}
186
198ssize_t
199lacf_base64_decode2(const uint8_t *encoded, size_t encoded_size, uint8_t *raw,
200 int mod)
201{
202 const uint8_t *dec_table = mod ? base64_dec_table_mod : base64_dec_table;
203 const char term_char = mod ? '-' : '=';
204
205 if (base64_dec_table[0] == 'U')
206 base64_init_dec_tables ();
207
208 size_t i, j;
209
210 /* bad size */
211 if (encoded_size & 3)
212 return -1;
213
214 /* nothing to decode */
215 if (!encoded_size)
216 return 0;
217
218 /* decode Base64 blocks up to the last one */
219 for (i = j = 0; i + 4 < encoded_size; i+= 4, j += 3)
220 {
221 if (dec_table[encoded[i + 0]] == 'x' ||
222 dec_table[encoded[i + 1]] == 'x' ||
223 dec_table[encoded[i + 2]] == 'x' ||
224 dec_table[encoded[i + 3]] == 'x')
225 return -1;
226
227 raw[j] = (dec_table[encoded[i]] << 2) | (dec_table[encoded[i + 1]] >> 4);
228 raw[j + 1] = (dec_table[encoded[i + 1]] << 4) |
229 (dec_table[encoded[i + 2]] >> 2);
230 raw[j + 2] = (dec_table[encoded[i + 2]] << 6) |
231 (dec_table[encoded[i + 3]]);
232 }
233
234 /* now handle the special ending cases for the last Base64 block */
235 if (dec_table[encoded[i + 0]] != 'x' &&
236 dec_table[encoded[i + 1]] != 'x' &&
237 encoded[i + 2] == term_char && encoded[i + 3] == term_char)
238 {
239 /* single-decoded-byte end block */
240 raw[j] = (dec_table[encoded[i]] << 2) |
241 (dec_table[encoded[i + 1]] >> 4);
242 raw[j + 1] = 0;
243 raw[j + 2] = 0;
244 j += 1;
245 }
246 else if (dec_table[encoded[i + 0]] != 'x' &&
247 dec_table[encoded[i + 1]] != 'x' &&
248 dec_table[encoded[i + 2]] != 'x' && encoded[i + 3] == term_char)
249 {
250 /* two-decoded-bytes end block */
251 raw[j] = (dec_table[encoded[i]] << 2) | (dec_table[encoded[i + 1]] >> 4);
252 raw[j + 1] = (dec_table[encoded[i + 1]] << 4) |
253 (dec_table[encoded[i + 2]] >> 2);
254 raw[j + 2] = 0;
255 j += 2;
256 }
257 else if (dec_table[encoded[i + 0]] != 'x' &&
258 dec_table[encoded[i + 1]] != 'x' &&
259 dec_table[encoded[i + 2]] != 'x' &&
260 dec_table[encoded[i + 3]] != 'x')
261 {
262 /* three-decoded-bytes end block */
263 raw[j] = (dec_table[encoded[i]] << 2) |
264 (dec_table[encoded[i + 1]] >> 4);
265 raw[j + 1] = (dec_table[encoded[i + 1]] << 4) |
266 (dec_table[encoded[i + 2]] >> 2);
267 raw[j + 2] = (dec_table[encoded[i + 2]] << 6) |
268 (dec_table[encoded[i + 3]]);
269 j += 3;
270 }
271 else
272 /* error decoding last block */
273 return -1;
274
275 return j;
276}
size_t lacf_base64_encode2(const uint8_t *raw, size_t raw_size, uint8_t *encoded, int mod)
Definition base64.c:111
size_t lacf_base64_encode(const uint8_t *raw, size_t raw_size, uint8_t *encoded)
Definition base64.c:93
ssize_t lacf_base64_decode(const uint8_t *encoded, size_t encoded_size, uint8_t *raw)
Definition base64.c:182
ssize_t lacf_base64_decode2(const uint8_t *encoded, size_t encoded_size, uint8_t *raw, int mod)
Definition base64.c:199