KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > celtix > common > util > Base64Utility


1 package org.objectweb.celtix.common.util;
2
3 /**
4  * Base64Utility - this static class provides useful base64
5  * encoding utilities.
6  * <p>
7  * @author Darach Ennis
8  * @author Craig Ryan
9  */

10
11 // Java imports
12
import java.io.IOException JavaDoc;
13 import java.io.OutputStream JavaDoc;
14 import java.io.Writer JavaDoc;
15 import java.util.logging.Logger JavaDoc;
16
17 import org.objectweb.celtix.common.i18n.Message;
18 import org.objectweb.celtix.common.logging.LogUtils;
19
20
21 /**
22  * This class converts to/from base64. The alternative conversions include:
23  *
24  * encode:
25  * byte[] into String
26  * byte[] into char[]
27  * byte[] into OutStream
28  * byte[] into Writer
29  * decode:
30  * char[] into byte[]
31  * String into byte[]
32  * char[] into OutStream
33  * String into OutStream
34  *
35  */

36 public final class Base64Utility {
37     
38     private static final Logger JavaDoc LOG = LogUtils.getL7dLogger(Base64Utility.class);
39
40     
41     // base 64 character set
42
//
43
private static final char[] BCS = {
44         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
45         'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
46         'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
47         'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
48         'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
49         'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
50         '8', '9', '+', '/'
51     };
52
53     // base 64 wadding
54
private static final char PAD = '=';
55
56     // size of base 64 decode table
57
private static final int BDTSIZE = 128;
58
59     // base 64 decode table
60
private static final byte[] BDT = new byte[128];
61
62     
63     private static final int PAD_SIZE0 = 1;
64     private static final int PAD_SIZE4 = 2;
65     private static final int PAD_SIZE8 = 3;
66     
67     // class static intializer for building decode table
68
static {
69         for (int i = 0; i < BDTSIZE; i++) {
70             BDT[i] = Byte.MAX_VALUE;
71         }
72
73         for (int i = 0; i < BCS.length; i++) {
74             BDT[BCS[i]] = (byte)i;
75         }
76     }
77     
78     
79     private Base64Utility() {
80         //utility class, never constructed
81
}
82     
83     /**
84      * The <code>decode_chunk</code> routine decodes a chunk of data
85      * into its native encoding.
86      *
87      * base64 encodes each 3 octets of data into 4 characters from a
88      * limited 64 character set. The 3 octets are joined to form
89      * 24 bits which are then split into 4 x 6bit values. Each 6 bit
90      * value is then used as an index into the 64 character table of
91      * base64 chars. If the total data length is not a 3 octet multiple
92      * the '=' char is used as padding for the final 4 char group,
93      * either 1 octet + '==' or 2 octets + '='.
94      *
95      * @param id The input data to be processed
96      * @param o The offset from which to begin processing
97      * @param l The length (bound) at which processing is to end
98      * @return The decoded data
99      * @exception Base64Exception Thrown is processing fails due to
100      * formatting exceptions in the encoded data
101      */

102     public static byte[] decodeChunk(char[] id,
103                                      int o,
104                                      int l)
105         throws Base64Exception {
106         
107         // Keep it simple - must be >= 4 and a multiple of 4. Unpadded
108
// base64 data contain < 3 octets is invalid.
109
//
110
if (((l - o) % 4 != 0) || (l - o) < 4) {
111             return null;
112         }
113
114         char[] ib = new char[4];
115         int ibcount = 0;
116
117         // cryan. Calc the num of octets. Each 4 chars of base64 chars
118
// (representing 24 bits) encodes 3 octets.
119
//
120
int octetCount = 3 * (l / 4);
121
122         // Final 4 chars may contain 3 octets or padded to contain
123
// 1 or 2 octets.
124
//
125
if (id[l - 1] == PAD) {
126             // TT== means last 4 chars encode 8 bits (ie subtract 2)
127
// TTT= means last 4 chars encode 16 bits (ie subtract 1)
128
octetCount -= (id[l - 2] == PAD) ? 2 : 1;
129         }
130
131         byte[] ob = new byte[octetCount];
132         int obcount = 0;
133
134         for (int i = o; i < o + l && i < id.length; i++) {
135             if (id[i] == PAD
136                 || id[i] < BDT.length
137                 && BDT[id[i]] != Byte.MAX_VALUE) {
138                 
139                 ib[ibcount++] = id[i];
140
141                 // Decode each 4 char sequence.
142
//
143
if (ibcount == ib.length) {
144                     ibcount = 0;
145                     obcount += processEncodeme(ib, ob, obcount);
146                 }
147             }
148         }
149
150         return ob;
151     }
152
153     public static byte[] decode(String JavaDoc id) throws Base64Exception {
154         char[] cd = id.toCharArray();
155         return decodeChunk(cd, 0, cd.length);
156     }
157
158     public static void decode(char[] id,
159                              int o,
160                              int l,
161                              OutputStream JavaDoc ostream)
162         throws Base64Exception {
163
164         try {
165             ostream.write(decodeChunk(id, o, l));
166         } catch (IOException JavaDoc e) {
167             // convert exception to Base64Exception
168
throw new Base64Exception(new Message("BASE64_RUNTIME_EXCEPTION", LOG), e);
169         }
170     }
171
172     public static void decode(String JavaDoc id,
173                               OutputStream JavaDoc ostream)
174         throws Base64Exception {
175         
176         try {
177             char[] cd = id.toCharArray();
178             ostream.write(decodeChunk(cd, 0, cd.length));
179         } catch (IOException JavaDoc e) {
180             throw new Base64Exception(new Message("BASE64_DECODE_IOEXCEPTION", LOG), e);
181         }
182     }
183
184     // Returns base64 representation of specified byte array.
185
//
186
public static String JavaDoc encode(byte[] id) {
187         char[] cd = encodeChunk(id, 0, id.length);
188         return new String JavaDoc(cd, 0, cd.length);
189     }
190
191     // Returns base64 representation of specified byte array.
192
//
193
public static char[] encodeChunk(byte[] id,
194                                      int o,
195                                      int l) {
196         if (l <= 0) {
197             return null;
198         }
199
200         char[] out;
201
202         // If not a multiple of 3 octets then a final padded 4 char
203
// slot is needed.
204
//
205
if ((l - o) % 3 == 0) {
206             out = new char[l / 3 * 4];
207         } else {
208             out = new char[l / 3 * 4 + 4];
209         }
210
211         int rindex = o;
212         int windex = 0;
213         int rest = l - o;
214
215         while (rest >= 3) {
216             int i = ((id[rindex] & 0xff) << 16)
217                     + ((id[rindex + 1] & 0xff) << 8)
218                     + (id[rindex + 2] & 0xff);
219
220             out[windex++] = BCS[i >> 18];
221             out[windex++] = BCS[(i >> 12) & 0x3f];
222             out[windex++] = BCS[(i >> 6) & 0x3f];
223             out[windex++] = BCS[i & 0x3f];
224             rindex += 3;
225             rest -= 3;
226         }
227
228         if (rest == 1) {
229             int i = id[rindex] & 0xff;
230             out[windex++] = BCS[i >> 2];
231             out[windex++] = BCS[(i << 4) & 0x3f];
232             out[windex++] = PAD;
233             out[windex++] = PAD;
234         } else if (rest == 2) {
235             int i = ((id[rindex] & 0xff) << 8) + (id[rindex + 1] & 0xff);
236             out[windex++] = BCS[i >> 10];
237             out[windex++] = BCS[(i >> 4) & 0x3f];
238             out[windex++] = BCS[(i << 2) & 0x3f];
239             out[windex++] = PAD;
240         }
241         return out;
242     }
243
244     //
245
// Outputs base64 representation of the specified byte array
246
// to a byte stream.
247
//
248
public static void encodeChunk(byte[] id,
249                                    int o,
250                                    int l,
251                                    OutputStream JavaDoc ostream) throws Base64Exception {
252         try {
253             ostream.write(new String JavaDoc(encodeChunk(id, o, l)).getBytes());
254         } catch (IOException JavaDoc e) {
255             throw new Base64Exception(new Message("BASE64_ENCODE_IOEXCEPTION", LOG), e);
256         }
257     }
258
259
260     // Outputs base64 representation of the specified byte
261
// array to a character stream.
262
//
263
public static void encode(byte[] id,
264                               int o,
265                               int l,
266                               Writer JavaDoc writer) throws Base64Exception {
267         try {
268             writer.write(encodeChunk(id, o, l));
269         } catch (IOException JavaDoc e) {
270             throw new Base64Exception(new Message("BASE64_ENCODE_WRITER_IOEXCEPTION", LOG), e);
271         }
272     }
273
274
275     //---- Private static methods --------------------------------------
276

277     /**
278      * The <code>process</code> routine processes an atomic base64
279      * unit of encoding (encodeme) into its native encoding. This class is
280      * used by decode routines to do the grunt work of decoding
281      * base64 encoded information
282      *
283      * @param ib Input character buffer of encoded bytes
284      * @param ob Output byte buffer of decoded bytes
285      * @param p Pointer to the encodeme of interest
286      * @return The decoded encodeme
287      * @exception Base64Exception Thrown is processing fails due to
288      * formatting exceptions in the encoded data
289      */

290     private static int processEncodeme(char[] ib,
291                                        byte[] ob,
292                                        int p)
293         throws Base64Exception {
294         
295
296         int spad = PAD_SIZE8;
297         if (ib[3] == PAD) {
298             spad = PAD_SIZE4;
299         }
300         if (ib[2] == PAD) {
301             spad = PAD_SIZE0;
302         }
303
304         int b0 = BDT[ib[0]];
305         int b1 = BDT[ib[1]];
306         int b2 = BDT[ib[2]];
307         int b3 = BDT[ib[3]];
308
309         switch (spad) {
310         case PAD_SIZE0:
311             ob[p] = (byte)(b0 << 2 & 0xfc | b1 >> 4 & 0x3);
312             return PAD_SIZE0;
313         case PAD_SIZE4:
314             ob[p++] = (byte)(b0 << 2 & 0xfc | b1 >> 4 & 0x3);
315             ob[p] = (byte)(b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
316             return PAD_SIZE4;
317         case PAD_SIZE8:
318             ob[p++] = (byte)(b0 << 2 & 0xfc | b1 >> 4 & 0x3);
319             ob[p++] = (byte)(b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
320             ob[p] = (byte)(b2 << 6 & 0xc0 | b3 & 0x3f);
321             return PAD_SIZE8;
322         default:
323             // We should never get here
324
throw new IllegalStateException JavaDoc();
325         }
326     }
327
328 }
329
Popular Tags