
U8* @base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

U8* @base64_decode(U8* input, I64* output_length)
{
    I64 input_length = StrLen(input);
    if (input_length % 4 != 0) {
        return NULL; // Invalid Base64 input length
    }

    // Calculate the expected output length
    *output_length = (3 * input_length) / 4;
    if (input[input_length - 1] == '=') {
        (*output_length)--;
    }
    if (input[input_length - 2] == '=') {
        (*output_length)--;
    }

    // Allocate memory for the decoded data
    U8* decoded_data = CAlloc(*output_length, erythros_mem_task);
    if (decoded_data == NULL) {
        return NULL; // Memory allocation failed
    }

    // Initialize variables for decoding process
    I32 i, j = 0;
    U32 sextet_bits = 0;
    I64 sextet_count = 0;
    U32 base64_value;
    U8* char_pointer;
    U8 input_find_buf[2];
    input_find_buf[1] = NULL;

    // Loop through the Base64 input and decode it
    for (i = 0; i < input_length; i++) {
        // Convert Base64 character to a 6-bit value
        base64_value = 0;
        if (input[i] == '=') {
            base64_value = 0;
        } else {
            input_find_buf[0] = input[i];
            char_pointer = StrFirstOcc(@base64_chars, input_find_buf);
            if (char_pointer == NULL) {
                Free(decoded_data);
                return NULL; // Invalid Base64 character
            }
            base64_value = char_pointer - @base64_chars;
        }

        // Combine 6-bit values into a 24-bit sextet
        sextet_bits = (sextet_bits << 6) | base64_value;
        sextet_count++;

        // When a sextet is complete, decode it into three bytes
        if (sextet_count == 4) {
            decoded_data[j++] = (sextet_bits >> 16) & 0xFF;
            decoded_data[j++] = (sextet_bits >> 8) & 0xFF;
            decoded_data[j++] = sextet_bits & 0xFF;
            sextet_bits = 0;
            sextet_count = 0;
        }
    }

    return decoded_data;
}

U8* @base64_encode(U8* input, I64 input_length)
{
    I64 i;
    U8 buf[3];
    I64 c = 0;
    U8* output = CAlloc(input_length * 2, erythros_mem_task);

    for (i = 0; i < input_length; i += 3) {
        buf[0] = input[i];
        buf[1] = @t((i + 1 < input_length), input[i + 1], 0);
        buf[2] = @t((i + 2 < input_length), input[i + 2], 0);

        output[c++] = @base64_chars[(buf[0] & 0xfc) >> 2];
        output[c++] = @base64_chars[((buf[0] & 0x03) << 4) + ((buf[1] & 0xf0) >> 4)];
        output[c++] = @t((i + 1 < input_length), @base64_chars[((buf[1] & 0x0f) << 2) + ((buf[2] & 0xc0) >> 6)], '=');
        output[c++] = @t((i + 2 < input_length), @base64_chars[buf[2] & 0x3f], '=');
    }

    output[c] = '\0';
    return output;
}

"base64 ";
