summaryrefslogtreecommitdiffstats
path: root/src/builtin.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/builtin.c')
-rw-r--r--src/builtin.c64
1 files changed, 62 insertions, 2 deletions
diff --git a/src/builtin.c b/src/builtin.c
index aa0ab4d5..24e311e1 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -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")));