Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions include/libbase64.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ extern "C" {
#define BASE64_FORCE_AVX (1 << 7)
#define BASE64_FORCE_AVX512 (1 << 8)

#define BASE64_CPU_MASK (0x1FF)

#define BASE64_NO_PADDING (1 << 13) /* encoding: do not output padding bytes, decoding: enforce no padding bytes */
#define BASE64_CANONICAL (1 << 14) /* decoding: enforce there are no padding bits (i.e. carry == 0) */

struct base64_state {
int eof;
int bytes;
Expand Down Expand Up @@ -139,6 +144,11 @@ int BASE64_EXPORT base64_stream_decode
, size_t *outlen
) ;

/* Finalizes checks begun by previous successful calls to `base64_stream_decode()`. */
int BASE64_EXPORT base64_stream_decode_final
( struct base64_state *state
) ;

#ifdef __cplusplus
}
#endif
Expand Down
6 changes: 4 additions & 2 deletions lib/arch/generic/dec_tail.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@
break;
}
if ((q = base64_table_dec_8bit[*s++]) >= 254) {
int const pad_check = (state->flags & BASE64_NO_PADDING) ? 0 : 254;
st.bytes++;
// When q == 254, the input char is '='.
// Check if next byte is also '=':
if (q == 254) {
if (q == pad_check) {
if (slen-- != 0) {
st.bytes = 0;
// EOF:
Expand Down Expand Up @@ -70,11 +71,12 @@
break;
}
if ((q = base64_table_dec_8bit[*s++]) >= 254) {
int const pad_check = (state->flags & BASE64_NO_PADDING) ? 0 : 254;
st.bytes = 0;
st.eof = BASE64_EOF;
// When q == 254, the input char is '='. Return 1 and EOF.
// When q == 255, the input char is invalid. Return 0 and EOF.
ret = ((q == 254) && (slen == 0)) ? 1 : 0;
ret = ((q == pad_check) && (slen == 0)) ? 1 : 0;
break;
}
*o++ = st.carry | q;
Expand Down
2 changes: 1 addition & 1 deletion lib/codec_choose.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ codec_choose_forced (struct codec *codec, int flags)
// always allow it, even if the codec is a no-op.
// For testing purposes.

if (!(flags & 0xFFFF)) {
if (!(flags & BASE64_CPU_MASK)) {
return false;
}

Expand Down
4 changes: 4 additions & 0 deletions lib/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@
// End-of-file when stream end has been reached or invalid input provided:
#define BASE64_EOF 2

// Due to the overhead of initializing OpenMP and creating a team of
// threads, we require the data length to be larger than a threshold:
#define BASE64_OMP_THRESHOLD 20000

// GCC 7 defaults to issuing a warning for fallthrough in switch statements,
// unless the fallthrough cases are marked with an attribute. As we use
// fallthrough deliberately, define an alias for the attribute:
Expand Down
1 change: 1 addition & 0 deletions lib/exports.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ base64_stream_encode_final
base64_decode
base64_stream_decode
base64_stream_decode_init
base64_stream_decode_final
54 changes: 40 additions & 14 deletions lib/lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ void
base64_stream_encode_init (struct base64_state *state, int flags)
{
// If any of the codec flags are set, redo choice:
if (codec.enc == NULL || flags & 0xFF) {
codec_choose(&codec, flags);
if (codec.enc == NULL || flags & BASE64_CPU_MASK) {
codec_choose(&codec, flags & BASE64_CPU_MASK);
}
state->eof = 0;
state->bytes = 0;
Expand Down Expand Up @@ -50,13 +50,21 @@ base64_stream_encode_final

if (state->bytes == 1) {
*o++ = base64_table_enc_6bit[state->carry];
if (state->flags & BASE64_NO_PADDING) {
*outlen = 1;
return;
}
*o++ = '=';
*o++ = '=';
*outlen = 3;
return;
}
if (state->bytes == 2) {
*o++ = base64_table_enc_6bit[state->carry];
if (state->flags & BASE64_NO_PADDING) {
*outlen = 1;
return;
}
*o++ = '=';
*outlen = 2;
return;
Expand All @@ -68,8 +76,8 @@ void
base64_stream_decode_init (struct base64_state *state, int flags)
{
// If any of the codec flags are set, redo choice:
if (codec.dec == NULL || flags & 0xFFFF) {
codec_choose(&codec, flags);
if (codec.dec == NULL || flags & BASE64_CPU_MASK) {
codec_choose(&codec, flags & BASE64_CPU_MASK);
}
state->eof = 0;
state->bytes = 0;
Expand All @@ -89,12 +97,30 @@ base64_stream_decode
return codec.dec(state, src, srclen, out, outlen);
}

#ifdef _OPENMP

// Due to the overhead of initializing OpenMP and creating a team of
// threads, we require the data length to be larger than a threshold:
#define OMP_THRESHOLD 20000
int
base64_stream_decode_final
( struct base64_state *state
)
{
if ((state->flags & BASE64_CANONICAL) && state->carry) {
return 0;
}
if (state->bytes == 0) {
return 1;
}
if (state->flags & BASE64_NO_PADDING) {
switch (state->bytes) {
case 2:
case 3:
return 1;
default:
break;
}
}
return 0;
}

#ifdef _OPENMP
// Conditionally include OpenMP-accelerated codec implementations:
#include "lib_openmp.c"
#endif
Expand All @@ -113,7 +139,7 @@ base64_encode
struct base64_state state;

#ifdef _OPENMP
if (srclen >= OMP_THRESHOLD) {
if (srclen >= BASE64_OMP_THRESHOLD) {
base64_encode_openmp(src, srclen, out, outlen, flags);
return;
}
Expand Down Expand Up @@ -145,7 +171,7 @@ base64_decode
struct base64_state state;

#ifdef _OPENMP
if (srclen >= OMP_THRESHOLD) {
if (srclen >= BASE64_OMP_THRESHOLD) {
return base64_decode_openmp(src, srclen, out, outlen, flags);
}
#endif
Expand All @@ -157,8 +183,8 @@ base64_decode
ret = base64_stream_decode(&state, src, srclen, out, outlen);

// If when decoding a whole block, we're still waiting for input then fail:
if (ret && (state.bytes == 0)) {
return ret;
if (ret > 0) {
ret = base64_stream_decode_final(&state);
}
return 0;
return ret;
}
14 changes: 8 additions & 6 deletions lib/lib_openmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,17 @@ base64_decode_openmp

// Split the input string into num_threads parts, each
// part a multiple of 4 bytes. The remaining bytes will
// be done later:
len = srclen / (num_threads * 4);
// be done later, always including the last 4 bytes to
// process padding correctly:
len = (srclen - 4) / (num_threads * 4);
len *= 4;
last_len = srclen - num_threads * len;

// Init the stream reader:
base64_stream_decode_init(&state, flags);

initial_state = state;
state.flags |= BASE64_NO_PADDING;
}

// Single has an implicit barrier to wait here for the above to
Expand Down Expand Up @@ -141,9 +143,9 @@ base64_decode_openmp
sum += s;
*outlen = sum;

// If when decoding a whole block, we're still waiting for input then fail:
if (result && (state.bytes == 0)) {
return result;
// Final check:
if (result) {
result = base64_stream_decode_final(&state);
}
return 0;
return result;
}
Loading