<commit_before>#include "dime/util/encoding.h"

#include <string.h>

static unsigned char const
base64_chars[64] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static unsigned char const
base64_vals[128] =
{
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, 52,
    53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 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,
    0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0
};

/**
 * @brief
 *  Perform base64-decoding on a string and return the result.
 * @note
 *  SOLVED PROBLEM - why are we reinventing the wheel?
 * @param result
 *  double pointer to a newly allocated buffer containing the base64-decoded
 *  data, or NULL on failure.
 * @param buf
 *  a pointer to a buffer containing the data to be decoded.
 * @param len
 *  the length, in bytes, of the buffer to be decoded.
 * @param outlen
 *  a pointer to a variable to receive the length of the decoded data.
 * @free_using{free}
 */
derror_t const *
base64_decode(
    dime_ctx_t const *dime_ctx,
    unsigned char **result,
    size_t *result_length,
    char const *buf,
    size_t len)
{
    derror_t const *err;
    unsigned char *o;
    const char *p;
    size_t new_len;
    size_t written = 0;
    int loop = 0;
    int value = 0;

    if (dime_ctx == NULL
        || result == NULL
        || result_length == NULL
        || buf == NULL
        || len == 0
        || len % 4 != 0)
    {
        err = ERR_BAD_PARAM;
        goto error;
    }

    new_len = (len / 4) * 3;
    if (buf[len - 1] == '=') {
        new_len--;
    }
    if (buf[len - 2] == '=') {
        new_len--;
    }

    *result = malloc(new_len);
    if (*result == NULL) {
        err = ERR_NOMEM;
        goto error;
    }

    memset(*result, 0, new_len);

    o = *result;
    p = buf;

    // Get four characters at a time from the input buffer and decode them.
    for (size_t i = 0; i < len; i++) {

        // Only process legit base64 characters.
        if ((*p >= 'A' && *p <= 'Z')
            || (*p >= 'a' && *p <= 'z')
            || (*p >= '0' && *p <= '9')
            || *p == '+'
            || *p == '/')
        {
            // Do the appropriate operation.
            switch (loop) {

            case 0:
                value = base64_vals[(int)*p++] << 18;
                loop++;
                break;
            case 1:
                value += base64_vals[(int)*p++] << 12;
                *o++ = (value & 0x00ff0000) >> 16;
                written++;
                loop++;
                break;
            case 2:
                value += (unsigned int)base64_vals[(int)*p++] << 6;
                *o++ = (value & 0x0000ff00) >> 8;
                written++;
                loop++;
                break;
            case 3:
                value += (unsigned int)base64_vals[(int)*p++];
                *o++ = value & 0x000000ff;
                written++;
                loop = 0;
                break;
            default:
                err = ERR_ENCODING;
                LOG_ERROR(dime_ctx,
                    "an unexpected error occurred during base64 decoding");
                goto cleanup_result;
            }

        } else if (*p == '=') {
            i = len;
        } else {
            p++;
        }

    }

    *result_length = written;

    return NULL;

cleanup_result:
    free(*result);
    *result = NULL;
error:
    *result_length = 0;
    return err;
}

/**
 * @brief
 *  Return the base64-encoded string of a data buffer.
 * @param result
 *  a pointer to a newly allocated sds string containing the base64-encoded<commit_msg>Update encoding.c<commit_after>#include "dime/util/encoding.h"

#include <string.h>

static unsigned char const
base64_chars[64] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static unsigned char const
base64_vals[128] =
{
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, 52,
    53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 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,
    0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0
};

/**
 * @brief
 *  Perform base64-decoding on a string and return the result.
 * @note
 *  SOLVED PROBLEM - why are we reinventing the wheel?
 * @param result
 *  double pointer to a newly allocated buffer containing the base64-decoded
 *  data, or NULL on failure.
 * @param buf
 *  a pointer to a buffer containing the data to be decoded.
 * @param len
 *  the length, in bytes, of the buffer to be decoded.
 * @param outlen
 *  a pointer to a variable to receive the length of the decoded data.
 * @free_using{free}
 */
derror_t const *
base64_decode(
    dime_ctx_t const *dime_ctx,
    unsigned char **result,
    size_t *result_length,
    char const *buf,
    size_t len)
{
    derror_t const *err;
    unsigned char *o;
    const char *p;
    size_t new_len;
    size_t written = 0;
    int loop = 0;
    int value = 0;

    if (dime_ctx == NULL
        || result == NULL
        || result_length == NULL
        || buf == NULL
        || len == 0
        || len % 4 != 0)
    {
        err = ERR_BAD_PARAM;
        goto error;
    }

    new_len = (len / 4) * 3;
    if (buf[len - 1] == '=') {
        new_len--;
    }
    if (buf[len - 2] == '=') {
        new_len--;
    }

    *result = malloc(new_len);
    if (*result == NULL) {
        err = ERR_NOMEM;
        goto error;
    }

    memset(*result, 0, new_len);

    o = *result;
    p = buf;

    // Get four characters at a time from the input buffer and decode them.
    for (size_t i = 0; i < len; i++) {

        // Only process legit base64 characters.
        if ((*p >= 'A' && *p <= 'Z')
            || (*p >= 'a' && *p <= 'z')
            || (*p >= '0' && *p <= '9')
            || *p == '+'
            || *p == '/')
        {
            // Do the appropriate operation.
            switch (loop) {

            case 0:
                value = base64_vals[(int)*p++] << 18;
                loop++;
                break;
            case 1:
                value += base64_vals[(int)*p++] << 12;
                *o++ = (value & 0x00ff0000) >> 16;
                written++;
                loop++;
                break;
            case 2:
                value += (unsigned int)base64_vals[(int)*p++] << 6;
                *o++ = (value & 0x0000ff00) >> 8;
                written++;
                loop++;
                break;
            case 3:
                value += (unsigned int)base64_vals[(int)*p++];
                *o++ = value & 0x000000ff;
                written++;
                loop = 0;
                break;
            default:
                err = ERR_ENCODING;
                LOG_ERROR(dime_ctx,
                    "an unexpected error occurred during base64 decoding");
                goto cleanup_result;
            }

        } else if (*p == '=') {
            i = len;
        } else {
            p++;
        }

    }

    *result_length = written;

    return NULL;

cleanup_result:
    free(*result);
    *result = NULL;
error:
    return err;
}

/**
 * @brief
 *  Return the base64-encoded string of a data buffer.
 * @param result
 *  a pointer to a newly allocated sds string containing the base64-encoded
{'fraction_non_alphanumeric': 0.14530358069538143, 'fraction_numerical': 0.07044628956927868, 'mean_word_length': 1.6132203389830508, 'pattern_counts': {'":': 0, '<': 25, '<?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': 26, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4292252', 'n_tokens_mistral': 3198, 'n_tokens_neox': 2626, 'n_words': 892}