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

Reply via email to