@@ -132,7 +132,7 @@ size_t base64_decoded_size(const TypeName* src, size_t size) {
132132
133133
134134// supports regular and URL-safe base64
135- static const int unbase64_table[] =
135+ static const int8_t unbase64_table[] =
136136 { -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -2 , -1 , -1 , -2 , -1 , -1 ,
137137 -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
138138 -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[] =
150150 -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
151151 -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1
152152 };
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)])
154155
155156
156157template <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+ }
190189
191- *dst++ = ((b & 0x0F ) << 4 ) | ((c & 0x3C ) >> 2 );
192- if (dst == dstEnd)
193- break ;
194190
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 ) {
198208 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 ;
202215 }
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;
205220}
206221
207222
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+
209230
210231template <typename TypeName>
211232unsigned hex2bin (TypeName c) {
0 commit comments