/**
 * @file Base64.h
 * @brief Inline Base64 encoder.
 *
 * Used exclusively for the WebSocket HTTP upgrade handshake.
 */

#ifndef STREAMHUB_BASE64_H_
#define STREAMHUB_BASE64_H_

#include "CompilerTypes.h"

namespace StreamHub {

using MARTe::uint8;
using MARTe::uint32;

static const char kBase64Chars[] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

/**
 * @brief Base64-encode @p inLen bytes from @p in into @p out (null-terminated).
 * @param out Must have room for at least ceil(inLen/3)*4 + 1 bytes.
 * @return Number of characters written (excluding null terminator).
 */
inline uint32 Base64Encode(const uint8 *in, uint32 inLen, char *out) {
    uint32 outIdx = 0u;
    uint32 i = 0u;
    while (i + 3u <= inLen) {
        out[outIdx++] = kBase64Chars[(in[i] >> 2u) & 0x3Fu];
        out[outIdx++] = kBase64Chars[((in[i] & 0x03u) << 4u) | ((in[i+1u] >> 4u) & 0x0Fu)];
        out[outIdx++] = kBase64Chars[((in[i+1u] & 0x0Fu) << 2u) | ((in[i+2u] >> 6u) & 0x03u)];
        out[outIdx++] = kBase64Chars[in[i+2u] & 0x3Fu];
        i += 3u;
    }
    uint32 rem = inLen - i;
    if (rem == 1u) {
        out[outIdx++] = kBase64Chars[(in[i] >> 2u) & 0x3Fu];
        out[outIdx++] = kBase64Chars[(in[i] & 0x03u) << 4u];
        out[outIdx++] = '=';
        out[outIdx++] = '=';
    } else if (rem == 2u) {
        out[outIdx++] = kBase64Chars[(in[i] >> 2u) & 0x3Fu];
        out[outIdx++] = kBase64Chars[((in[i] & 0x03u) << 4u) | ((in[i+1u] >> 4u) & 0x0Fu)];
        out[outIdx++] = kBase64Chars[(in[i+1u] & 0x0Fu) << 2u];
        out[outIdx++] = '=';
    }
    out[outIdx] = '\0';
    return outIdx;
}

} /* namespace StreamHub */

#endif /* STREAMHUB_BASE64_H_ */
