@@ -132,7 +132,7 @@ size_t base64_decoded_size(const TypeName* src, size_t size) {
132
132
133
133
134
134
// supports regular and URL-safe base64
135
- static const int unbase64_table[] =
135
+ static const int8_t unbase64_table[] =
136
136
{ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -2 , -1 , -1 , -2 , -1 , -1 ,
137
137
-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
138
138
-2 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 62 , -1 , 62 , -1 , 63 ,
@@ -150,62 +150,83 @@ static const int unbase64_table[] =
150
150
-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
151
151
-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1
152
152
};
153
- #define unbase64 (x ) unbase64_table[(uint8_t )(x)]
153
+ #define unbase64 (x ) \
154
+ static_cast <uint8_t >(unbase64_table[static_cast <uint8_t >(x)])
154
155
155
156
156
157
template <typename TypeName>
157
- size_t base64_decode (char * buf,
158
- size_t len,
159
- const TypeName* src,
160
- const size_t srcLen) {
161
- char a, b, c, d;
162
- char * dst = buf;
163
- char * dstEnd = buf + len;
164
- const TypeName* srcEnd = src + srcLen;
165
-
166
- while (src < srcEnd && dst < dstEnd) {
167
- int remaining = srcEnd - src;
168
-
169
- while (unbase64 (*src) < 0 && src < srcEnd)
170
- src++, remaining--;
171
- if (remaining == 0 || *src == ' =' )
172
- break ;
173
- a = unbase64 (*src++);
174
-
175
- while (unbase64 (*src) < 0 && src < srcEnd)
176
- src++, remaining--;
177
- if (remaining <= 1 || *src == ' =' )
178
- break ;
179
- b = unbase64 (*src++);
180
-
181
- *dst++ = (a << 2 ) | ((b & 0x30 ) >> 4 );
182
- if (dst == dstEnd)
183
- break ;
184
-
185
- while (unbase64 (*src) < 0 && src < srcEnd)
186
- src++, remaining--;
187
- if (remaining <= 2 || *src == ' =' )
188
- break ;
189
- c = unbase64 (*src++);
158
+ size_t base64_decode_slow (char * dst, size_t dstlen,
159
+ const TypeName* src, size_t srclen) {
160
+ uint8_t hi;
161
+ uint8_t lo;
162
+ size_t i = 0 ;
163
+ size_t k = 0 ;
164
+ for (;;) {
165
+ #define V (expr ) \
166
+ while (i < srclen) { \
167
+ const uint8_t c = src[i]; \
168
+ lo = unbase64 (c); \
169
+ i += 1 ; \
170
+ if (lo < 64 ) \
171
+ break ; /* Legal character. */ \
172
+ if (c == ' =' ) \
173
+ return k; \
174
+ } \
175
+ expr; \
176
+ if (i >= srclen) \
177
+ return k; \
178
+ if (k >= dstlen) \
179
+ return k; \
180
+ hi = lo;
181
+ V (/* Nothing. */ );
182
+ V (dst[k++] = ((hi & 0x3F ) << 2 ) | ((lo & 0x30 ) >> 4 ));
183
+ V (dst[k++] = ((hi & 0x0F ) << 4 ) | ((lo & 0x3C ) >> 2 ));
184
+ V (dst[k++] = ((hi & 0x03 ) << 6 ) | ((lo & 0x3F ) >> 0 ));
185
+ #undef V
186
+ }
187
+ UNREACHABLE ();
188
+ }
190
189
191
- *dst++ = ((b & 0x0F ) << 4 ) | ((c & 0x3C ) >> 2 );
192
- if (dst == dstEnd)
193
- break ;
194
190
195
- while (unbase64 (*src) < 0 && src < srcEnd)
196
- src++, remaining--;
197
- if (remaining <= 3 || *src == ' =' )
191
+ template <typename TypeName>
192
+ size_t base64_decode_fast (char * const dst, const size_t dstlen,
193
+ const TypeName* const src, const size_t srclen,
194
+ const size_t decoded_size) {
195
+ const size_t available = dstlen < decoded_size ? dstlen : decoded_size;
196
+ const size_t max_i = srclen / 4 * 4 ;
197
+ const size_t max_k = available / 3 * 3 ;
198
+ size_t i = 0 ;
199
+ size_t k = 0 ;
200
+ while (i < max_i && k < max_k) {
201
+ const uint32_t v =
202
+ unbase64 (src[i + 0 ]) << 24 |
203
+ unbase64 (src[i + 1 ]) << 16 |
204
+ unbase64 (src[i + 2 ]) << 8 |
205
+ unbase64 (src[i + 3 ]);
206
+ // If MSB is set, input contains whitespace or is not valid base64.
207
+ if (v & 0x80808080 ) {
198
208
break ;
199
- d = unbase64 (*src++);
200
-
201
- *dst++ = ((c & 0x03 ) << 6 ) | (d & 0x3F );
209
+ }
210
+ dst[k + 0 ] = ((v >> 22 ) & 0xFC ) | ((v >> 20 ) & 0x03 );
211
+ dst[k + 1 ] = ((v >> 12 ) & 0xF0 ) | ((v >> 10 ) & 0x0F );
212
+ dst[k + 2 ] = ((v >> 2 ) & 0xC0 ) | ((v >> 0 ) & 0x3F );
213
+ i += 4 ;
214
+ k += 3 ;
202
215
}
203
-
204
- return dst - buf;
216
+ if (i < srclen && k < dstlen) {
217
+ return k + base64_decode_slow (dst + k, dstlen - k, src + i, srclen - i);
218
+ }
219
+ return k;
205
220
}
206
221
207
222
208
- // // HEX ////
223
+ template <typename TypeName>
224
+ size_t base64_decode (char * const dst, const size_t dstlen,
225
+ const TypeName* const src, const size_t srclen) {
226
+ const size_t decoded_size = base64_decoded_size (src, srclen);
227
+ return base64_decode_fast (dst, dstlen, src, srclen, decoded_size);
228
+ }
229
+
209
230
210
231
template <typename TypeName>
211
232
unsigned hex2bin (TypeName c) {
0 commit comments