summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbb/uuencode.c75
1 files changed, 43 insertions, 32 deletions
diff --git a/libbb/uuencode.c b/libbb/uuencode.c
index 7c7f1cf..0e6fc8a 100644
--- a/libbb/uuencode.c
+++ b/libbb/uuencode.c
@@ -93,9 +93,10 @@ const char* FAST_FUNC decode_base64(char **pp_dst, const char *src)
char *dst = *pp_dst;
unsigned ch = 0;
int i = 0;
+ int t;
- while (*src) {
- int t = (unsigned char)*src++;
+ while ((t = (unsigned char)*src) != '\0') {
+ src++;
/* "if" forest is faster than strchr(bb_uuenc_tbl_base64, t) */
if (t >= '0' && t <= '9')
@@ -131,7 +132,7 @@ const char* FAST_FUNC decode_base64(char **pp_dst, const char *src)
}
}
*pp_dst = dst;
- /* i should be zero here if full 4-char block was decoded */
+ /* i is zero here if full 4-char block was decoded */
return src - i; /* -i rejects truncations: e.g. "MQ" and "MQ=" (correct encoding is "MQ==" -> "1") */
}
@@ -141,9 +142,10 @@ const char* FAST_FUNC decode_base32(char **pp_dst, const char *src)
char *dst = *pp_dst;
uint64_t ch = 0;
int i = 0;
+ int t;
- while (*src) {
- int t = (unsigned char)*src++;
+ while ((t = (unsigned char)*src) != '\0') {
+ src++;
/* "if" forest is faster than strchr(bb_uuenc_tbl_base32, t) */
if (t >= '2' && t <= '7')
@@ -156,27 +158,35 @@ const char* FAST_FUNC decode_base32(char **pp_dst, const char *src)
//TODO: add BASE64_FLAG_foo to die on bad char?
continue;
- ch = (ch << 5) | t;
+ ch = (ch << 5) | (unsigned)t; /* cast prevents pointless sign-extension of t */
if (++i == 8) {
+ /* testcase:
+ * echo ' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18' | base32 | base32 -d
+ * IOW, decoding of
+ * EAYSAMRAGMQDIIBVEA3CANZAHAQDSIBRGAQDCMJAGEZCAMJTEAYTIIBRGUQDCNRAGE3SAMJYBI==
+ * ====
+ * should correctly stitch together the tail.
+ */
+ if (t == 0) {
+ const char *s = src;
+ while (*--s == '=')
+ t--;
+ }
*dst++ = (char) (ch >> 32);
*dst++ = (char) (ch >> 24);
*dst++ = (char) (ch >> 16);
*dst++ = (char) (ch >> 8);
*dst++ = (char) ch;
- if (t == 0 && src[-1] == '=') { /* was last input char '='? */
- const char *s = src;
- while (*--s == '=' && --i != 0)
- continue;
- i = 8 - i; /* count of =, must be 1, 3, 4 or 6 */
- dst -= (i+1) * 2 / 3; /* discard last 1, 2, 3 or 4 bytes */
- i = 0;
- break;
- }
i = 0;
+ if (t < 0) /* was last input char '='? */
+ break;
}
}
+ if (t < 0) /* was last input char '='? */
+ /* -t is the count of =, must be 1, 3, 4 or 6 */
+ dst -= (-t + 1) * 2 / 3; /* discard last 1, 2, 3 or 4 bytes */
*pp_dst = dst;
- /* i should be zero here if full 8-char block was decoded */
+ /* i is zero here if full 8-char block was decoded */
return src - i;
}
#endif
@@ -193,19 +203,20 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags)
#define uu_style_end (flags & BASE64_FLAG_UU_STOP)
#define base32 (flags & BASE64_32)
- /* uuencoded files have 61 byte lines. Use 64 byte buffer
- * to process line at a time.
+ /* uuencoded files have 61 byte lines.
+ * base32/64 have 76 byte lines by default.
+ * Use 80 byte buffer to process one line at a time.
*/
- enum { BUFFER_SIZE = 64 };
-
- char in_buf[BUFFER_SIZE + 2];
- char out_buf[BUFFER_SIZE / 4 * 3 + 2];
- char *out_tail;
- const char *in_tail;
+ enum { BUFFER_SIZE = 80 };
+ /* decoded data is shorter than input, can use single buffer for both */
+ char buf[BUFFER_SIZE + 2];
int term_seen = 0;
int in_count = 0;
while (1) {
+ char *out_tail;
+ const char *in_tail;
+
while (in_count < BUFFER_SIZE) {
int ch = fgetc(src_stream);
if (ch == exit_char) {
@@ -224,23 +235,23 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags)
*/
if (ch <= ' ')
break;
- in_buf[in_count++] = ch;
+ buf[in_count++] = ch;
}
- in_buf[in_count] = '\0';
+ buf[in_count] = '\0';
/* Did we encounter "====" line? */
- if (uu_style_end && strcmp(in_buf, "====") == 0)
+ if (uu_style_end && strcmp(buf, "====") == 0)
return;
- out_tail = out_buf;
+ out_tail = buf;
#if ENABLE_BASE32
if (base32)
- in_tail = decode_base32(&out_tail, in_buf);
+ in_tail = decode_base32(&out_tail, buf);
else
#endif
- in_tail = decode_base64(&out_tail, in_buf);
+ in_tail = decode_base64(&out_tail, buf);
- fwrite(out_buf, (out_tail - out_buf), 1, dst_stream);
+ fwrite(buf, (out_tail - buf), 1, dst_stream);
if (term_seen) {
/* Did we consume ALL characters? */
@@ -252,6 +263,6 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags)
/* It was partial decode */
in_count = strlen(in_tail);
- memmove(in_buf, in_tail, in_count);
+ memmove(buf, in_tail, in_count);
}
}