001: package uk.org.ponder.stringutil;
002:
003: /** A utility class to decode Base64-encoded character strings back into
004: * byte arrays.
005: */
006:
007: public class CharToByteBase64 {
008:
009: public final static byte pem_reverse_array[] = new byte[256];
010:
011: static {
012: for (int i = 0; i < 255; i++) {
013: pem_reverse_array[i] = -1;
014: }
015: for (int i = 0; i < ByteToCharBase64.pem_array.length; i++) {
016: pem_reverse_array[ByteToCharBase64.pem_array[i]] = (byte) i;
017: }
018: }
019:
020: /**
021: * Decode an input array of chars into an output array of bytes. This method is
022: * more inefficient than the 5-parameter version below since a new byte output
023: * array is allocated and returned with each call.
024: * @param inarray An character array holding the data to be converted from
025: * Base64 to bytes.
026: * @param instart The start position of the character data to be converted.
027: * @param inlength The length of the character data to be converted.
028: * @return A byte array holding the decoded bytes.
029: */
030:
031: // for example, (11 + 1) * 3 = 36 -> 9??
032: public static byte[] decode(char[] inarray, int instart,
033: int inlength) {
034: // 3 6 9 12 15 18 21 24
035: // 1->1 2->2 3->3 4->3 5->4 6->5 7->6 8->6
036: byte[] sufficientbuffer = new byte[((inlength + 1) * 3) / 4];
037: decode(inarray, instart, inlength, sufficientbuffer, 0);
038: return sufficientbuffer;
039: }
040:
041: /**
042: * Decode an input array of chars into an output array of bytes.
043: * @param inarray An character array holding the data to be converted from
044: * Base64 to bytes.
045: * @param instart The start position of the character data to be converted.
046: * @param inlength The length of the character data to be converted.
047: * @param outarray A byte array to receive the decoded character data.
048: * @param outstart The position within the byte array to start writing the
049: * decoded data.
050: * @return The number of bytes that were decoded and written to the supplied
051: * byte array.
052: */
053: public static int decode(char[] inarray, int instart, int inlength,
054: byte[] outarray, int outstart) {
055: int decodestop;
056: for (decodestop = 0; decodestop < inlength; ++decodestop) {
057: System.out.print("char: " + inarray[decodestop + instart]
058: + " ");
059: if (pem_reverse_array[(byte) (inarray[decodestop + instart])] == -1)
060: break;
061: }
062: int outpos = outstart;
063: while (decodestop > 0) {
064: // int bytestogo = decodestop * 3 / 4;
065: int rem = ((decodestop - 1) % 4) + 1; // 4->4, 5->1
066: int virtualstart = instart + (rem - 4); // 4->0, 3->-1, 2->-2, 1->-3
067: int a = 0, b = 0, c = 0, d = 0;
068:
069: switch (rem) {
070: // first set of masks to convert from char to index
071: // second set to avoid sign-extension
072: case 4:
073: // a b c d
074: // 000000 001111 111122 222222
075: a = pem_reverse_array[inarray[virtualstart] & 0xff] & 0xff;
076: // NOBREAK
077: case 3:
078: // b c d
079: // 001111 111122 222222
080: b = pem_reverse_array[inarray[virtualstart + 1] & 0xff] & 0xff;
081: // nb sign bit of b & c will be 0, so no problem with right shift
082: outarray[outpos++] = (byte) ((a << 2) + (b >> 4));
083: // NOBREAK
084: case 2:
085: // c d
086: // 111122 222222
087: c = pem_reverse_array[inarray[virtualstart + 2] & 0xff] & 0xff;
088: outarray[outpos++] = (byte) ((b << 4) + (c >> 2));
089: case 1:
090: // d
091: // 222222
092: d = pem_reverse_array[inarray[virtualstart + 3] & 0xff] & 0xff;
093: outarray[outpos++] = (byte) ((c << 6) + d);
094: break;
095: }
096: System.out.println("a " + a + " b " + b + " c " + c + " d "
097: + d);
098: instart += rem;
099: decodestop -= rem; // should make rem 4 on all subsequent times until 0.
100: }
101: return outpos - outstart;
102: }
103: }
|