package zeta.util;
import java.util.Arrays;
public class Base64 {
public static char PAD = '*'; private static char ENCODING_62 = '-'; private static char ENCODING_63 = '.';
public static String encode(byte[] data) {
final int dataLength = data.length;
char[] encodedData = new char[((dataLength+2)/3) << 2]; for (int i = 0, j = 3; j <= dataLength; j += 3, i += 4) {
int d = ((data[j-3] & 255) << 16) | ((data[j-2] & 255) << 8) | (data[j-1] & 255);
encodedData[i] = encodeMap[(d >> 18) & 63];
encodedData[i+1] = encodeMap[(d >> 12) & 63];
encodedData[i+2] = encodeMap[(d >> 6) & 63];
encodedData[i+3] = encodeMap[d & 63];
}
int m = dataLength%3;
if (m == 1) {
int d = data[dataLength-1] & 255;
encodedData[encodedData.length-4] = encodeMap[(d >> 2) & 63];
encodedData[encodedData.length-3] = encodeMap[(d << 4) & 63];
encodedData[encodedData.length-2] = PAD;
encodedData[encodedData.length-1] = PAD;
} else if (m == 2) {
int d = ((data[dataLength-2] & 255) << 8) | (data[dataLength-1] & 255);
encodedData[encodedData.length-4] = encodeMap[(d >> 10) & 63];
encodedData[encodedData.length-3] = encodeMap[(d >> 4) & 63];
encodedData[encodedData.length-2] = encodeMap[(d << 2) & 63];
encodedData[encodedData.length-1] = PAD;
}
return new String(encodedData);
}
public static byte[] decode(String encodedData) {
char[] encodedDataArray = encodedData.toCharArray();
int encodedDataLength = encodedDataArray.length;
int countIgnoredCharacters = 0;
for (int i = 0; i < encodedDataLength; ++i) {
int b = encodedDataArray[i];
if (b < 0 || b > 127 || decodeMap[b] < 0 && encodedDataArray[i] != PAD) {
++countIgnoredCharacters;
}
}
if (countIgnoredCharacters > 0) {
char[] c = new char[encodedDataLength-countIgnoredCharacters];
for (int i = 0, j = 0; i < encodedDataLength; ++i) {
int b = encodedDataArray[i];
if (b >= 0 && b <= 127 && (decodeMap[b] >= 0 || encodedDataArray[i] == PAD)) {
c[j++] = encodedDataArray[i];
}
}
encodedDataArray = c;
encodedDataLength = c.length;
}
if ((encodedDataLength&3) != 0) {
throw new IllegalArgumentException("Length of Base64 encoded input string is " + encodedDataLength + " which is not a multiple of 4.");
}
int dataLength = 3*encodedDataLength/4;
if (encodedDataLength > 0 && encodedDataArray[encodedDataLength-1] == PAD) {
encodedDataArray[encodedDataLength-1] = encodeMap[0];
dataLength = (3*(encodedDataLength-1))/4;
if (encodedDataArray[encodedDataLength-2] == PAD) {
dataLength = (3*(encodedDataLength-2))/4;
encodedDataArray[encodedDataLength-2] = encodeMap[0];
if (encodedDataArray[encodedDataLength-3] == PAD) {
dataLength = (3*(encodedDataLength-3))/4;
encodedDataArray[encodedDataLength-3] = encodeMap[0];
if (encodedDataArray[encodedDataLength-4] == PAD) {
throw new IllegalArgumentException("Base64 encoded input string contains too many padding characters.");
}
}
}
}
byte[] data = new byte[dataLength];
int j = 3;
for (int i = 4; j <= dataLength; i += 4, j += 3) {
int b = (decodeMap[encodedDataArray[i-4]] << 18) | (decodeMap[encodedDataArray[i-3]] << 12)
| (decodeMap[encodedDataArray[i-2]] << 6) | decodeMap[encodedDataArray[i-1]];
data[j-3] = (byte)((b >> 16) & 255);
data[j-2] = (byte)((b >> 8) & 255);
data[j-1] = (byte)(b & 255);
}
if (j-2 == dataLength) {
int b = (decodeMap[encodedDataArray[encodedDataLength-4]] << 2) | (decodeMap[encodedDataArray[encodedDataLength-3]] >> 4);
data[j-3] = (byte)(b & 255);
} else if (j-1 == dataLength) {
int b = (decodeMap[encodedDataArray[encodedDataLength-4]] << 10) | (decodeMap[encodedDataArray[encodedDataLength-3]] << 4)
| (decodeMap[encodedDataArray[encodedDataLength-2]] >> 2);
data[j-3] = (byte)((b >> 8) & 255);
data[j-2] = (byte)(b & 255);
}
return data;
}
private static byte[] decodeMap = new byte[128];
private static char[] encodeMap = new char[64];
static {
for (int i = 0; i <= 25; ++i) {
encodeMap[i] = (char)('A' + i);
}
for (int i = 26; i <= 51; ++i) {
encodeMap[i] = (char)('a' + i - 26);
}
for (int i = 52; i <= 61; ++i) {
encodeMap[i] = (char)('0' + i - 52);
}
encodeMap[62] = ENCODING_62; encodeMap[63] = ENCODING_63;
Arrays.fill(decodeMap, (byte)-1);
for (int i = 0; i < 64; ++i) {
decodeMap[encodeMap[i]] = (byte)i;
}
}
public static void main(String[] args) {
try {
java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream();
StreamUtils.writeData(new java.io.FileInputStream(args[0]), out, true, true);
System.out.println(Arrays.equals(decode(encode(out.toByteArray())), out.toByteArray()));
} catch (java.io.IOException ioe) {
ioe.printStackTrace();
}
}
}