summaryrefslogtreecommitdiff
path: root/lib/tar/base64.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tar/base64.c')
-rw-r--r--lib/tar/base64.c39
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;
}