Denis Vlasenko | 21afc7d | 2006-09-03 15:49:40 +0000 | [diff] [blame] | 1 | /* vi: set sw=4 ts=4: */ |
| 2 | /* |
Denys Vlasenko | c8f9a8d | 2010-09-16 18:10:04 +0200 | [diff] [blame] | 3 | * Copyright 2003, Glenn McGrath |
| 4 | * Copyright 2006, Rob Landley <rob@landley.net> |
| 5 | * Copyright 2010, Denys Vlasenko |
Denis Vlasenko | 21afc7d | 2006-09-03 15:49:40 +0000 | [diff] [blame] | 6 | * |
Denys Vlasenko | 0ef64bd | 2010-08-16 20:14:46 +0200 | [diff] [blame] | 7 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
Denis Vlasenko | 21afc7d | 2006-09-03 15:49:40 +0000 | [diff] [blame] | 8 | */ |
Denis Vlasenko | 21afc7d | 2006-09-03 15:49:40 +0000 | [diff] [blame] | 9 | #include "libbb.h" |
| 10 | |
Denys Vlasenko | 2090048 | 2020-11-25 22:47:00 +0100 | [diff] [blame] | 11 | /* Conversion tables */ |
Denys Vlasenko | fc6faac | 2020-11-28 12:48:34 +0100 | [diff] [blame] | 12 | #if ENABLE_BASE32 |
| 13 | const char bb_uuenc_tbl_base32[] ALIGN1 = { |
| 14 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', |
| 15 | 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', |
| 16 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', |
| 17 | 'Y', 'Z', '2', '3', '4', '5', '6', '7', |
| 18 | /* unused: '=', */ |
| 19 | }; |
| 20 | #endif |
Denys Vlasenko | 2090048 | 2020-11-25 22:47:00 +0100 | [diff] [blame] | 21 | /* for base 64 */ |
Denys Vlasenko | fc6faac | 2020-11-28 12:48:34 +0100 | [diff] [blame] | 22 | const char bb_uuenc_tbl_base64[] ALIGN1 = { |
Denis Vlasenko | 21afc7d | 2006-09-03 15:49:40 +0000 | [diff] [blame] | 23 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', |
| 24 | 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', |
| 25 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', |
| 26 | 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', |
| 27 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', |
| 28 | 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', |
| 29 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', |
| 30 | '4', '5', '6', '7', '8', '9', '+', '/', |
Denys Vlasenko | ae04ce8 | 2020-11-28 13:39:05 +0100 | [diff] [blame] | 31 | '=' /* termination character */ |
Denis Vlasenko | 21afc7d | 2006-09-03 15:49:40 +0000 | [diff] [blame] | 32 | }; |
Denys Vlasenko | fc6faac | 2020-11-28 12:48:34 +0100 | [diff] [blame] | 33 | const char bb_uuenc_tbl_std[] ALIGN1 = { |
Denis Vlasenko | 21afc7d | 2006-09-03 15:49:40 +0000 | [diff] [blame] | 34 | '`', '!', '"', '#', '$', '%', '&', '\'', |
| 35 | '(', ')', '*', '+', ',', '-', '.', '/', |
| 36 | '0', '1', '2', '3', '4', '5', '6', '7', |
| 37 | '8', '9', ':', ';', '<', '=', '>', '?', |
| 38 | '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', |
| 39 | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', |
| 40 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', |
Denys Vlasenko | ae04ce8 | 2020-11-28 13:39:05 +0100 | [diff] [blame] | 41 | 'X', 'Y', 'Z', '[', '\\',']', '^', '_', |
Denis Vlasenko | 21afc7d | 2006-09-03 15:49:40 +0000 | [diff] [blame] | 42 | '`' /* termination character */ |
| 43 | }; |
| 44 | |
| 45 | /* |
Denis Vlasenko | e8240f1 | 2007-06-26 15:59:37 +0000 | [diff] [blame] | 46 | * Encode bytes at S of length LENGTH to uuencode or base64 format and place it |
Denis Vlasenko | 21afc7d | 2006-09-03 15:49:40 +0000 | [diff] [blame] | 47 | * to STORE. STORE will be 0-terminated, and must point to a writable |
| 48 | * buffer of at least 1+BASE64_LENGTH(length) bytes. |
| 49 | * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3)) |
| 50 | */ |
Denis Vlasenko | defc1ea | 2008-06-27 02:52:20 +0000 | [diff] [blame] | 51 | void FAST_FUNC bb_uuencode(char *p, const void *src, int length, const char *tbl) |
Denis Vlasenko | 21afc7d | 2006-09-03 15:49:40 +0000 | [diff] [blame] | 52 | { |
Denis Vlasenko | e8240f1 | 2007-06-26 15:59:37 +0000 | [diff] [blame] | 53 | const unsigned char *s = src; |
Denis Vlasenko | 21afc7d | 2006-09-03 15:49:40 +0000 | [diff] [blame] | 54 | |
Denis Vlasenko | 4661117 | 2007-08-06 15:43:17 +0000 | [diff] [blame] | 55 | /* Transform the 3x8 bits to 4x6 bits */ |
| 56 | while (length > 0) { |
| 57 | unsigned s1, s2; |
| 58 | |
| 59 | /* Are s[1], s[2] valid or should be assumed 0? */ |
| 60 | s1 = s2 = 0; |
| 61 | length -= 3; /* can be >=0, -1, -2 */ |
Denis Vlasenko | e5dbba2 | 2007-08-06 15:49:12 +0000 | [diff] [blame] | 62 | if (length >= -1) { |
Denis Vlasenko | 4661117 | 2007-08-06 15:43:17 +0000 | [diff] [blame] | 63 | s1 = s[1]; |
Denis Vlasenko | e5dbba2 | 2007-08-06 15:49:12 +0000 | [diff] [blame] | 64 | if (length >= 0) |
Denis Vlasenko | 4661117 | 2007-08-06 15:43:17 +0000 | [diff] [blame] | 65 | s2 = s[2]; |
| 66 | } |
Denis Vlasenko | 21afc7d | 2006-09-03 15:49:40 +0000 | [diff] [blame] | 67 | *p++ = tbl[s[0] >> 2]; |
Denis Vlasenko | 4661117 | 2007-08-06 15:43:17 +0000 | [diff] [blame] | 68 | *p++ = tbl[((s[0] & 3) << 4) + (s1 >> 4)]; |
| 69 | *p++ = tbl[((s1 & 0xf) << 2) + (s2 >> 6)]; |
| 70 | *p++ = tbl[s2 & 0x3f]; |
Denis Vlasenko | 21afc7d | 2006-09-03 15:49:40 +0000 | [diff] [blame] | 71 | s += 3; |
| 72 | } |
Denis Vlasenko | 4661117 | 2007-08-06 15:43:17 +0000 | [diff] [blame] | 73 | /* Zero-terminate */ |
Denis Vlasenko | 21afc7d | 2006-09-03 15:49:40 +0000 | [diff] [blame] | 74 | *p = '\0'; |
Denis Vlasenko | 4661117 | 2007-08-06 15:43:17 +0000 | [diff] [blame] | 75 | /* If length is -2 or -1, pad last char or two */ |
| 76 | while (length) { |
| 77 | *--p = tbl[64]; |
| 78 | length++; |
| 79 | } |
Denis Vlasenko | 21afc7d | 2006-09-03 15:49:40 +0000 | [diff] [blame] | 80 | } |
Denys Vlasenko | c8f9a8d | 2010-09-16 18:10:04 +0200 | [diff] [blame] | 81 | |
| 82 | /* |
Denys Vlasenko | 2cd37d6 | 2020-11-27 21:25:34 +0100 | [diff] [blame] | 83 | * Decode base64 encoded string. |
Leonid Lisovskiy | 328f27f | 2011-10-28 13:59:04 +0200 | [diff] [blame] | 84 | * |
Denys Vlasenko | ae04ce8 | 2020-11-28 13:39:05 +0100 | [diff] [blame] | 85 | * Returns: pointer past the last written output byte, |
| 86 | * the result is not NUL-terminated. |
| 87 | * (*pp_src) is advanced past the last read byte. |
Leonid Lisovskiy | 328f27f | 2011-10-28 13:59:04 +0200 | [diff] [blame] | 88 | * If points to '\0', then the source was fully decoded. |
Denys Vlasenko | c8f9a8d | 2010-09-16 18:10:04 +0200 | [diff] [blame] | 89 | */ |
Denys Vlasenko | 885121e | 2020-11-28 13:26:44 +0100 | [diff] [blame] | 90 | char* FAST_FUNC decode_base64(char *dst, const char **pp_src) |
Denys Vlasenko | c8f9a8d | 2010-09-16 18:10:04 +0200 | [diff] [blame] | 91 | { |
Denys Vlasenko | 885121e | 2020-11-28 13:26:44 +0100 | [diff] [blame] | 92 | const char *src = pp_src ? *pp_src : dst; /* for httpd.c, support NULL 2nd param */ |
Denys Vlasenko | 170b862 | 2020-11-27 20:44:55 +0100 | [diff] [blame] | 93 | unsigned ch = 0; |
Denys Vlasenko | f140b49 | 2020-11-28 12:33:50 +0100 | [diff] [blame] | 94 | unsigned t; |
Denys Vlasenko | 170b862 | 2020-11-27 20:44:55 +0100 | [diff] [blame] | 95 | int i = 0; |
Denys Vlasenko | c8f9a8d | 2010-09-16 18:10:04 +0200 | [diff] [blame] | 96 | |
Denys Vlasenko | 7467e90 | 2020-11-28 09:50:14 +0100 | [diff] [blame] | 97 | while ((t = (unsigned char)*src) != '\0') { |
| 98 | src++; |
Denys Vlasenko | c8f9a8d | 2010-09-16 18:10:04 +0200 | [diff] [blame] | 99 | |
Denys Vlasenko | 170b862 | 2020-11-27 20:44:55 +0100 | [diff] [blame] | 100 | /* "if" forest is faster than strchr(bb_uuenc_tbl_base64, t) */ |
| 101 | if (t >= '0' && t <= '9') |
| 102 | t = t - '0' + 52; |
| 103 | else if (t >= 'A' && t <= 'Z') |
| 104 | t = t - 'A'; |
| 105 | else if (t >= 'a' && t <= 'z') |
| 106 | t = t - 'a' + 26; |
| 107 | else if (t == '+') |
| 108 | t = 62; |
| 109 | else if (t == '/') |
| 110 | t = 63; |
| 111 | else if (t == '=' && (i == 3 || (i == 2 && *src == '='))) |
| 112 | /* the above disallows "==AA", "A===", "AA=A" etc */ |
| 113 | t = 0x1000000; |
| 114 | else |
Denys Vlasenko | c8f9a8d | 2010-09-16 18:10:04 +0200 | [diff] [blame] | 115 | //TODO: add BASE64_FLAG_foo to die on bad char? |
Denys Vlasenko | 170b862 | 2020-11-27 20:44:55 +0100 | [diff] [blame] | 116 | continue; |
Denys Vlasenko | c8f9a8d | 2010-09-16 18:10:04 +0200 | [diff] [blame] | 117 | |
Denys Vlasenko | 170b862 | 2020-11-27 20:44:55 +0100 | [diff] [blame] | 118 | ch = (ch << 6) | t; |
Denys Vlasenko | f140b49 | 2020-11-28 12:33:50 +0100 | [diff] [blame] | 119 | i = (i + 1) & 3; |
| 120 | if (i == 0) { |
Denys Vlasenko | 170b862 | 2020-11-27 20:44:55 +0100 | [diff] [blame] | 121 | *dst++ = (char) (ch >> 16); |
| 122 | *dst++ = (char) (ch >> 8); |
| 123 | *dst++ = (char) ch; |
Denys Vlasenko | 170b862 | 2020-11-27 20:44:55 +0100 | [diff] [blame] | 124 | if (ch & 0x1000000) { /* was last input char '='? */ |
| 125 | dst--; |
| 126 | if (ch & (0x1000000 << 6)) /* was it "=="? */ |
| 127 | dst--; |
Denys Vlasenko | c8f9a8d | 2010-09-16 18:10:04 +0200 | [diff] [blame] | 128 | break; |
Denys Vlasenko | 170b862 | 2020-11-27 20:44:55 +0100 | [diff] [blame] | 129 | } |
| 130 | ch = 0; |
Denys Vlasenko | c8f9a8d | 2010-09-16 18:10:04 +0200 | [diff] [blame] | 131 | } |
Denys Vlasenko | 170b862 | 2020-11-27 20:44:55 +0100 | [diff] [blame] | 132 | } |
Denys Vlasenko | 7467e90 | 2020-11-28 09:50:14 +0100 | [diff] [blame] | 133 | /* i is zero here if full 4-char block was decoded */ |
Denys Vlasenko | 885121e | 2020-11-28 13:26:44 +0100 | [diff] [blame] | 134 | if (pp_src) |
Denys Vlasenko | ae04ce8 | 2020-11-28 13:39:05 +0100 | [diff] [blame] | 135 | *pp_src = src - i; /* -i signals truncation: e.g. "MQ" and "MQ=" (correct encoding is "MQ==" -> "1") */ |
Denys Vlasenko | 885121e | 2020-11-28 13:26:44 +0100 | [diff] [blame] | 136 | return dst; |
Leonid Lisovskiy | 328f27f | 2011-10-28 13:59:04 +0200 | [diff] [blame] | 137 | } |
| 138 | |
Denys Vlasenko | 2090048 | 2020-11-25 22:47:00 +0100 | [diff] [blame] | 139 | #if ENABLE_BASE32 |
Denys Vlasenko | 885121e | 2020-11-28 13:26:44 +0100 | [diff] [blame] | 140 | char* FAST_FUNC decode_base32(char *dst, const char **pp_src) |
Denys Vlasenko | 2090048 | 2020-11-25 22:47:00 +0100 | [diff] [blame] | 141 | { |
Denys Vlasenko | 885121e | 2020-11-28 13:26:44 +0100 | [diff] [blame] | 142 | const char *src = *pp_src; |
| 143 | uint64_t ch = 0; |
Denys Vlasenko | f140b49 | 2020-11-28 12:33:50 +0100 | [diff] [blame] | 144 | unsigned t; |
Denys Vlasenko | 2cd37d6 | 2020-11-27 21:25:34 +0100 | [diff] [blame] | 145 | int i = 0; |
Denys Vlasenko | 2090048 | 2020-11-25 22:47:00 +0100 | [diff] [blame] | 146 | |
Denys Vlasenko | 7467e90 | 2020-11-28 09:50:14 +0100 | [diff] [blame] | 147 | while ((t = (unsigned char)*src) != '\0') { |
| 148 | src++; |
Denys Vlasenko | 2090048 | 2020-11-25 22:47:00 +0100 | [diff] [blame] | 149 | |
Denys Vlasenko | 2cd37d6 | 2020-11-27 21:25:34 +0100 | [diff] [blame] | 150 | /* "if" forest is faster than strchr(bb_uuenc_tbl_base32, t) */ |
| 151 | if (t >= '2' && t <= '7') |
| 152 | t = t - '2' + 26; |
Denys Vlasenko | 2cd37d6 | 2020-11-27 21:25:34 +0100 | [diff] [blame] | 153 | else if (t == '=' && i > 1) |
| 154 | t = 0; |
Denys Vlasenko | f140b49 | 2020-11-28 12:33:50 +0100 | [diff] [blame] | 155 | else { |
| 156 | t = (t | 0x20) - 'a'; |
| 157 | if (t > 25) |
Denys Vlasenko | 2cd37d6 | 2020-11-27 21:25:34 +0100 | [diff] [blame] | 158 | //TODO: add BASE64_FLAG_foo to die on bad char? |
Denys Vlasenko | f140b49 | 2020-11-28 12:33:50 +0100 | [diff] [blame] | 159 | continue; |
| 160 | } |
Denys Vlasenko | 2090048 | 2020-11-25 22:47:00 +0100 | [diff] [blame] | 161 | |
Denys Vlasenko | f140b49 | 2020-11-28 12:33:50 +0100 | [diff] [blame] | 162 | ch = (ch << 5) | t; |
| 163 | i = (i + 1) & 7; |
| 164 | if (i == 0) { |
Denys Vlasenko | 2cd37d6 | 2020-11-27 21:25:34 +0100 | [diff] [blame] | 165 | *dst++ = (char) (ch >> 32); |
Denys Vlasenko | f140b49 | 2020-11-28 12:33:50 +0100 | [diff] [blame] | 166 | if (src[-1] == '=') /* was last input char '='? */ |
| 167 | goto tail; |
Denys Vlasenko | 2cd37d6 | 2020-11-27 21:25:34 +0100 | [diff] [blame] | 168 | *dst++ = (char) (ch >> 24); |
| 169 | *dst++ = (char) (ch >> 16); |
| 170 | *dst++ = (char) (ch >> 8); |
| 171 | *dst++ = (char) ch; |
Denys Vlasenko | 2090048 | 2020-11-25 22:47:00 +0100 | [diff] [blame] | 172 | } |
Denys Vlasenko | 2cd37d6 | 2020-11-27 21:25:34 +0100 | [diff] [blame] | 173 | } |
Denys Vlasenko | 7467e90 | 2020-11-28 09:50:14 +0100 | [diff] [blame] | 174 | /* i is zero here if full 8-char block was decoded */ |
Denys Vlasenko | 885121e | 2020-11-28 13:26:44 +0100 | [diff] [blame] | 175 | *pp_src = src - i; |
| 176 | return dst; |
Denys Vlasenko | f140b49 | 2020-11-28 12:33:50 +0100 | [diff] [blame] | 177 | tail: |
| 178 | { |
| 179 | const char *s = src; |
| 180 | while (*--s == '=') |
| 181 | i++; |
| 182 | /* Why duplicate the below code? Testcase: |
| 183 | * echo ' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18' | base32 | base32 -d |
| 184 | * IOW, decoding of |
| 185 | * EAYSAMRAGMQDIIBVEA3CANZAHAQDSIBRGAQDCMJAGEZCAMJTEAYTIIBRGUQDCNRAGE3SAMJYBI== |
| 186 | * ==== |
| 187 | * must correctly stitch together the tail, must not overwrite |
| 188 | * the tail before it is analyzed! (we can be decoding in-place) |
| 189 | * Else testcase fails, prints trailing extra NUL bytes. |
| 190 | */ |
| 191 | *dst++ = (char) (ch >> 24); |
| 192 | *dst++ = (char) (ch >> 16); |
| 193 | *dst++ = (char) (ch >> 8); |
| 194 | *dst++ = (char) ch; |
| 195 | dst -= (i+1) * 2 / 3; /* discard last 1, 2, 3 or 4 bytes */ |
| 196 | } |
Denys Vlasenko | 885121e | 2020-11-28 13:26:44 +0100 | [diff] [blame] | 197 | *pp_src = src; |
| 198 | return dst; |
Denys Vlasenko | 2090048 | 2020-11-25 22:47:00 +0100 | [diff] [blame] | 199 | } |
| 200 | #endif |
| 201 | |
Leonid Lisovskiy | 328f27f | 2011-10-28 13:59:04 +0200 | [diff] [blame] | 202 | /* |
| 203 | * Decode base64 encoded stream. |
| 204 | * Can stop on EOF, specified char, or on uuencode-style "====" line: |
| 205 | * flags argument controls it. |
| 206 | */ |
| 207 | void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) |
| 208 | { |
| 209 | /* Note that EOF _can_ be passed as exit_char too */ |
| 210 | #define exit_char ((int)(signed char)flags) |
| 211 | #define uu_style_end (flags & BASE64_FLAG_UU_STOP) |
Denys Vlasenko | 2090048 | 2020-11-25 22:47:00 +0100 | [diff] [blame] | 212 | #define base32 (flags & BASE64_32) |
Leonid Lisovskiy | 328f27f | 2011-10-28 13:59:04 +0200 | [diff] [blame] | 213 | |
Denys Vlasenko | 7467e90 | 2020-11-28 09:50:14 +0100 | [diff] [blame] | 214 | /* uuencoded files have 61 byte lines. |
| 215 | * base32/64 have 76 byte lines by default. |
| 216 | * Use 80 byte buffer to process one line at a time. |
Leonid Lisovskiy | 328f27f | 2011-10-28 13:59:04 +0200 | [diff] [blame] | 217 | */ |
Denys Vlasenko | 7467e90 | 2020-11-28 09:50:14 +0100 | [diff] [blame] | 218 | enum { BUFFER_SIZE = 80 }; |
| 219 | /* decoded data is shorter than input, can use single buffer for both */ |
| 220 | char buf[BUFFER_SIZE + 2]; |
Leonid Lisovskiy | 328f27f | 2011-10-28 13:59:04 +0200 | [diff] [blame] | 221 | int term_seen = 0; |
| 222 | int in_count = 0; |
| 223 | |
| 224 | while (1) { |
Denys Vlasenko | 7467e90 | 2020-11-28 09:50:14 +0100 | [diff] [blame] | 225 | char *out_tail; |
| 226 | const char *in_tail; |
| 227 | |
Leonid Lisovskiy | 328f27f | 2011-10-28 13:59:04 +0200 | [diff] [blame] | 228 | while (in_count < BUFFER_SIZE) { |
| 229 | int ch = fgetc(src_stream); |
| 230 | if (ch == exit_char) { |
| 231 | if (in_count == 0) |
| 232 | return; |
| 233 | term_seen = 1; |
| 234 | break; |
| 235 | } |
| 236 | if (ch == EOF) { |
| 237 | term_seen = 1; |
| 238 | break; |
| 239 | } |
| 240 | /* Prevent "====" line to be split: stop if we see '\n'. |
| 241 | * We can also skip other whitespace and skirt the problem |
| 242 | * of files with NULs by stopping on any control char or space: |
| 243 | */ |
| 244 | if (ch <= ' ') |
| 245 | break; |
Denys Vlasenko | 7467e90 | 2020-11-28 09:50:14 +0100 | [diff] [blame] | 246 | buf[in_count++] = ch; |
Leonid Lisovskiy | 328f27f | 2011-10-28 13:59:04 +0200 | [diff] [blame] | 247 | } |
Denys Vlasenko | 7467e90 | 2020-11-28 09:50:14 +0100 | [diff] [blame] | 248 | buf[in_count] = '\0'; |
Leonid Lisovskiy | 328f27f | 2011-10-28 13:59:04 +0200 | [diff] [blame] | 249 | |
| 250 | /* Did we encounter "====" line? */ |
Denys Vlasenko | 7467e90 | 2020-11-28 09:50:14 +0100 | [diff] [blame] | 251 | if (uu_style_end && strcmp(buf, "====") == 0) |
Leonid Lisovskiy | 328f27f | 2011-10-28 13:59:04 +0200 | [diff] [blame] | 252 | return; |
| 253 | |
Denys Vlasenko | 885121e | 2020-11-28 13:26:44 +0100 | [diff] [blame] | 254 | in_tail = buf; |
Denys Vlasenko | 2090048 | 2020-11-25 22:47:00 +0100 | [diff] [blame] | 255 | #if ENABLE_BASE32 |
| 256 | if (base32) |
Denys Vlasenko | 885121e | 2020-11-28 13:26:44 +0100 | [diff] [blame] | 257 | out_tail = decode_base32(buf, &in_tail); |
Denys Vlasenko | 2090048 | 2020-11-25 22:47:00 +0100 | [diff] [blame] | 258 | else |
| 259 | #endif |
Denys Vlasenko | 885121e | 2020-11-28 13:26:44 +0100 | [diff] [blame] | 260 | out_tail = decode_base64(buf, &in_tail); |
Leonid Lisovskiy | 328f27f | 2011-10-28 13:59:04 +0200 | [diff] [blame] | 261 | |
Denys Vlasenko | 7467e90 | 2020-11-28 09:50:14 +0100 | [diff] [blame] | 262 | fwrite(buf, (out_tail - buf), 1, dst_stream); |
Leonid Lisovskiy | 328f27f | 2011-10-28 13:59:04 +0200 | [diff] [blame] | 263 | |
| 264 | if (term_seen) { |
| 265 | /* Did we consume ALL characters? */ |
| 266 | if (*in_tail == '\0') |
| 267 | return; |
| 268 | /* No */ |
Denys Vlasenko | ae04ce8 | 2020-11-28 13:39:05 +0100 | [diff] [blame] | 269 | bb_simple_error_msg_and_die("truncated input"); |
Leonid Lisovskiy | 328f27f | 2011-10-28 13:59:04 +0200 | [diff] [blame] | 270 | } |
| 271 | |
| 272 | /* It was partial decode */ |
| 273 | in_count = strlen(in_tail); |
Denys Vlasenko | 7467e90 | 2020-11-28 09:50:14 +0100 | [diff] [blame] | 274 | memmove(buf, in_tail, in_count); |
Leonid Lisovskiy | 328f27f | 2011-10-28 13:59:04 +0200 | [diff] [blame] | 275 | } |
Denys Vlasenko | c8f9a8d | 2010-09-16 18:10:04 +0200 | [diff] [blame] | 276 | } |