diff options
author | Leonid Lisovskiy <lly.dev@gmail.com> | 2011-10-28 13:59:04 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-10-28 13:59:55 +0200 |
commit | 328f27fe447761f355104e7f524dc1115f16ca44 (patch) | |
tree | 1a8280c4cbc4458b89dda72c4d0c8f7402661355 /libbb | |
parent | ec447c7f01acb0e3abd9daa52a1b616be3f39484 (diff) | |
download | busybox-w32-328f27fe447761f355104e7f524dc1115f16ca44.tar.gz busybox-w32-328f27fe447761f355104e7f524dc1115f16ca44.tar.bz2 busybox-w32-328f27fe447761f355104e7f524dc1115f16ca44.zip |
libbb: split decode_base64 off read_base64
function old new delta
decode_base64 - 182 +182
read_base64 378 255 -123
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 0/1 up/down: 182/-123) Total: 59 bytes
Signed-off-by: Leonid Lisovskiy <lly.dev@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/uuencode.c | 125 |
1 files changed, 100 insertions, 25 deletions
diff --git a/libbb/uuencode.c b/libbb/uuencode.c index 03e708fd5..23e2123bc 100644 --- a/libbb/uuencode.c +++ b/libbb/uuencode.c | |||
@@ -73,23 +73,23 @@ void FAST_FUNC bb_uuencode(char *p, const void *src, int length, const char *tbl | |||
73 | } | 73 | } |
74 | 74 | ||
75 | /* | 75 | /* |
76 | * Decode base64 encoded stream. | 76 | * Decode base64 encoded string. Stops on '\0'. |
77 | * Can stop on EOF, specified char, or on uuencode-style "====" line: | 77 | * |
78 | * flags argument controls it. | 78 | * Returns: pointer to the undecoded part of source. |
79 | * If points to '\0', then the source was fully decoded. | ||
80 | * (*dst): advanced past the last written byte. | ||
79 | */ | 81 | */ |
80 | void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) | 82 | const char* FAST_FUNC decode_base64(char **pp_dst, const char *src) |
81 | { | 83 | { |
82 | /* Note that EOF _can_ be passed as exit_char too */ | 84 | char *dst = *pp_dst; |
83 | #define exit_char ((int)(signed char)flags) | 85 | const char *src_tail; |
84 | #define uu_style_end (flags & BASE64_FLAG_UU_STOP) | ||
85 | |||
86 | int term_count = 0; | ||
87 | 86 | ||
88 | while (1) { | 87 | while (1) { |
89 | unsigned char translated[4]; | 88 | unsigned char translated[4]; |
90 | int count = 0; | 89 | int count = 0; |
91 | 90 | ||
92 | /* Process one group of 4 chars */ | 91 | /* Process one group of 4 chars */ |
92 | src_tail = src; | ||
93 | while (count < 4) { | 93 | while (count < 4) { |
94 | char *table_ptr; | 94 | char *table_ptr; |
95 | int ch; | 95 | int ch; |
@@ -101,11 +101,20 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) | |||
101 | * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n" | 101 | * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n" |
102 | */ | 102 | */ |
103 | do { | 103 | do { |
104 | ch = fgetc(src_stream); | 104 | ch = *src; |
105 | if (ch == exit_char && count == 0) | 105 | if (ch == '\0') { |
106 | return; | 106 | if (count == 0) { |
107 | if (ch == EOF) | 107 | /* Example: |
108 | bb_error_msg_and_die("truncated base64 input"); | 108 | * If we decode "QUJD <NUL>", we want |
109 | * to return ptr to NUL, not to ' ', | ||
110 | * because we did fully decode | ||
111 | * the string (to "ABC"). | ||
112 | */ | ||
113 | src_tail = src; | ||
114 | } | ||
115 | goto ret; | ||
116 | } | ||
117 | src++; | ||
109 | table_ptr = strchr(bb_uuenc_tbl_base64, ch); | 118 | table_ptr = strchr(bb_uuenc_tbl_base64, ch); |
110 | //TODO: add BASE64_FLAG_foo to die on bad char? | 119 | //TODO: add BASE64_FLAG_foo to die on bad char? |
111 | //Note that then we may need to still allow '\r' (for mail processing) | 120 | //Note that then we may need to still allow '\r' (for mail processing) |
@@ -114,21 +123,15 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) | |||
114 | /* Convert encoded character to decimal */ | 123 | /* Convert encoded character to decimal */ |
115 | ch = table_ptr - bb_uuenc_tbl_base64; | 124 | ch = table_ptr - bb_uuenc_tbl_base64; |
116 | 125 | ||
117 | if (ch == 65 /* '\n' */) { | 126 | if (ch == 65) { /* '\n' */ |
118 | /* Terminating "====" line? */ | ||
119 | if (uu_style_end && term_count == 4) | ||
120 | return; /* yes */ | ||
121 | term_count = 0; | ||
122 | continue; | 127 | continue; |
123 | } | 128 | } |
124 | /* ch is 64 if char was '=', otherwise 0..63 */ | 129 | /* ch is 64 if char was '=', otherwise 0..63 */ |
125 | translated[count] = ch & 63; /* 64 -> 0 */ | 130 | translated[count] = ch & 63; /* 64 -> 0 */ |
126 | if (ch == 64) { | 131 | if (ch == 64) { /* '=' */ |
127 | term_count++; | ||
128 | break; | 132 | break; |
129 | } | 133 | } |
130 | count++; | 134 | count++; |
131 | term_count = 0; | ||
132 | } | 135 | } |
133 | 136 | ||
134 | /* Merge 6 bit chars to 8 bit. | 137 | /* Merge 6 bit chars to 8 bit. |
@@ -136,10 +139,82 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) | |||
136 | * "eQ==" -> "y", not "y NUL NUL" | 139 | * "eQ==" -> "y", not "y NUL NUL" |
137 | */ | 140 | */ |
138 | if (count > 1) | 141 | if (count > 1) |
139 | fputc(translated[0] << 2 | translated[1] >> 4, dst_stream); | 142 | *dst++ = translated[0] << 2 | translated[1] >> 4; |
140 | if (count > 2) | 143 | if (count > 2) |
141 | fputc(translated[1] << 4 | translated[2] >> 2, dst_stream); | 144 | *dst++ = translated[1] << 4 | translated[2] >> 2; |
142 | if (count > 3) | 145 | if (count > 3) |
143 | fputc(translated[2] << 6 | translated[3], dst_stream); | 146 | *dst++ = translated[2] << 6 | translated[3]; |
144 | } /* while (1) */ | 147 | } /* while (1) */ |
148 | ret: | ||
149 | *pp_dst = dst; | ||
150 | return src_tail; | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * Decode base64 encoded stream. | ||
155 | * Can stop on EOF, specified char, or on uuencode-style "====" line: | ||
156 | * flags argument controls it. | ||
157 | */ | ||
158 | void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) | ||
159 | { | ||
160 | /* Note that EOF _can_ be passed as exit_char too */ | ||
161 | #define exit_char ((int)(signed char)flags) | ||
162 | #define uu_style_end (flags & BASE64_FLAG_UU_STOP) | ||
163 | |||
164 | /* uuencoded files have 61 byte lines. Use 64 byte buffer | ||
165 | * to process line at a time. | ||
166 | */ | ||
167 | enum { BUFFER_SIZE = 64 }; | ||
168 | |||
169 | char in_buf[BUFFER_SIZE + 2]; | ||
170 | char out_buf[BUFFER_SIZE / 4 * 3 + 2]; | ||
171 | char *out_tail; | ||
172 | const char *in_tail; | ||
173 | int term_seen = 0; | ||
174 | int in_count = 0; | ||
175 | |||
176 | while (1) { | ||
177 | while (in_count < BUFFER_SIZE) { | ||
178 | int ch = fgetc(src_stream); | ||
179 | if (ch == exit_char) { | ||
180 | if (in_count == 0) | ||
181 | return; | ||
182 | term_seen = 1; | ||
183 | break; | ||
184 | } | ||
185 | if (ch == EOF) { | ||
186 | term_seen = 1; | ||
187 | break; | ||
188 | } | ||
189 | /* Prevent "====" line to be split: stop if we see '\n'. | ||
190 | * We can also skip other whitespace and skirt the problem | ||
191 | * of files with NULs by stopping on any control char or space: | ||
192 | */ | ||
193 | if (ch <= ' ') | ||
194 | break; | ||
195 | in_buf[in_count++] = ch; | ||
196 | } | ||
197 | in_buf[in_count] = '\0'; | ||
198 | |||
199 | /* Did we encounter "====" line? */ | ||
200 | if (uu_style_end && strcmp(in_buf, "====") == 0) | ||
201 | return; | ||
202 | |||
203 | out_tail = out_buf; | ||
204 | in_tail = decode_base64(&out_tail, in_buf); | ||
205 | |||
206 | fwrite(out_buf, (out_tail - out_buf), 1, dst_stream); | ||
207 | |||
208 | if (term_seen) { | ||
209 | /* Did we consume ALL characters? */ | ||
210 | if (*in_tail == '\0') | ||
211 | return; | ||
212 | /* No */ | ||
213 | bb_error_msg_and_die("truncated base64 input"); | ||
214 | } | ||
215 | |||
216 | /* It was partial decode */ | ||
217 | in_count = strlen(in_tail); | ||
218 | memmove(in_buf, in_tail, in_count); | ||
219 | } | ||
145 | } | 220 | } |