/*	
 *	clipcode.c
 *
 *	文字コード処理
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2007 Naoyuki Sawa
 *
 *	* Mon Feb 19 00:05:57 JST 2007 Naoyuki Sawa
 *	- 1st リリース。
 */
#include "clip.h"

/****************************************************************************
 *	Base64
 ****************************************************************************/

static const char base64_tbl[/*64 + 1(nul)*/] =
	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	"abcdefghijklmnopqrstuvwxyz"
	"0123456789+/";

int
base64_encode(
	      char*  dst, int dst_cap,
	const void* _src, int src_len)
{
	const unsigned char* src = _src;
	//
	int dst_len;
	int a;

	dst_len = ((src_len + 2) / 3) * 4;
	if(dst_cap < (dst_len + 1/*nul*/)) DIE(); /* 出力バッファ不足 */

	while(src_len) {
		switch(src_len) {
		case 1:
			/* xxxxxx xx0000 000000 000000 */
			a  = *src++ << 16;
			*dst++ = base64_tbl[(a >> 18) & 0x3f];
			*dst++ = base64_tbl[(a >> 12) & 0x3f];
			*dst++ = '=';
			*dst++ = '=';
			src_len -= 1;
			break;
		case 2:
			/* xxxxxx xxyyyy yyyy00 000000 */
			a  = *src++ << 16;
			a |= *src++ <<  8;
			*dst++ = base64_tbl[(a >> 18) & 0x3f];
			*dst++ = base64_tbl[(a >> 12) & 0x3f];
			*dst++ = base64_tbl[(a >>  6) & 0x3f];
			*dst++ = '=';
			src_len -= 2;
			break;
		default: /* 3以上 */
			/* xxxxxx xxyyyy yyyyzz zzzzzz */
			a  = *src++ << 16;
			a |= *src++ <<  8;
			a |= *src++ <<  0;
			*dst++ = base64_tbl[(a >> 18) & 0x3f];
			*dst++ = base64_tbl[(a >> 12) & 0x3f];
			*dst++ = base64_tbl[(a >>  6) & 0x3f];
			*dst++ = base64_tbl[(a >>  0) & 0x3f];
			src_len -= 3;
			break;
		}
	}

	*dst++ = '\0'/*nul*/;

	return dst_len;
}

int
base64_decode(
	      void* _dst, int dst_cap,
	const char*  src)
{
	unsigned char* dst = _dst;
	//
	int src_len;
	int dst_len;
	int a;

	src_len = strlen(src);
	if(!src_len) return 0;
	if(src_len & 3) DIE(); /* Base64エンコードされた文字列は四文字の倍数であるはず */
	dst_len = (src_len / 4) * 3;
	if(src[src_len - 1] == '=') { src_len--; dst_len--; }
	if(src[src_len - 1] == '=') { src_len--; dst_len--; }
	if((int)strspn(src, base64_tbl) != src_len) DIE(); /* 不正な文字が含まれている */
	if(dst_cap < dst_len) DIE(); /* 出力バッファ不足 */

	while(src_len) {
		switch(src_len) {
		//case 1: → 有り得ません
		case 2:
			a  = (strchr(base64_tbl, *src++) - base64_tbl) << 18;
			a |= (strchr(base64_tbl, *src++) - base64_tbl) << 12;
			*dst++ = a >> 16;
			src_len -= 2;
			break;
		case 3:
			a  = (strchr(base64_tbl, *src++) - base64_tbl) << 18;
			a |= (strchr(base64_tbl, *src++) - base64_tbl) << 12;
			a |= (strchr(base64_tbl, *src++) - base64_tbl) <<  6;
			*dst++ = a >> 16;
			*dst++ = a >>  8;
			src_len -= 3;
			break;
		default: /* 4以上 */
			a  = (strchr(base64_tbl, *src++) - base64_tbl) << 18;
			a |= (strchr(base64_tbl, *src++) - base64_tbl) << 12;
			a |= (strchr(base64_tbl, *src++) - base64_tbl) <<  6;
			a |= (strchr(base64_tbl, *src++) - base64_tbl) <<  0;
			*dst++ = a >> 16;
			*dst++ = a >>  8;
			*dst++ = a >>  0;
			src_len -= 4;
			break;
		}
	}

	return dst_len;
}

