diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2020-11-28 09:50:14 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2020-11-28 09:50:14 +0100 |
commit | 7467e905e558228aab992f85406382518f2e1666 (patch) | |
tree | ab4b716757c36b66b80e3c2dac8ccecceea5fe8d | |
parent | 2cd37d65e221f7267e97360d21f55a2318b25355 (diff) | |
download | busybox-w32-7467e905e558228aab992f85406382518f2e1666.tar.gz busybox-w32-7467e905e558228aab992f85406382518f2e1666.tar.bz2 busybox-w32-7467e905e558228aab992f85406382518f2e1666.zip |
base32/64: code shrink
function old new delta
decode_base64 180 178 -2
decode_base32 224 217 -7
read_base64 236 222 -14
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-23) Total: -23 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | libbb/uuencode.c | 75 |
1 files changed, 43 insertions, 32 deletions
diff --git a/libbb/uuencode.c b/libbb/uuencode.c index 7c7f1cf1c..0e6fc8a3c 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) | |||
93 | char *dst = *pp_dst; | 93 | char *dst = *pp_dst; |
94 | unsigned ch = 0; | 94 | unsigned ch = 0; |
95 | int i = 0; | 95 | int i = 0; |
96 | int t; | ||
96 | 97 | ||
97 | while (*src) { | 98 | while ((t = (unsigned char)*src) != '\0') { |
98 | int t = (unsigned char)*src++; | 99 | src++; |
99 | 100 | ||
100 | /* "if" forest is faster than strchr(bb_uuenc_tbl_base64, t) */ | 101 | /* "if" forest is faster than strchr(bb_uuenc_tbl_base64, t) */ |
101 | if (t >= '0' && t <= '9') | 102 | if (t >= '0' && t <= '9') |
@@ -131,7 +132,7 @@ const char* FAST_FUNC decode_base64(char **pp_dst, const char *src) | |||
131 | } | 132 | } |
132 | } | 133 | } |
133 | *pp_dst = dst; | 134 | *pp_dst = dst; |
134 | /* i should be zero here if full 4-char block was decoded */ | 135 | /* i is zero here if full 4-char block was decoded */ |
135 | return src - i; /* -i rejects truncations: e.g. "MQ" and "MQ=" (correct encoding is "MQ==" -> "1") */ | 136 | return src - i; /* -i rejects truncations: e.g. "MQ" and "MQ=" (correct encoding is "MQ==" -> "1") */ |
136 | } | 137 | } |
137 | 138 | ||
@@ -141,9 +142,10 @@ const char* FAST_FUNC decode_base32(char **pp_dst, const char *src) | |||
141 | char *dst = *pp_dst; | 142 | char *dst = *pp_dst; |
142 | uint64_t ch = 0; | 143 | uint64_t ch = 0; |
143 | int i = 0; | 144 | int i = 0; |
145 | int t; | ||
144 | 146 | ||
145 | while (*src) { | 147 | while ((t = (unsigned char)*src) != '\0') { |
146 | int t = (unsigned char)*src++; | 148 | src++; |
147 | 149 | ||
148 | /* "if" forest is faster than strchr(bb_uuenc_tbl_base32, t) */ | 150 | /* "if" forest is faster than strchr(bb_uuenc_tbl_base32, t) */ |
149 | if (t >= '2' && t <= '7') | 151 | if (t >= '2' && t <= '7') |
@@ -156,27 +158,35 @@ const char* FAST_FUNC decode_base32(char **pp_dst, const char *src) | |||
156 | //TODO: add BASE64_FLAG_foo to die on bad char? | 158 | //TODO: add BASE64_FLAG_foo to die on bad char? |
157 | continue; | 159 | continue; |
158 | 160 | ||
159 | ch = (ch << 5) | t; | 161 | ch = (ch << 5) | (unsigned)t; /* cast prevents pointless sign-extension of t */ |
160 | if (++i == 8) { | 162 | if (++i == 8) { |
163 | /* testcase: | ||
164 | * echo ' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18' | base32 | base32 -d | ||
165 | * IOW, decoding of | ||
166 | * EAYSAMRAGMQDIIBVEA3CANZAHAQDSIBRGAQDCMJAGEZCAMJTEAYTIIBRGUQDCNRAGE3SAMJYBI== | ||
167 | * ==== | ||
168 | * should correctly stitch together the tail. | ||
169 | */ | ||
170 | if (t == 0) { | ||
171 | const char *s = src; | ||
172 | while (*--s == '=') | ||
173 | t--; | ||
174 | } | ||
161 | *dst++ = (char) (ch >> 32); | 175 | *dst++ = (char) (ch >> 32); |
162 | *dst++ = (char) (ch >> 24); | 176 | *dst++ = (char) (ch >> 24); |
163 | *dst++ = (char) (ch >> 16); | 177 | *dst++ = (char) (ch >> 16); |
164 | *dst++ = (char) (ch >> 8); | 178 | *dst++ = (char) (ch >> 8); |
165 | *dst++ = (char) ch; | 179 | *dst++ = (char) ch; |
166 | if (t == 0 && src[-1] == '=') { /* was last input char '='? */ | ||
167 | const char *s = src; | ||
168 | while (*--s == '=' && --i != 0) | ||
169 | continue; | ||
170 | i = 8 - i; /* count of =, must be 1, 3, 4 or 6 */ | ||
171 | dst -= (i+1) * 2 / 3; /* discard last 1, 2, 3 or 4 bytes */ | ||
172 | i = 0; | ||
173 | break; | ||
174 | } | ||
175 | i = 0; | 180 | i = 0; |
181 | if (t < 0) /* was last input char '='? */ | ||
182 | break; | ||
176 | } | 183 | } |
177 | } | 184 | } |
185 | if (t < 0) /* was last input char '='? */ | ||
186 | /* -t is the count of =, must be 1, 3, 4 or 6 */ | ||
187 | dst -= (-t + 1) * 2 / 3; /* discard last 1, 2, 3 or 4 bytes */ | ||
178 | *pp_dst = dst; | 188 | *pp_dst = dst; |
179 | /* i should be zero here if full 8-char block was decoded */ | 189 | /* i is zero here if full 8-char block was decoded */ |
180 | return src - i; | 190 | return src - i; |
181 | } | 191 | } |
182 | #endif | 192 | #endif |
@@ -193,19 +203,20 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) | |||
193 | #define uu_style_end (flags & BASE64_FLAG_UU_STOP) | 203 | #define uu_style_end (flags & BASE64_FLAG_UU_STOP) |
194 | #define base32 (flags & BASE64_32) | 204 | #define base32 (flags & BASE64_32) |
195 | 205 | ||
196 | /* uuencoded files have 61 byte lines. Use 64 byte buffer | 206 | /* uuencoded files have 61 byte lines. |
197 | * to process line at a time. | 207 | * base32/64 have 76 byte lines by default. |
208 | * Use 80 byte buffer to process one line at a time. | ||
198 | */ | 209 | */ |
199 | enum { BUFFER_SIZE = 64 }; | 210 | enum { BUFFER_SIZE = 80 }; |
200 | 211 | /* decoded data is shorter than input, can use single buffer for both */ | |
201 | char in_buf[BUFFER_SIZE + 2]; | 212 | char buf[BUFFER_SIZE + 2]; |
202 | char out_buf[BUFFER_SIZE / 4 * 3 + 2]; | ||
203 | char *out_tail; | ||
204 | const char *in_tail; | ||
205 | int term_seen = 0; | 213 | int term_seen = 0; |
206 | int in_count = 0; | 214 | int in_count = 0; |
207 | 215 | ||
208 | while (1) { | 216 | while (1) { |
217 | char *out_tail; | ||
218 | const char *in_tail; | ||
219 | |||
209 | while (in_count < BUFFER_SIZE) { | 220 | while (in_count < BUFFER_SIZE) { |
210 | int ch = fgetc(src_stream); | 221 | int ch = fgetc(src_stream); |
211 | if (ch == exit_char) { | 222 | if (ch == exit_char) { |
@@ -224,23 +235,23 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) | |||
224 | */ | 235 | */ |
225 | if (ch <= ' ') | 236 | if (ch <= ' ') |
226 | break; | 237 | break; |
227 | in_buf[in_count++] = ch; | 238 | buf[in_count++] = ch; |
228 | } | 239 | } |
229 | in_buf[in_count] = '\0'; | 240 | buf[in_count] = '\0'; |
230 | 241 | ||
231 | /* Did we encounter "====" line? */ | 242 | /* Did we encounter "====" line? */ |
232 | if (uu_style_end && strcmp(in_buf, "====") == 0) | 243 | if (uu_style_end && strcmp(buf, "====") == 0) |
233 | return; | 244 | return; |
234 | 245 | ||
235 | out_tail = out_buf; | 246 | out_tail = buf; |
236 | #if ENABLE_BASE32 | 247 | #if ENABLE_BASE32 |
237 | if (base32) | 248 | if (base32) |
238 | in_tail = decode_base32(&out_tail, in_buf); | 249 | in_tail = decode_base32(&out_tail, buf); |
239 | else | 250 | else |
240 | #endif | 251 | #endif |
241 | in_tail = decode_base64(&out_tail, in_buf); | 252 | in_tail = decode_base64(&out_tail, buf); |
242 | 253 | ||
243 | fwrite(out_buf, (out_tail - out_buf), 1, dst_stream); | 254 | fwrite(buf, (out_tail - buf), 1, dst_stream); |
244 | 255 | ||
245 | if (term_seen) { | 256 | if (term_seen) { |
246 | /* Did we consume ALL characters? */ | 257 | /* Did we consume ALL characters? */ |
@@ -252,6 +263,6 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) | |||
252 | 263 | ||
253 | /* It was partial decode */ | 264 | /* It was partial decode */ |
254 | in_count = strlen(in_tail); | 265 | in_count = strlen(in_tail); |
255 | memmove(in_buf, in_tail, in_count); | 266 | memmove(buf, in_tail, in_count); |
256 | } | 267 | } |
257 | } | 268 | } |