/*
 * $Id: Base64Encoder.java,v 1.1 2007/12/07 05:04:57 nito Exp $
 *
 * Copyright (c) 1999 Norihiro Itoh, All rights reserved.
 *
 * This source file is a part of utilities.
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the Umlaut distribution.
 */
package jp.co.argo21.nautica.workflow.util;

/**
 * 任意のバイト列をBase64形式に変換するエンコーダです。
 * 
 * @author 伊藤宣博
 * @version $Revision: 1.1 $, $Date: 2007/12/07 05:04:57 $
 */
public class Base64Encoder
{
	/**
	 * 指定されたバイト列を、BASE64形式でエンコードし、 その文字列を返します。
	 * 
	 * @param raw
	 *            エンコード対象のバイト列
	 * @return BASE64形式の文字列
	 */
	public static String encode(byte[] raw)
	{
		StringBuffer encoded = new StringBuffer();

		for (int i = 0; i < raw.length; i += 3) {
			encoded.append(encodeBlock(raw, i));
		}

		return encoded.toString();
	}

	private static char[] encodeBlock(byte[] raw, int offset)
	{
		int block = 0;
		int slack = raw.length - offset - 1;
		int end = (slack >= 2) ? 2 : slack;

		for (int i = 0; i <= end; i++) {
			byte b = raw[offset + i];
			int neuter = (b < 0) ? b + 256 : b;
			block += neuter << (8 * (2 - i));
		}

		char[] base64 = new char[4];
		for (int i = 0; i < 4; i++) {
			int sixBit = (block >>> (6 * (3 - i))) & 0x3f;
			base64[i] = getChar(sixBit);
		}

		if (slack < 1)
			base64[2] = '=';
		if (slack < 2)
			base64[3] = '=';

		return base64;
	}

	private static char getChar(int sixBit)
	{
		if (sixBit >= 0 && sixBit <= 25)
			return (char) ('A' + sixBit);
		if (sixBit >= 26 && sixBit <= 51)
			return (char) ('a' + (sixBit - 26));
		if (sixBit >= 52 && sixBit <= 61)
			return (char) ('0' + (sixBit - 52));
		if (sixBit == 62)
			return '+';
		if (sixBit == 63)
			return '/';
		return '?';
	}
}
