diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2020-11-28 12:33:50 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2020-11-28 12:33:50 +0100 |
commit | f140b49f5f631b09acf7811933d843fe17f06343 (patch) | |
tree | 97d5e77ed73a3864bd8ea4ca7b9ad0af8130e89a /libbb | |
parent | 7467e905e558228aab992f85406382518f2e1666 (diff) |
base32/64: code shrink
function old new delta
decode_base64 178 173 -5
decode_base32 217 186 -31
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-36) Total: -36 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/uuencode.c | 66 |
1 files changed, 37 insertions, 29 deletions
diff --git a/libbb/uuencode.c b/libbb/uuencode.c index 0e6fc8a3c..6205af261 100644 --- a/libbb/uuencode.c +++ b/libbb/uuencode.c @@ -92,8 +92,8 @@ const char* FAST_FUNC decode_base64(char **pp_dst, const char *src) { char *dst = *pp_dst; unsigned ch = 0; + unsigned t; int i = 0; - int t; while ((t = (unsigned char)*src) != '\0') { src++; @@ -117,11 +117,11 @@ const char* FAST_FUNC decode_base64(char **pp_dst, const char *src) continue; ch = (ch << 6) | t; - if (++i == 4) { + i = (i + 1) & 3; + if (i == 0) { *dst++ = (char) (ch >> 16); *dst++ = (char) (ch >> 8); *dst++ = (char) ch; - i = 0; if (ch & 0x1000000) { /* was last input char '='? */ dst--; if (ch & (0x1000000 << 6)) /* was it "=="? */ @@ -140,9 +140,9 @@ const char* FAST_FUNC decode_base64(char **pp_dst, const char *src) const char* FAST_FUNC decode_base32(char **pp_dst, const char *src) { char *dst = *pp_dst; - uint64_t ch = 0; + int64_t ch = 0; + unsigned t; int i = 0; - int t; while ((t = (unsigned char)*src) != '\0') { src++; @@ -150,44 +150,52 @@ const char* FAST_FUNC decode_base32(char **pp_dst, const char *src) /* "if" forest is faster than strchr(bb_uuenc_tbl_base32, t) */ if (t >= '2' && t <= '7') t = t - '2' + 26; - else if ((t|0x20) >= 'a' && (t|0x20) <= 'z') - t = (t|0x20) - 'a'; else if (t == '=' && i > 1) t = 0; - else + else { + t = (t | 0x20) - 'a'; + if (t > 25) //TODO: add BASE64_FLAG_foo to die on bad char? - continue; + continue; + } - 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--; - } + ch = (ch << 5) | t; + i = (i + 1) & 7; + if (i == 0) { *dst++ = (char) (ch >> 32); + if (src[-1] == '=') /* was last input char '='? */ + goto tail; *dst++ = (char) (ch >> 24); *dst++ = (char) (ch >> 16); *dst++ = (char) (ch >> 8); *dst++ = (char) ch; - 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 is zero here if full 8-char block was decoded */ return src - i; + tail: + { + const char *s = src; + while (*--s == '=') + i++; + /* Why duplicate the below code? 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== + * ==== + * must correctly stitch together the tail, must not overwrite + * the tail before it is analyzed! (we can be decoding in-place) + * Else testcase fails, prints trailing extra NUL bytes. + */ + *dst++ = (char) (ch >> 24); + *dst++ = (char) (ch >> 16); + *dst++ = (char) (ch >> 8); + *dst++ = (char) ch; + dst -= (i+1) * 2 / 3; /* discard last 1, 2, 3 or 4 bytes */ + } + *pp_dst = dst; + return src; } #endif |