[git commit] base32: new applet

Denys Vlasenko vda.linux at googlemail.com
Thu Nov 26 08:04:16 UTC 2020


commit: https://git.busybox.net/busybox/commit/?id=20900489a1fff2a563999d90e24239206f202b21
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
baseNUM_main                                           -     568    +568
decode_base32                                          -     275    +275
bb_uuenc_tbl_base32                                    -      34     +34
read_base64                                          218     236     +18
applet_names                                        2732    2739      +7
applet_main                                         1580    1584      +4
packed_usage                                       33480   33478      -2
base64_main                                          208       -    -208
------------------------------------------------------------------------------
(add/remove: 3/1 grow/shrink: 3/1 up/down: 906/-210)          Total: 696 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 coreutils/uudecode.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++-----
 include/libbb.h      |   3 ++
 libbb/uuencode.c     |  84 ++++++++++++++++++++++++++++++++++--
 3 files changed, 192 insertions(+), 13 deletions(-)

diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c
index 5b2edd649..e4fb0d48b 100644
--- a/coreutils/uudecode.c
+++ b/coreutils/uudecode.c
@@ -168,9 +168,11 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv)
 }
 #endif
 
-//applet:IF_BASE64(APPLET(base64, BB_DIR_BIN, BB_SUID_DROP))
-
-//kbuild:lib-$(CONFIG_BASE64) += uudecode.o
+//config:config BASE32
+//config:	bool "base32 (4.9 kb)"
+//config:	default y
+//config:	help
+//config:	Base32 encode and decode
 
 //config:config BASE64
 //config:	bool "base64 (4.9 kb)"
@@ -178,6 +180,14 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv)
 //config:	help
 //config:	Base64 encode and decode
 
+//usage:#define base32_trivial_usage
+//usage:	"[-d] [FILE]"
+//usage:#define base32_full_usage "\n\n"
+//usage:       "Base32 encode or decode FILE to standard output"
+//usage:     "\n	-d	Decode data"
+////usage:     "\n	-w COL	Wrap lines at COL (default 76, 0 disables)"
+////usage:     "\n	-i	When decoding, ignore non-alphabet characters"
+
 //usage:#define base64_trivial_usage
 //usage:	"[-d] [FILE]"
 //usage:#define base64_full_usage "\n\n"
@@ -186,9 +196,77 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv)
 ////usage:     "\n	-w COL	Wrap lines at COL (default 76, 0 disables)"
 ////usage:     "\n	-i	When decoding, ignore non-alphabet characters"
 
