/*
 * base64.c - Standard Base64 encoder (RFC 4648).
 *
 * Used to produce the Sec-WebSocket-Accept header value.
 */

#include "base64.h"

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

int base64_encode(const uint8_t *in, size_t in_len,
		  char *out, size_t out_sz)
{
	size_t out_len = 4 * ((in_len + 2) / 3);
	size_t i, j;

	if (out_sz < out_len + 1)
		return -1;

	for (i = 0, j = 0; i + 2 < in_len; i += 3, j += 4) {
		uint32_t triplet = ((uint32_t)in[i] << 16) |
				   ((uint32_t)in[i + 1] << 8) |
				   ((uint32_t)in[i + 2]);

		out[j]     = b64_table[(triplet >> 18) & 0x3F];
		out[j + 1] = b64_table[(triplet >> 12) & 0x3F];
		out[j + 2] = b64_table[(triplet >> 6)  & 0x3F];
		out[j + 3] = b64_table[(triplet)       & 0x3F];
	}

	/* Handle remaining bytes */
	if (i < in_len) {
		uint32_t triplet = (uint32_t)in[i] << 16;

		if (i + 1 < in_len)
			triplet |= (uint32_t)in[i + 1] << 8;

		out[j]     = b64_table[(triplet >> 18) & 0x3F];
		out[j + 1] = b64_table[(triplet >> 12) & 0x3F];
		out[j + 2] = (i + 1 < in_len)
			   ? b64_table[(triplet >> 6) & 0x3F]
			   : '=';
		out[j + 3] = '=';
		j += 4;
	}

	out[j] = '\0';
	return (int)j;
}
