Add @base64d for decoding base64 #47
This commit is contained in:
1 parent
dc679081fa
commit
e0b784ac6d
8 files changed
+124
-5
No files matched your search
+62
-2
@@ -396,6 +396,24 @@ static jv f_utf8bytelength(jq_state *jq, jv input) {
|
||||
|
||||
#define CHARS_ALPHANUM "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
|
||||
static const unsigned char BASE64_ENCODE_TABLE[64 + 1] = CHARS_ALPHANUM "+/";
|
||||
static const unsigned char BASE64_INVALID_ENTRY = 0xFF;
|
||||
static const unsigned char BASE64_DECODE_TABLE[255] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
62, // +
|
||||
0xFF, 0xFF, 0xFF,
|
||||
63, // /
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // 0-9
|
||||
0xFF, 0xFF, 0xFF,
|
||||
99, // =
|
||||
0xFF, 0xFF, 0xFF,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // A-Z
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // a-z
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
|
||||
static jv escape_string(jv input, const char* escapings) {
|
||||
|
||||
assert(jv_get_kind(input) == JV_KIND_STRING);
|
||||
@@ -548,7 +566,6 @@ static jv f_format(jq_state *jq, jv input, jv fmt) {
|
||||
jv_free(fmt);
|
||||
input = f_tostring(jq, input);
|
||||
jv line = jv_string("");
|
||||
const char b64[64 + 1] = CHARS_ALPHANUM "+/";
|
||||
const unsigned char* data = (const unsigned char*)jv_string_value(input);
|
||||
int len = jv_string_length_bytes(jv_copy(input));
|
||||
for (int i=0; i<len; i+=3) {
|
||||
@@ -560,7 +577,7 @@ static jv f_format(jq_state *jq, jv input, jv fmt) {
|
||||
}
|
||||
char buf[4];
|
||||
for (int j=0; j<4; j++) {
|
||||
buf[j] = b64[(code >> (18 - j*6)) & 0x3f];
|
||||
buf[j] = BASE64_ENCODE_TABLE[(code >> (18 - j*6)) & 0x3f];
|
||||
}
|
||||
if (n < 3) buf[3] = '=';
|
||||
if (n < 2) buf[2] = '=';
|
||||
@@ -568,6 +585,49 @@ static jv f_format(jq_state *jq, jv input, jv fmt) {
|
||||
}
|
||||
jv_free(input);
|
||||
return line;
|
||||
} else if (!strcmp(fmt_s, "base64d")) {
|
||||
jv_free(fmt);
|
||||
input = f_tostring(jq, input);
|
||||
const unsigned char* data = (const unsigned char*)jv_string_value(input);
|
||||
int len = jv_string_length_bytes(jv_copy(input));
|
||||
size_t decoded_len = (3 * len) / 4; // 3 usable bytes for every 4 bytes of input
|
||||
char *result = malloc(decoded_len * sizeof(char));
|
||||
memset(result, 0, decoded_len * sizeof(char));
|
||||
uint32_t ri = 0;
|
||||
int input_bytes_read=0;
|
||||
uint32_t code = 0;
|
||||
for (int i=0; i<len && data[i] != '='; i++) {
|
||||
if (BASE64_DECODE_TABLE[data[i]] == BASE64_INVALID_ENTRY) {
|
||||
free(result);
|
||||
return type_error(input, "is not valid base64 data");
|
||||
}
|
||||
|
||||
code <<= 6;
|
||||
code |= BASE64_DECODE_TABLE[data[i]];
|
||||
input_bytes_read++;
|
||||
|
||||
if (input_bytes_read == 4) {
|
||||
result[ri++] = (code >> 16) & 0xFF;
|
||||
result[ri++] = (code >> 8) & 0xFF;
|
||||
result[ri++] = code & 0xFF;
|
||||
input_bytes_read = 0;
|
||||
code = 0;
|
||||
}
|
||||
}
|
||||
if (input_bytes_read == 3) {
|
||||
result[ri++] = (code >> 10) & 0xFF;
|
||||
result[ri++] = (code >> 2) & 0xFF;
|
||||
} else if (input_bytes_read == 2) {
|
||||
result[ri++] = (code >> 4) & 0xFF;
|
||||
} else if (input_bytes_read == 1) {
|
||||
free(result);
|
||||
return type_error(input, "trailing base64 byte found");
|
||||
}
|
||||
|
||||
jv line = jv_string_sized(result, ri);
|
||||
jv_free(input);
|
||||
free(result);
|
||||
return line;
|
||||
} else {
|
||||
jv_free(input);
|
||||
return jv_invalid_with_msg(jv_string_concat(fmt, jv_string(" is not a valid format")));
|
||||
|
||||
Reference in new issue
Block a user