Base64public class Base64 extends Object implements BinaryEncoder, BinaryDecoderProvides Base64 encoding and decoding as defined by RFC 2045.
This class implements section 6.8. Base64 Content-Transfer-Encoding
from RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One:
Format of Internet Message Bodies by Freed and Borenstein. |
Fields Summary |
---|
static final int | CHUNK_SIZEChunk size per RFC 2045 section 6.8.
The {@value} character limit does not count the trailing CRLF, but counts
all other characters, including any equal signs. | static final byte[] | CHUNK_SEPARATORChunk separator per RFC 2045 section 2.1. | static final int | BASELENGTHThe base length. | static final int | LOOKUPLENGTHLookup length. | static final int | EIGHTBITUsed to calculate the number of bits in a byte. | static final int | SIXTEENBITUsed when encoding something which has fewer than 24 bits. | static final int | TWENTYFOURBITGROUPUsed to determine how many bits data contains. | static final int | FOURBYTEUsed to get the number of Quadruples. | static final int | SIGNUsed to test the sign of a byte. | static final byte | PADByte used to pad output. | private static byte[] | base64Alphabet | private static byte[] | lookUpBase64Alphabet |
Methods Summary |
---|
public java.lang.Object | decode(java.lang.Object pObject)Decodes an Object using the base64 algorithm. This method
is provided in order to satisfy the requirements of the
Decoder interface, and will throw a DecoderException if the
supplied object is not of type byte[].
if (!(pObject instanceof byte[])) {
throw new DecoderException("Parameter supplied to Base64 decode is not a byte[]");
}
return decode((byte[]) pObject);
| public byte[] | decode(byte[] pArray)Decodes a byte[] containing containing
characters in the Base64 alphabet.
return decodeBase64(pArray);
| public static byte[] | decodeBase64(byte[] base64Data)Decodes Base64 data into octects
// RFC 2045 requires that we discard ALL non-Base64 characters
base64Data = discardNonBase64(base64Data);
// handle the edge case, so we don't have to worry about it later
if (base64Data.length == 0) {
return new byte[0];
}
int numberQuadruple = base64Data.length / FOURBYTE;
byte decodedData[] = null;
byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;
// Throw away anything not in base64Data
int encodedIndex = 0;
int dataIndex = 0;
{
// this sizes the output array properly - rlw
int lastData = base64Data.length;
// ignore the '=' padding
while (base64Data[lastData - 1] == PAD) {
if (--lastData == 0) {
return new byte[0];
}
}
decodedData = new byte[lastData - numberQuadruple];
}
for (int i = 0; i < numberQuadruple; i++) {
dataIndex = i * 4;
marker0 = base64Data[dataIndex + 2];
marker1 = base64Data[dataIndex + 3];
b1 = base64Alphabet[base64Data[dataIndex]];
b2 = base64Alphabet[base64Data[dataIndex + 1]];
if (marker0 != PAD && marker1 != PAD) {
//No PAD e.g 3cQl
b3 = base64Alphabet[marker0];
b4 = base64Alphabet[marker1];
decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
decodedData[encodedIndex + 1] =
(byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);
} else if (marker0 == PAD) {
//Two PAD e.g. 3c[Pad][Pad]
decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
} else if (marker1 == PAD) {
//One PAD e.g. 3cQ[Pad]
b3 = base64Alphabet[marker0];
decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
decodedData[encodedIndex + 1] =
(byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
}
encodedIndex += 3;
}
return decodedData;
| static byte[] | discardNonBase64(byte[] data)Discards any characters outside of the base64 alphabet, per
the requirements on page 25 of RFC 2045 - "Any characters
outside of the base64 alphabet are to be ignored in base64
encoded data."
byte groomedData[] = new byte[data.length];
int bytesCopied = 0;
for (int i = 0; i < data.length; i++) {
if (isBase64(data[i])) {
groomedData[bytesCopied++] = data[i];
}
}
byte packedData[] = new byte[bytesCopied];
System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
return packedData;
| static byte[] | discardWhitespace(byte[] data)Discards any whitespace from a base-64 encoded block.
byte groomedData[] = new byte[data.length];
int bytesCopied = 0;
for (int i = 0; i < data.length; i++) {
switch (data[i]) {
case (byte) ' " :
case (byte) '\n" :
case (byte) '\r" :
case (byte) '\t" :
break;
default:
groomedData[bytesCopied++] = data[i];
}
}
byte packedData[] = new byte[bytesCopied];
System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
return packedData;
| public java.lang.Object | encode(java.lang.Object pObject)Encodes an Object using the base64 algorithm. This method
is provided in order to satisfy the requirements of the
Encoder interface, and will throw an EncoderException if the
supplied object is not of type byte[].
if (!(pObject instanceof byte[])) {
throw new EncoderException(
"Parameter supplied to Base64 encode is not a byte[]");
}
return encode((byte[]) pObject);
| public byte[] | encode(byte[] pArray)Encodes a byte[] containing binary data, into a byte[] containing
characters in the Base64 alphabet.
return encodeBase64(pArray, false);
| public static byte[] | encodeBase64(byte[] binaryData)Encodes binary data using the base64 algorithm but
does not chunk the output.
return encodeBase64(binaryData, false);
| public static byte[] | encodeBase64(byte[] binaryData, boolean isChunked)Encodes binary data using the base64 algorithm, optionally
chunking the output into 76 character blocks.
int lengthDataBits = binaryData.length * EIGHTBIT;
int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
byte encodedData[] = null;
int encodedDataLength = 0;
int nbrChunks = 0;
if (fewerThan24bits != 0) {
//data not divisible by 24 bit
encodedDataLength = (numberTriplets + 1) * 4;
} else {
// 16 or 8 bit
encodedDataLength = numberTriplets * 4;
}
// If the output is to be "chunked" into 76 character sections,
// for compliance with RFC 2045 MIME, then it is important to
// allow for extra length to account for the separator(s)
if (isChunked) {
nbrChunks =
(CHUNK_SEPARATOR.length == 0 ? 0 : (int) Math.ceil((float) encodedDataLength / CHUNK_SIZE));
encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length;
}
encodedData = new byte[encodedDataLength];
byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
int encodedIndex = 0;
int dataIndex = 0;
int i = 0;
int nextSeparatorIndex = CHUNK_SIZE;
int chunksSoFar = 0;
//log.debug("number of triplets = " + numberTriplets);
for (i = 0; i < numberTriplets; i++) {
dataIndex = i * 3;
b1 = binaryData[dataIndex];
b2 = binaryData[dataIndex + 1];
b3 = binaryData[dataIndex + 2];
//log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3);
l = (byte) (b2 & 0x0f);
k = (byte) (b1 & 0x03);
byte val1 =
((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
byte val2 =
((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
byte val3 =
((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
//log.debug( "val2 = " + val2 );
//log.debug( "k4 = " + (k<<4) );
//log.debug( "vak = " + (val2 | (k<<4)) );
encodedData[encodedIndex + 1] =
lookUpBase64Alphabet[val2 | (k << 4)];
encodedData[encodedIndex + 2] =
lookUpBase64Alphabet[(l << 2) | val3];
encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f];
encodedIndex += 4;
// If we are chunking, let's put a chunk separator down.
if (isChunked) {
// this assumes that CHUNK_SIZE % 4 == 0
if (encodedIndex == nextSeparatorIndex) {
System.arraycopy(
CHUNK_SEPARATOR,
0,
encodedData,
encodedIndex,
CHUNK_SEPARATOR.length);
chunksSoFar++;
nextSeparatorIndex =
(CHUNK_SIZE * (chunksSoFar + 1)) +
(chunksSoFar * CHUNK_SEPARATOR.length);
encodedIndex += CHUNK_SEPARATOR.length;
}
}
}
// form integral number of 6-bit groups
dataIndex = i * 3;
if (fewerThan24bits == EIGHTBIT) {
b1 = binaryData[dataIndex];
k = (byte) (b1 & 0x03);
//log.debug("b1=" + b1);
//log.debug("b1<<2 = " + (b1>>2) );
byte val1 =
((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4];
encodedData[encodedIndex + 2] = PAD;
encodedData[encodedIndex + 3] = PAD;
} else if (fewerThan24bits == SIXTEENBIT) {
b1 = binaryData[dataIndex];
b2 = binaryData[dataIndex + 1];
l = (byte) (b2 & 0x0f);
k = (byte) (b1 & 0x03);
byte val1 =
((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
byte val2 =
((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex + 1] =
lookUpBase64Alphabet[val2 | (k << 4)];
encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2];
encodedData[encodedIndex + 3] = PAD;
}
if (isChunked) {
// we also add a separator to the end of the final chunk.
if (chunksSoFar < nbrChunks) {
System.arraycopy(
CHUNK_SEPARATOR,
0,
encodedData,
encodedDataLength - CHUNK_SEPARATOR.length,
CHUNK_SEPARATOR.length);
}
}
return encodedData;
| public static byte[] | encodeBase64Chunked(byte[] binaryData)Encodes binary data using the base64 algorithm and chunks
the encoded output into 76 character blocks
return encodeBase64(binaryData, true);
| public static boolean | isArrayByteBase64(byte[] arrayOctect)Tests a given byte array to see if it contains
only valid characters within the Base64 alphabet.
arrayOctect = discardWhitespace(arrayOctect);
int length = arrayOctect.length;
if (length == 0) {
// shouldn't a 0 length array be valid base64 data?
// return false;
return true;
}
for (int i = 0; i < length; i++) {
if (!isBase64(arrayOctect[i])) {
return false;
}
}
return true;
| private static boolean | isBase64(byte octect)
// Populating the lookup and character arrays
for (int i = 0; i < BASELENGTH; i++) {
base64Alphabet[i] = (byte) -1;
}
for (int i = 'Z"; i >= 'A"; i--) {
base64Alphabet[i] = (byte) (i - 'A");
}
for (int i = 'z"; i >= 'a"; i--) {
base64Alphabet[i] = (byte) (i - 'a" + 26);
}
for (int i = '9"; i >= '0"; i--) {
base64Alphabet[i] = (byte) (i - '0" + 52);
}
base64Alphabet['+"] = 62;
base64Alphabet['/"] = 63;
for (int i = 0; i <= 25; i++) {
lookUpBase64Alphabet[i] = (byte) ('A" + i);
}
for (int i = 26, j = 0; i <= 51; i++, j++) {
lookUpBase64Alphabet[i] = (byte) ('a" + j);
}
for (int i = 52, j = 0; i <= 61; i++, j++) {
lookUpBase64Alphabet[i] = (byte) ('0" + j);
}
lookUpBase64Alphabet[62] = (byte) '+";
lookUpBase64Alphabet[63] = (byte) '/";
if (octect == PAD) {
return true;
} else if (base64Alphabet[octect] == -1) {
return false;
} else {
return true;
}
|
|