35fd3b95af9938763e7f1042e19a0b8626f4b710
[org.ibex.util.git] / src / org / ibex / util / Base64.java
1 package org.ibex.util;
2
3 public class Base64 {
4
5     private static final byte[] encodingTable = {
6         (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
7         (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
8         (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
9         (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
10         (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
11         (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
12         (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
13         (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', (byte)'0', (byte)'1',
14         (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8',
15         (byte)'9', (byte)'+', (byte)'/'
16     };
17
18     // FIXME could be far more efficient
19     public static class InputStream extends java.io.ByteArrayInputStream {
20         public InputStream(String s) { super(decode(s.getBytes())); }
21     }
22
23     /**
24      * encode the input data producong a base 64 encoded byte array.
25      *
26      * @return a byte array containing the base 64 encoded data.
27      */
28     public static byte[] encode(byte[]  data) {
29         byte[]  bytes;
30                 
31         int modulus = data.length % 3;
32         if (modulus == 0) {
33             bytes = new byte[4 * data.length / 3];
34         } else {
35             bytes = new byte[4 * ((data.length / 3) + 1)];
36         }
37
38         int dataLength = (data.length - modulus);
39         int a1, a2, a3;
40         for (int i = 0, j = 0; i < dataLength; i += 3, j += 4) {
41             a1 = data[i] & 0xff;
42             a2 = data[i + 1] & 0xff;
43             a3 = data[i + 2] & 0xff;
44             
45             bytes[j] = encodingTable[(a1 >>> 2) & 0x3f];
46             bytes[j + 1] = encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f];
47             bytes[j + 2] = encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f];
48             bytes[j + 3] = encodingTable[a3 & 0x3f];
49         }
50
51         int     b1, b2, b3;
52         int     d1, d2;
53
54         switch (modulus) {
55                 case 0:         /* nothing left to do */
56                     break;
57                 case 1:
58                     d1 = data[data.length - 1] & 0xff;
59                     b1 = (d1 >>> 2) & 0x3f;
60                     b2 = (d1 << 4) & 0x3f;
61
62                     bytes[bytes.length - 4] = encodingTable[b1];
63                     bytes[bytes.length - 3] = encodingTable[b2];
64                     bytes[bytes.length - 2] = (byte)'=';
65                     bytes[bytes.length - 1] = (byte)'=';
66                     break;
67                 case 2:
68                     d1 = data[data.length - 2] & 0xff;
69                     d2 = data[data.length - 1] & 0xff;
70
71                     b1 = (d1 >>> 2) & 0x3f;
72                     b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
73                     b3 = (d2 << 2) & 0x3f;
74
75                     bytes[bytes.length - 4] = encodingTable[b1];
76                     bytes[bytes.length - 3] = encodingTable[b2];
77                     bytes[bytes.length - 2] = encodingTable[b3];
78                     bytes[bytes.length - 1] = (byte)'=';
79                     break;
80             }
81
82         return bytes;
83     }
84
85     private static final byte[] decodingTable;
86
87     static {
88         decodingTable = new byte[128];
89         for (int i = 'A'; i <= 'Z'; i++) decodingTable[i] = (byte)(i - 'A');
90         for (int i = 'a'; i <= 'z'; i++) decodingTable[i] = (byte)(i - 'a' + 26);
91         for (int i = '0'; i <= '9'; i++) decodingTable[i] = (byte)(i - '0' + 52);
92         decodingTable['+'] = 62;
93         decodingTable['/'] = 63;
94     }
95
96     /**
97      * decode the base 64 encoded input data.
98      *
99      * @return a byte array representing the decoded data.
100      */
101     public static byte[] decode(byte[]  data) {
102         byte[]  bytes;
103         byte    b1, b2, b3, b4;
104
105         if (data[data.length - 2] == '=') bytes = new byte[(((data.length / 4) - 1) * 3) + 1];
106         else if (data[data.length - 1] == '=') bytes = new byte[(((data.length / 4) - 1) * 3) + 2];
107         else bytes = new byte[((data.length / 4) * 3)];
108
109         for (int i = 0, j = 0; i < data.length - 4; i += 4, j += 3) {
110             b1 = decodingTable[data[i]];
111             b2 = decodingTable[data[i + 1]];
112             b3 = decodingTable[data[i + 2]];
113             b4 = decodingTable[data[i + 3]];
114             
115             bytes[j] = (byte)((b1 << 2) | (b2 >> 4));
116             bytes[j + 1] = (byte)((b2 << 4) | (b3 >> 2));
117             bytes[j + 2] = (byte)((b3 << 6) | b4);
118         }
119
120         if (data[data.length - 2] == '=') {
121             b1 = decodingTable[data[data.length - 4]];
122             b2 = decodingTable[data[data.length - 3]];
123             bytes[bytes.length - 1] = (byte)((b1 << 2) | (b2 >> 4));
124         } else if (data[data.length - 1] == '=') {
125             b1 = decodingTable[data[data.length - 4]];
126             b2 = decodingTable[data[data.length - 3]];
127             b3 = decodingTable[data[data.length - 2]];
128             bytes[bytes.length - 2] = (byte)((b1 << 2) | (b2 >> 4));
129             bytes[bytes.length - 1] = (byte)((b2 << 4) | (b3 >> 2));
130         } else {
131             b1 = decodingTable[data[data.length - 4]];
132             b2 = decodingTable[data[data.length - 3]];
133             b3 = decodingTable[data[data.length - 2]];
134             b4 = decodingTable[data[data.length - 1]];
135             bytes[bytes.length - 3] = (byte)((b1 << 2) | (b2 >> 4));
136             bytes[bytes.length - 2] = (byte)((b2 << 4) | (b3 >> 2));
137             bytes[bytes.length - 1] = (byte)((b3 << 6) | b4);
138         }
139         return bytes;
140     }
141
142     /**
143      * decode the base 64 encoded String data.
144      *
145      * @return a byte array representing the decoded data.
146      */
147     public static byte[] decode(String  data) {
148         byte[]  bytes;
149         byte    b1, b2, b3, b4;
150
151         if (data.charAt(data.length() - 2) == '=')
152             bytes = new byte[(((data.length() / 4) - 1) * 3) + 1];
153         else if (data.charAt(data.length() - 1) == '=')
154             bytes = new byte[(((data.length() / 4) - 1) * 3) + 2];
155         else
156             bytes = new byte[((data.length() / 4) * 3)];
157
158         for (int i = 0, j = 0; i < data.length() - 4; i += 4, j += 3) {
159             b1 = decodingTable[data.charAt(i)];
160             b2 = decodingTable[data.charAt(i + 1)];
161             b3 = decodingTable[data.charAt(i + 2)];
162             b4 = decodingTable[data.charAt(i + 3)];
163             
164             bytes[j] = (byte)((b1 << 2) | (b2 >> 4));
165             bytes[j + 1] = (byte)((b2 << 4) | (b3 >> 2));
166             bytes[j + 2] = (byte)((b3 << 6) | b4);
167         }
168
169         if (data.charAt(data.length() - 2) == '=') {
170             b1 = decodingTable[data.charAt(data.length() - 4)];
171             b2 = decodingTable[data.charAt(data.length() - 3)];
172             bytes[bytes.length - 1] = (byte)((b1 << 2) | (b2 >> 4));
173         } else if (data.charAt(data.length() - 1) == '=') {
174             b1 = decodingTable[data.charAt(data.length() - 4)];
175             b2 = decodingTable[data.charAt(data.length() - 3)];
176             b3 = decodingTable[data.charAt(data.length() - 2)];
177             bytes[bytes.length - 2] = (byte)((b1 << 2) | (b2 >> 4));
178             bytes[bytes.length - 1] = (byte)((b2 << 4) | (b3 >> 2));
179         } else {
180             b1 = decodingTable[data.charAt(data.length() - 4)];
181             b2 = decodingTable[data.charAt(data.length() - 3)];
182             b3 = decodingTable[data.charAt(data.length() - 2)];
183             b4 = decodingTable[data.charAt(data.length() - 1)];
184             bytes[bytes.length - 3] = (byte)((b1 << 2) | (b2 >> 4));
185             bytes[bytes.length - 2] = (byte)((b2 << 4) | (b3 >> 2));
186             bytes[bytes.length - 1] = (byte)((b3 << 6) | b4);
187         }
188         return bytes;
189     }
190 }