On Tue, Oct 18, 2011 at 2:19 PM, Denys Vlasenko <[email protected]> wrote: > After you created decode_base64 which operates on string, > rewrite read_base64 to use it (say, by loop "read up to N*4 bytes, > decode them, repeat if no decode error, no EOF and no end char > encountered"). > > This may need some tweaks: decode_base64 should be taught > how to decode partial (incomplete) base64 string.
I prepare suggested variant, please take a look on patch attached, but it has worse code size (+28 bytes) than copy-n-paste :(( Will try to optimize it, but currently have no good ideas... Regards, Leonid
decode_base64() - decode base64 string Signed-off-by: Leonid Lisovskiy <[email protected]> --- include/libbb.h | 1 libbb/uuencode.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 88 insertions(+), 16 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index f0f54ef..9453be0 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1599,6 +1599,7 @@ enum { BASE64_FLAG_NO_STOP_CHAR = 0x80, }; void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags); +int FAST_FUNC decode_base64(const char *src, char **endptr, char *dst, int dstlen, int flags); typedef struct md5_ctx_t { uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */ diff --git a/libbb/uuencode.c b/libbb/uuencode.c index 03e708f..a1b0c0f 100644 --- a/libbb/uuencode.c +++ b/libbb/uuencode.c @@ -73,16 +73,15 @@ void FAST_FUNC bb_uuencode(char *p, const void *src, int length, const char *tbl } /* - * Decode base64 encoded stream. - * Can stop on EOF, specified char, or on uuencode-style "====" line: + * Decode base64 encoded string. + * Can stop on '\0' or on uuencode-style "====" line: * flags argument controls it. */ -void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) +int FAST_FUNC decode_base64(const char *src, char **endptr, char *buf, int buflen, int flags) { -/* Note that EOF _can_ be passed as exit_char too */ -#define exit_char ((int)(signed char)flags) #define uu_style_end (flags & BASE64_FLAG_UU_STOP) + int len = 0; int term_count = 0; while (1) { @@ -101,13 +100,18 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n" */ do { - ch = fgetc(src_stream); - if (ch == exit_char && count == 0) - return; - if (ch == EOF) - bb_error_msg_and_die("truncated base64 input"); + ch = *(src++); + if (ch == '\0') { + if (endptr != NULL) + *endptr = (char *)(src - count - 1); + if (count == 0) { + return len; + } else { + /* truncated base64 input */ + return -len; + } + } table_ptr = strchr(bb_uuenc_tbl_base64, ch); -//TODO: add BASE64_FLAG_foo to die on bad char? //Note that then we may need to still allow '\r' (for mail processing) } while (!table_ptr); @@ -117,7 +121,7 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) if (ch == 65 /* '\n' */) { /* Terminating "====" line? */ if (uu_style_end && term_count == 4) - return; /* yes */ + return len; /* yes */ term_count = 0; continue; } @@ -135,11 +139,78 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) * count can be < 4 when we decode the tail: * "eQ==" -> "y", not "y NUL NUL" */ - if (count > 1) - fputc(translated[0] << 2 | translated[1] >> 4, dst_stream); + if (buflen <= len + count) + /* output buffer too small */ + return -len; + if (count > 1) { + len += (count - 1); + *(buf++) = translated[0] << 2 | translated[1] >> 4; + } if (count > 2) - fputc(translated[1] << 4 | translated[2] >> 2, dst_stream); + *(buf++) = translated[1] << 4 | translated[2] >> 2; if (count > 3) - fputc(translated[2] << 6 | translated[3], dst_stream); + *(buf++) = translated[2] << 6 | translated[3]; } /* while (1) */ + + return len; +} + +/* + * Decode base64 encoded stream. + * Can stop on EOF, specified char, or on uuencode-style "====" line: + * flags argument controls it. + */ +void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) +{ +/* Note that EOF _can_ be passed as exit_char too */ +#define exit_char ((int)(signed char)flags) + + char in_buf[16+2], out_buf[12+2]; + char *in_rest; + int in_count = 0; + int term_seen = 0; + + while (1) { + int len; + + while (in_count < 16) { + int ch; + + ch = fgetc(src_stream); + if (ch == exit_char) { + if (in_count == 0) { + return; + } else { + term_seen = 1; + break; + } + } + if (ch == EOF) { + term_seen = 1; + break; + } + in_buf[in_count++] = ch; + } + in_buf[in_count] = '\0'; + + len = decode_base64(in_buf, &in_rest, out_buf, sizeof(out_buf), flags); + + if (len < 0) { + /* partial decode */ + if (term_seen || *in_rest == '\0') { + bb_error_msg_and_die("truncated base64 input"); +//TODO: add BASE64_FLAG_foo to die on bad char? + } + in_count = strlen(in_rest); + memmove(in_buf, in_rest, in_count); + len = -len; + } else if (len == 0) { + break; + } else { + in_count = 0; + } + + out_buf[len] = '\0'; + fputs(out_buf, dst_stream); + } } --
_______________________________________________ busybox mailing list [email protected] http://lists.busybox.net/mailman/listinfo/busybox
