package net.proxy;
public class BASE64Decoder {
private static final int EIGHT_BIT_MASK = 0xFF;
public byte[] decodeBuffer(String data) {
StringWrapper wrapper = new StringWrapper(data);
int length = wrapper.getUsefulLength() * 3 / 4;
byte byteArray[] = new byte[length];
int byteTriplet = 0;
int index = 0;
while (index + 2 < length) {
index = processByteArray(
wrapper,
byteArray,
index);
}
checkIfWeHave1ByteLeft(
index,
length,
wrapper, byteArray);
checkIfWeHave2BytesLeft(index,
length,
wrapper,
byteArray);
return byteArray;
}
private void checkIfWeHave2BytesLeft(int index, int length, StringWrapper wrapper, byte[] byteArray) {
int byteTriplet;
if (index == length - 2) {
byteTriplet = charToInt(wrapper.getNextUsefulChar());
byteTriplet <<= 6;
byteTriplet |= charToInt(wrapper.getNextUsefulChar());
byteTriplet <<= 6;
byteTriplet |= charToInt(wrapper.getNextUsefulChar());
byteTriplet >>= 2;
byteArray[index + 1] = (byte) (byteTriplet & EIGHT_BIT_MASK);
byteTriplet >>= 8;
byteArray[index] = (byte) (byteTriplet & EIGHT_BIT_MASK);
}
}
private void checkIfWeHave1ByteLeft(int byteIndex, int byteArrayLength, StringWrapper wrapper, byte[] result) {
int byteTriplet;
if (byteIndex == byteArrayLength - 1) {
byteTriplet = charToInt(wrapper.getNextUsefulChar());
byteTriplet <<= 6;
byteTriplet |= charToInt(wrapper.getNextUsefulChar());
byteTriplet >>= 4;
result[byteIndex] = (byte) (byteTriplet & EIGHT_BIT_MASK);
}
}
private int processByteArray(StringWrapper wrapper, byte[] result, int byteIndex) {
int byteTriplet;
byteTriplet = charToInt(wrapper.getNextUsefulChar());
byteTriplet <<= 6;
byteTriplet |= charToInt(wrapper.getNextUsefulChar());
byteTriplet <<= 6;
byteTriplet |= charToInt(wrapper.getNextUsefulChar());
byteTriplet <<= 6;
byteTriplet |= charToInt(wrapper.getNextUsefulChar());
result[byteIndex + 2] = (byte) (byteTriplet & EIGHT_BIT_MASK);
byteTriplet >>= 8;
result[byteIndex + 1] = (byte) (byteTriplet & EIGHT_BIT_MASK);
byteTriplet >>= 8;
result[byteIndex] = (byte) (byteTriplet & EIGHT_BIT_MASK);
byteIndex += 3;
return byteIndex;
}
private int charToInt(char c) {
if (c >= 'A' && c <= 'Z') {
return c - 'A';
}
if (c >= 'a' && c <= 'z') {
return (c - 'a') + Constants.LOWER_CASE_A_VALUE;
}
if (c >= '0' && c <= '9') {
return (c - '0') + Constants.ZERO_VALUE;
}
if (c == '+') {
return Constants.PLUS_VALUE;
}
if (c == '/') {
return Constants.SLASH_VALUE;
}
throw new IllegalArgumentException(c + " is not a valid Base64 character.");
}
private class StringWrapper {
private String mString;
private int mIndex = 0;
private int mUsefulLength;
private boolean isUsefulChar(char c) {
return (c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
(c == '+') ||
(c == '/');
}
public StringWrapper(String s) {
mString = s;
mUsefulLength = 0;
int length = mString.length();
for (int i = 0; i < length; i++) {
if (isUsefulChar(mString.charAt(i))) {
mUsefulLength++;
}
}
}
public int getUsefulLength() {
return mUsefulLength;
}
public char getNextUsefulChar() {
char result = '_'; while (!isUsefulChar(result)) {
result = mString.charAt(mIndex++);
}
return result;
}
}
}