-#if ENABLE_BASE64
-int base64_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int base64_main(int argc UNUSED_PARAM, char **argv)
+//                 APPLET_ODDNAME:name    main     location    suid_type     help
+//applet:IF_BASE32(APPLET_ODDNAME(base32, baseNUM, BB_DIR_BIN, BB_SUID_DROP, base32))
+//applet:IF_BASE64(APPLET_ODDNAME(base64, baseNUM, BB_DIR_BIN, BB_SUID_DROP, base64))
+
+//kbuild:lib-$(CONFIG_BASE64) += uudecode.o
+//kbuild:lib-$(CONFIG_BASE32) += uudecode.o
+
+#if ENABLE_BASE32 || ENABLE_BASE64
+
+# if ENABLE_BASE32
+static void bb_b32encode(char *p, const void *src, int length)
+{
+#define tbl bb_uuenc_tbl_base32
+	const unsigned char *s = src;
+
+	/* Transform 5x8 bits to 8x5 bits */
+	while (length > 0) {
+		unsigned cur, next;
+
+		length--;
+		cur = *s++;
+		*p++ = tbl[cur >> 3];			// xxxxx--- -------- -------- -------- --------
+		cur &= 7;
+
+		next = 0;
+		if (--length >= 0)
+			next = *s++;
+		*p++ = tbl[(cur << 2) + (next >> 6)];	// -----xxx xx------ -------- -------- --------
+		cur = next & 0x3f;
+
+		*p++ = tbl[cur >> 1];			// -------- --xxxxx- -------- -------- --------
+		cur &= 1;
+
+		next = 0;
+		if (--length >= 0)
+			next = *s++;
+		*p++ = tbl[(cur << 4) + (next >> 4)];	// -------- -------x xxxx---- -------- --------
+		cur = next & 0xf;
+
+		next = 0;
+		if (--length >= 0)
+			next = *s++;
+		*p++ = tbl[(cur << 1) + (next >> 7)];	// -------- -------- ----xxxx x------- --------
+		cur = next & 0x7f;
+
+		*p++ = tbl[cur >> 2];			// -------- -------- -------- -xxxxx-- --------
+		cur &= 3;
+
+		next = 0;
+		if (--length >= 0)
+			next = *s++;
+		*p++ = tbl[(cur << 3) + (next >> 5)];	// -------- -------- -------- ------xx xxx-----
+		cur = next & 0x1f;
+
+		*p++ = tbl[cur];			// -------- -------- -------- -------- ---xxxxx
+	}
+#undef tbl
+	/* Zero-terminate */
+	*p = '\0';
+	/* Pad as necessary */
+	length = ((-length) * 3) >> 1; /* -4 => 6 pad chars, -3 => 4, -2 => 3, -1 => 1 */
+	while (length--) {
+		*--p = '=';
+	}
+}
+# else
+void bb_b32encode(char *p, const void *src, int length); /* undefined */
+# endif
+
+int baseNUM_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int baseNUM_main(int argc UNUSED_PARAM, char **argv)
 {
 	FILE *src_stream;
 	unsigned opts;
@@ -200,7 +278,10 @@ int base64_main(int argc UNUSED_PARAM, char **argv)
 		*--argv = (char*)"-";
 	src_stream = xfopen_stdin(argv[0]);
 	if (opts) {
-		read_base64(src_stream, stdout, /*flags:*/ (unsigned char)EOF);
+		int flags = (unsigned char)EOF;
+		if (ENABLE_BASE32 && (!ENABLE_BASE64 || applet_name[4] == '3'))
+			flags = ((unsigned char)EOF) | BASE64_32;
+		read_base64(src_stream, stdout, flags);
 	} else {
 		enum {
 			SRC_BUF_SIZE = 76 / 4 * 3, /* this *MUST* be a multiple of 3 */
@@ -210,14 +291,31 @@ int base64_main(int argc UNUSED_PARAM, char **argv)
 		char dst_buf[DST_BUF_SIZE + 1];
 		int src_fd = fileno(src_stream);
 		while (1) {
-			size_t size = full_read(src_fd, src_buf, SRC_BUF_SIZE);
+			size_t size;
+			if (ENABLE_BASE32 && (!ENABLE_BASE64 || applet_name[4] == '3'))
+				size = 72 / 8 * 5;
+//FIXME: wrong, default width of base32 is not 72, but 76 chars
+//(not a multiple of 8 - requires adding wrapping logic)
+//when this is fixed, can implement -w COL too
+			else
+				size = SRC_BUF_SIZE;
+
+			size = full_read(src_fd, src_buf, size);
 			if (!size)
 				break;
 			if ((ssize_t)size < 0)
 				bb_simple_perror_msg_and_die(bb_msg_read_error);
+
 			/* Encode the buffer we just read in */
-			bb_uuencode(dst_buf, src_buf, size, bb_uuenc_tbl_base64);
-			xwrite(STDOUT_FILENO, dst_buf, 4 * ((size + 2) / 3));
+			if (ENABLE_BASE32 && (!ENABLE_BASE64 || applet_name[4] == '3')) {
+				bb_b32encode(dst_buf, src_buf, size);
+				size = 8 * ((size + 4) / 5);
+			} else {
+				bb_uuencode(dst_buf, src_buf, size, bb_uuenc_tbl_base64);
+				size = 4 * ((size + 2) / 3);
+			}
+
+			xwrite(STDOUT_FILENO, dst_buf, size);
 			bb_putchar('\n');
 			fflush(stdout);
 		}
diff --git a/include/libbb.h b/include/libbb.h
index 1b7c0b83a..ef4a34f07 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -2026,14 +2026,17 @@ char *percent_decode_in_place(char *str, int strict) FAST_FUNC;
 
 
 extern const char bb_uuenc_tbl_base64[] ALIGN1;
+extern const char bb_uuenc_tbl_base32[] ALIGN1;
 extern const char bb_uuenc_tbl_std[] ALIGN1;
 void bb_uuencode(char *store, const void *s, int length, const char *tbl) FAST_FUNC;
 enum {
 	BASE64_FLAG_UU_STOP = 0x100,
+	BASE64_32           = 0x200, /* base32 */
 	/* Sign-extends to a value which never matches fgetc result: */
 	BASE64_FLAG_NO_STOP_CHAR = 0x80,
 };
 const char *decode_base64(char **pp_dst, const char *src) FAST_FUNC;
+const char *decode_base32(char **pp_dst, const char *src) FAST_FUNC;
 void read_base64(FILE *src_stream, FILE *dst_stream, int flags) FAST_FUNC;
 
 typedef struct md5_ctx_t {
diff --git a/libbb/uuencode.c b/libbb/uuencode.c
index d36b34f63..b4ee20c20 100644
--- a/libbb/uuencode.c
+++ b/libbb/uuencode.c
@@ -8,7 +8,8 @@
  */
 #include "libbb.h"
 
-/* Conversion table.  for base 64 */
+/* Conversion tables */
+/* for base 64 */
 const char bb_uuenc_tbl_base64[65 + 1] ALIGN1 = {
 	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
 	'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
@@ -21,7 +22,16 @@ const char bb_uuenc_tbl_base64[65 + 1] ALIGN1 = {
 	'=' /* termination character */,
 	'\0' /* needed for uudecode.c only */
 };
-
+#if ENABLE_BASE32
+const char bb_uuenc_tbl_base32[33 + 1] ALIGN1 = {
+	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+	'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+	'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+	'Y', 'Z', '2', '3', '4', '5', '6', '7',
+	'=',
+	'\0'
+};
+#endif
 const char bb_uuenc_tbl_std[65] ALIGN1 = {
 	'`', '!', '"', '#', '$', '%', '&', '\'',
 	'(', ')', '*', '+', ',', '-', '.', '/',
@@ -153,6 +163,68 @@ const char* FAST_FUNC decode_base64(char **pp_dst, const char *src)
 	return src_tail;
 }
 
+#if ENABLE_BASE32
+const char* FAST_FUNC decode_base32(char **pp_dst, const char *src)
+{
+	char *dst = *pp_dst;
+	const char *src_tail;
+
+	while (1) {
+		unsigned char five_bit[8];
+		int count = 0;
+
+		/* Fetch up to eight 5-bit values */
+		src_tail = src;
+		while (count < 8) {
+			char *table_ptr;
+			int ch;
+
+			/* Get next _valid_ character.
+			 * bb_uuenc_tbl_base32[] contains this string:
+			 *  0         1         2         3
+			 *  01234567890123456789012345678901
+			 * "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567="
+			 */
+			do {
+				ch = *src;
+				if (ch == '\0') {
+					if (count == 0) {
+						src_tail = src;
+					}
+					goto ret;
+				}
+				src++;
+				table_ptr = strchr(bb_uuenc_tbl_base32, toupper(ch));
+			} while (!table_ptr);
+
+			/* Convert encoded character to decimal */
+			ch = table_ptr - bb_uuenc_tbl_base32;
+
+			/* ch is 32 if char was '=', otherwise 0..31 */
+			if (ch == 32)
+				break;
+			five_bit[count] = ch;
+			count++;
+		}
+
+		/* Transform 5-bit values to 8-bit ones */
+		if (count > 1)                                        // xxxxx xxx-- ----- ----- ----- ----- ----- -----
+			*dst++ = five_bit[0] << 3 | five_bit[1] >> 2;
+		if (count > 3)                                        // ----- ---xx xxxxx x---- ----- ----- ----- -----
+			*dst++ = five_bit[1] << 6 | five_bit[2] << 1 | five_bit[3] >> 4;
+		if (count > 4)                                        // ----- ----- ----- -xxxx xxxx- ----- ----- -----
+			*dst++ = five_bit[3] << 4 | five_bit[4] >> 1;
+		if (count > 6)                                        // ----- ----- ----- ----- ----x xxxxx xx--- -----
+			*dst++ = five_bit[4] << 7 | five_bit[5] << 2 | five_bit[6] >> 3;
+		if (count > 7)                                        // ----- ----- ----- ----- ----- ----- --xxx xxxxx
+			*dst++ = five_bit[6] << 5 | five_bit[7];
+	} /* while (1) */
+ ret:
+	*pp_dst = dst;
+	return src_tail;
+}
+#endif
+
 /*
  * Decode base64 encoded stream.
  * Can stop on EOF, specified char, or on uuencode-style "====" line:
@@ -163,6 +235,7 @@ 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)
 #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.
@@ -204,7 +277,12 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags)
 			return;
 
 		out_tail = out_buf;
-		in_tail = decode_base64(&out_tail, in_buf);
+#if ENABLE_BASE32
+		if (base32)
+			in_tail = decode_base32(&out_tail, in_buf);
+		else
+#endif
+			in_tail = decode_base64(&out_tail, in_buf);
 
 		fwrite(out_buf, (out_tail - out_buf), 1, dst_stream);
 


More information about the busybox-cvs mailing list