// Copyright (C) 2003-2009 by Object Mentor, Inc. All rights reserved.
// Released under the terms of the CPL Common Public License version 1.0.
package fitnesse.util;
import java.io.UnsupportedEncodingException;
import util.FileUtil;
public class Base64 {
private static final byte[] base64Alphabet =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes();
private static final byte pad = '=';
private static final int[] base64Value;
static {{
base64Value = new int[0xff+1];
for (int i = 0; i <= 0xff; i++)
base64Value[i] = -1;
for (int v = 0; v <= 0x3f; v++)
base64Value[base64Alphabet[v]] = v;
base64Value[pad] = 0;
}}
public static String decode(String value) throws UnsupportedEncodingException {
return new String(decode(value.getBytes(FileUtil.CHARENCODING)));
}
public static byte[] decode(byte[] bytes) {
int lengthOfDecoding = getLengthOfDecoding(bytes);
byte[] decoding = new byte[lengthOfDecoding];
int decodingIndex = 0;
for (int index = 0; index < bytes.length; index += 4) {
int v1 = getValueFor(bytes[index]);
int v2 = getValueFor(bytes[index + 1]);
int v3 = getValueFor(bytes[index + 2]);
int v4 = getValueFor(bytes[index + 3]);
int c1 = (v1 << 2 | v2 >> 4) & 0xff;
int c2 = (v2 << 4 | v3 >> 2) & 0xff;
int c3 = (v3 << 6 | v4) & 0xff;
decoding[decodingIndex++] = (byte)c1;
if (bytes[index + 2] != pad)
decoding[decodingIndex++] = (byte)c2;
if (bytes[index + 3] != pad)
decoding[decodingIndex++] = (byte)c3;
}
return decoding;
}
public static String encode(String value) {
return new String(encode(value.getBytes()));
}
public static byte[] encode(byte[] bytes) {
int inputLength = bytes.length;
int lengthOfEncoding = getLengthOfEncoding(bytes);
byte[] encoding = new byte[lengthOfEncoding];
int encodingIndex = 0;
int index = 0;
while (index < inputLength) {
byte c1 = bytes[index];
byte c2 = index + 1 >= inputLength ? 0 : bytes[index + 1];
byte c3 = index + 2 >= inputLength ? 0 : bytes[index + 2];
int v1 = ((c1 & 0xfc) >> 2) & 0x3f;
int v2 = (c1 << 4 | (c2 & 0xf0) >> 4) & 0x3f;
int v3 = (c2 << 2 | (c3 & 0xc0) >> 6) & 0x3f;
int v4 = c3 & 0x3f;
encoding[encodingIndex++] = base64Alphabet[v1];
encoding[encodingIndex++] = base64Alphabet[v2];
encoding[encodingIndex++] = (index + 1 >= inputLength) ? pad : base64Alphabet[v3];
encoding[encodingIndex++] = (index + 2 >= inputLength) ? pad : base64Alphabet[v4];
index += 3;
}
return encoding;
}
private static int getLengthOfDecoding(byte[] bytes) {
if ((bytes.length & 3) != 0)
throw new IllegalArgumentException("Truncated BASE64 data? length=" + bytes.length);
int lengthOfOutput = (bytes.length >> 2) * 3;
if (bytes.length > 0) {
if (bytes[bytes.length - 1] == pad)
lengthOfOutput--;
if (bytes[bytes.length - 2] == pad)
lengthOfOutput--;
}
return lengthOfOutput;
}
private static int getLengthOfEncoding(byte[] bytes) {
return ((bytes.length + 2) / 3) << 2;
}
public static int getValueFor(byte b) {
int value = base64Value[b & 0xff];
if (value == -1)
throw new IllegalArgumentException("Invalid BASE64 symbol: " + (char)(b & 0xff));
return value;
}
}