/*
	ZazouMiniWebServer

	Copyright (C) 2003-2011 Xavier Garreau <xavier@xgarreau.org>

	This file is part of ZazouMiniWebServer.

    ZazouMiniWebServer is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    ZazouMiniWebServer is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ZazouMiniWebServer; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/

#include <iostream>
#include "stdafx.h"
#include "ZMWSbase64.h"

namespace base64 {
	const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
}
	

const std::string base64::encode(const std::string& a_string) {
	const char *p_source = a_string.c_str();
	std::string b64str;
	
	unsigned int source_len = a_string.length();
	unsigned int res_len = (8*source_len+5)/6;
	unsigned int s_ind, s_res, b64_index;
	
	for (unsigned int i=0; i < res_len ; ++i) {
		s_ind = (6*i)/8;
		s_res = (6*i)%8;
		if (s_res<=2) {
			b64_index = (p_source[s_ind] >> (2 - s_res)) & 0x3f;
		} else {
			b64_index = (p_source[s_ind] << (s_res - 2)) & 0x3f;
			b64_index |= (p_source[s_ind+1] >> (8 - (s_res - 2))) & 0x3f;
		}
		b64str += alphabet[b64_index];
	}
	while (b64str.length()%4) b64str += '=';
	return b64str;
}

const char base64::get_num_val(const char& b64_char) {
	char ret_char = b64_char;
	if ((ret_char>='A') && (ret_char<='Z')) {
		ret_char-='A';
	} else if ((ret_char>='a') && (ret_char<='z')) {
		ret_char+=26-'a';
	} else if ((ret_char>='0') && (ret_char<='9')) {
		ret_char+=52-'0';
	} else if (ret_char=='+') {
		ret_char=62;
	} else if (ret_char=='/') {
		ret_char=63;
	} else {
		ret_char = -1;
	}
	return ret_char;
}

const std::string base64::decode(const std::string& b64_string) {
	const char *p_source = b64_string.c_str();
	std::string res_str;
	
	unsigned int source_len = b64_string.length();
	unsigned int i=0;
	
	char res_char;
	char src_char;
	
	while ((i < source_len) && (p_source[i]!='=')) {
		src_char = get_num_val(p_source[i]);
		if (src_char == -1) {
			++i;
			continue;
		}
		
		switch (i%4) {
		case 0:
			res_char = src_char << 2;
			break;
		case 1:
			res_char += src_char >> 4;
			res_str += res_char;
			res_char = src_char << 4;
			break;
		case 2:
			res_char += src_char >> 2;
			res_str += res_char;
			res_char = src_char << 6;
			break;
		case 3:
			res_char += src_char;
			res_str += res_char;
			break;
		}
		++i;
	}
	return res_str;
}
