diff options
Diffstat (limited to 'lib/tar/base64.c')
-rw-r--r-- | lib/tar/base64.c | 39 |
1 files changed, 29 insertions, 10 deletions
diff --git a/lib/tar/base64.c b/lib/tar/base64.c index 0ccf3c4..f88444a 100644 --- a/lib/tar/base64.c +++ b/lib/tar/base64.c @@ -23,18 +23,37 @@ static sqfs_u8 convert(char in) return 0; } -void base64_decode(sqfs_u8 *out, const char *in) +size_t base64_decode(sqfs_u8 *out, const char *in, size_t len) { - char temp[4]; + sqfs_u8 *start = out; - while (*in != '\0' && *in != '=') { - temp[0] = *in == '\0' ? 0 : convert(*(in++)); - temp[1] = *in == '\0' ? 0 : convert(*(in++)); - temp[2] = *in == '\0' ? 0 : convert(*(in++)); - temp[3] = *in == '\0' ? 0 : convert(*(in++)); + while (len > 0) { + unsigned int diff = 0, value = 0; - *(out++) = ((temp[0] << 2) & 0xFC) | ((temp[1] >> 4) & 0x03); - *(out++) = ((temp[1] << 4) & 0xF0) | ((temp[2] >> 2) & 0x0F); - *(out++) = ((temp[2] << 6) & 0xC0) | ( temp[3] & 0x3F); + while (diff < 4 && len > 0) { + if (*in == '=' || *in == '_' || *in == '\0') { + len = 0; + } else { + value = (value << 6) | convert(*(in++)); + --len; + ++diff; + } + } + + if (diff < 2) + break; + + value <<= 6 * (4 - diff); + + switch (diff) { + case 4: out[2] = value & 0xff; /* fall-through */ + case 3: out[1] = (value >> 8) & 0xff; /* fall-through */ + default: out[0] = (value >> 16) & 0xff; + } + + out += (diff * 3) / 4; } + + *out = '\0'; + return out - start; } |