<commit_before>/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */

#include <jose/b64.h>

#include <stdbool.h>
#include <string.h>

static const char table[] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "abcdefghijklmnopqrstuvwxyz"
    "0123456789-_";

size_t
jose_b64_dlen(size_t elen)
{
    switch (elen % 4) {
    case 0: return elen / 4 * 3;
    case 2: return elen / 4 * 3 + 1;
    case 3: return elen / 4 * 3 + 2;
    default: return 0;
    }
}

size_t
jose_b64_elen(size_t dlen)
{
    switch (dlen % 3) {
    case 0: return dlen / 3 * 4;
    case 1: return dlen / 3 * 4 + 2;
    case 2: return dlen / 3 * 4 + 3;
    default: return 0;
    }
}

bool
jose_b64_decode(const char *enc, uint8_t dec[])
{
    uint8_t rem = 0;
    size_t len = 0;

    for (size_t i = 0; enc[i]; i++) {
        uint8_t v = 0;

        for (char c = enc[i]; v < sizeof(table) && table[v] != c; v++)
            continue;

        if (v >= sizeof(table))
            return false;

        switch (i % 4) {
        case 0:
            if (!enc[i+1])
                return false;

            rem = v << 2;
            break;

        case 1:
            dec[len++] = rem | (v >> 4);
            rem = v << 4;
            break;

        case 2:
            dec[len++] = rem | (v >> 2);
            rem = v << 6;
            break;

        case 3:
            dec[len++] = rem | v;
            break;
        }
    }

    return true;
}

uint8_t *
jose_b64_decode_buf(const char *enc, size_t *len)
{
    uint8_t *buf = NULL;

    if (!enc)
        return NULL;

    *len = jose_b64_dlen(strlen(enc));
    buf = malloc(*len);
    if (!buf)
        return NULL;

    if (jose_b64_decode(enc, buf))
        return buf;

    free(buf);
    return NULL;
}

uint8_t *
jose_b64_decode_buf_json(const json_t *enc, size_t *len)
{
    if (!json_is_string(enc))
        return NULL;

    return jose_b64_decode_buf(json_string_value(enc), len);
}

bool
jose_b64_decode_json(const json_t *enc, uint8_t dec[])
{
    if (!json_is_string(enc))
        return false;

    return jose_b64_decode(json_string_value(enc), dec);
}

json_t *
jose_b64_decode_json_load(const json_t *enc)
{
    uint8_t *buf = NULL;
    json_t *out = NULL;
    size_t len = 0;

    if (!json_is_string(enc))
        return NULL;

    len = jose_b64_dlen(json_string_length(enc));
    buf = malloc(len);
    if (!buf)
        return NULL;

    if (jose_b64_decode_json(enc, buf))
        out = json_loadb((char *) buf, len, JSON_DECODE_ANY, NULL);<commit_msg>Check for zero return value<commit_after>/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */

#include <jose/b64.h>

#include <stdbool.h>
#include <string.h>

static const char table[] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "abcdefghijklmnopqrstuvwxyz"
    "0123456789-_";

size_t
jose_b64_dlen(size_t elen)
{
    switch (elen % 4) {
    case 0: return elen / 4 * 3;
    case 2: return elen / 4 * 3 + 1;
    case 3: return elen / 4 * 3 + 2;
    default: return 0;
    }
}

size_t
jose_b64_elen(size_t dlen)
{
    switch (dlen % 3) {
    case 0: return dlen / 3 * 4;
    case 1: return dlen / 3 * 4 + 2;
    case 2: return dlen / 3 * 4 + 3;
    default: return 0;
    }
}

bool
jose_b64_decode(const char *enc, uint8_t dec[])
{
    uint8_t rem = 0;
    size_t len = 0;

    for (size_t i = 0; enc[i]; i++) {
        uint8_t v = 0;

        for (char c = enc[i]; v < sizeof(table) && table[v] != c; v++)
            continue;

        if (v >= sizeof(table))
            return false;

        switch (i % 4) {
        case 0:
            if (!enc[i+1])
                return false;

            rem = v << 2;
            break;

        case 1:
            dec[len++] = rem | (v >> 4);
            rem = v << 4;
            break;

        case 2:
            dec[len++] = rem | (v >> 2);
            rem = v << 6;
            break;

        case 3:
            dec[len++] = rem | v;
            break;
        }
    }

    return true;
}

uint8_t *
jose_b64_decode_buf(const char *enc, size_t *len)
{
    uint8_t *buf = NULL;

    if (!enc)
        return NULL;

    *len = jose_b64_dlen(strlen(enc));
    buf = malloc(*len);
    if (!buf)
        return NULL;

    if (jose_b64_decode(enc, buf))
        return buf;

    free(buf);
    return NULL;
}

uint8_t *
jose_b64_decode_buf_json(const json_t *enc, size_t *len)
{
    if (!json_is_string(enc))
        return NULL;

    return jose_b64_decode_buf(json_string_value(enc), len);
}

bool
jose_b64_decode_json(const json_t *enc, uint8_t dec[])
{
    if (!json_is_string(enc))
        return false;

    return jose_b64_decode(json_string_value(enc), dec);
}

json_t *
jose_b64_decode_json_load(const json_t *enc)
{
    uint8_t *buf = NULL;
    json_t *out = NULL;
    size_t len = 0;

    if (!json_is_string(enc))
        return NULL;

    len = jose_b64_dlen(json_string_length(enc));
    if (len == 0)
        return NULL;

    buf = malloc(len);
    if (!buf)
        return NULL;

    if (jose_b64_decode_json(enc, buf))
        out = json_loadb((char *) buf, len, JSON_DECODE_ANY, NULL);
{'fraction_non_alphanumeric': 0.12964411419632382, 'fraction_numerical': 0.036566288619475945, 'mean_word_length': 2.03021327014218, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6284880', 'n_tokens_mistral': 2142, 'n_tokens_neox': 1967, 'n_words': 500}