1#include <stdint.h>
2#include <stddef.h>
3#ifdef _OPENMP
4#include <omp.h>
5#endif
6
7#include "../include/libbase64.h"
8#include "codecs.h"
9#include "tables.h"
10
11// These static function pointers are initialized once when the library is
12// first used, and remain in use for the remaining lifetime of the program.
13// The idea being that CPU features don't change at runtime.
14static struct codec codec = { NULL, NULL };
15
16const uint8_t
17base64_table_enc[] =
18 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
19 "abcdefghijklmnopqrstuvwxyz"
20 "0123456789+/";
21
22// In the lookup table below, note that the value for '=' (character 61) is
23// 254, not 255. This character is used for in-band signaling of the end of
24// the datastream, and we will use that later. The characters A-Z, a-z, 0-9
25// and + / are mapped to their "decoded" values. The other bytes all map to
26// the value 255, which flags them as "invalid input".
27
28const uint8_t
29base64_table_dec[] =
30{
31 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 0..15
32 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 16..31
33 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, // 32..47
34 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 254, 255, 255, // 48..63
35 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64..79
36 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, // 80..95
37 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96..111
38 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, // 112..127
39 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 128..143
40 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
41 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
42 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
43 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
44 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
45 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
46 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
47};
48
49void
50base64_stream_encode_init (struct base64_state *state, int flags)
51{
52 // If any of the codec flags are set, redo choice:
53 if (codec.enc == NULL || flags & 0xFF) {
54 codec_choose(&codec, flags);
55 }
56 state->eof = 0;
57 state->bytes = 0;
58 state->carry = 0;
59 state->flags = flags;
60}
61
62void
63base64_stream_encode
64 ( struct base64_state *state
65 , const char *src
66 , size_t srclen
67 , char *out
68 , size_t *outlen
69 )
70{
71 codec.enc(state, src, srclen, out, outlen);
72}
73
74void
75base64_stream_encode_final
76 ( struct base64_state *state
77 , char *out
78 , size_t *outlen
79 )
80{
81 uint8_t *o = (uint8_t *)out;
82
83 if (state->bytes == 1) {
84 *o++ = base64_table_enc[state->carry];
85 *o++ = '=';
86 *o++ = '=';
87 *outlen = 3;
88 return;
89 }
90 if (state->bytes == 2) {
91 *o++ = base64_table_enc[state->carry];
92 *o++ = '=';
93 *outlen = 2;
94 return;
95 }
96 *outlen = 0;
97}
98
99void
100base64_stream_decode_init (struct base64_state *state, int flags)
101{
102 // If any of the codec flags are set, redo choice:
103 if (codec.dec == NULL || flags & 0xFF) {
104 codec_choose(&codec, flags);
105 }
106 state->eof = 0;
107 state->bytes = 0;
108 state->carry = 0;
109 state->flags = flags;
110}
111
112int
113base64_stream_decode
114 ( struct base64_state *state
115 , const char *src
116 , size_t srclen
117 , char *out
118 , size_t *outlen
119 )
120{
121 return codec.dec(state, src, srclen, out, outlen);
122}
123
124#ifdef _OPENMP
125
126 // Due to the overhead of initializing OpenMP and creating a team of
127 // threads, we require the data length to be larger than a threshold:
128 #define OMP_THRESHOLD 20000
129
130 // Conditionally include OpenMP-accelerated codec implementations:
131 #include "lib_openmp.c"
132#endif
133
134void
135base64_encode
136 ( const char *src
137 , size_t srclen
138 , char *out
139 , size_t *outlen
140 , int flags
141 )
142{
143 size_t s;
144 size_t t;
145 struct base64_state state;
146
147 #ifdef _OPENMP
148 if (srclen >= OMP_THRESHOLD) {
149 base64_encode_openmp(src, srclen, out, outlen, flags);
150 return;
151 }
152 #endif
153
154 // Init the stream reader:
155 base64_stream_encode_init(&state, flags);
156
157 // Feed the whole string to the stream reader:
158 base64_stream_encode(&state, src, srclen, out, &s);
159
160 // Finalize the stream by writing trailer if any:
161 base64_stream_encode_final(&state, out + s, &t);
162
163 // Final output length is stream length plus tail:
164 *outlen = s + t;
165}
166
167int
168base64_decode
169 ( const char *src
170 , size_t srclen
171 , char *out
172 , size_t *outlen
173 , int flags
174 )
175{
176 int ret;
177 struct base64_state state;
178
179 #ifdef _OPENMP
180 if (srclen >= OMP_THRESHOLD) {
181 return base64_decode_openmp(src, srclen, out, outlen, flags);
182 }
183 #endif
184
185 // Init the stream reader:
186 base64_stream_decode_init(&state, flags);
187
188 // Feed the whole string to the stream reader:
189 ret = base64_stream_decode(&state, src, srclen, out, outlen);
190
191 // If when decoding a whole block, we're still waiting for input then fail:
192 if (ret && (state.bytes == 0)) {
193 return ret;
194 }
195 return 0;
196}
197