KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > thoughtworks > xstream > core > util > Base64Encoder


1 package com.thoughtworks.xstream.core.util;
2
3 import java.io.ByteArrayOutputStream JavaDoc;
4 import java.io.IOException JavaDoc;
5 import java.io.Reader JavaDoc;
6 import java.io.StringReader JavaDoc;
7
8 /**
9  * Encodes binary data to plain text as Base64.
10  *
11  * <p>Despite there being a gazillion other Base64 implementations out there, this has been written as part of XStream as
12  * it forms a core part but is too trivial to warrant an extra dependency.</p>
13  *
14  * <p>This meets the standard as described in RFC 1521, section 5.2 <http://www.freesoft.org/CIE/RFC/1521/7.htm>, allowing
15  * other Base64 tools to manipulate the data.</p>
16  *
17  * @author Joe Walnes
18  */

19 public class Base64Encoder {
20
21     // Here's how encoding works:
22
//
23
// 1) Incoming bytes are broken up into groups of 3 (each byte having 8 bits).
24
//
25
// 2) The combined 24 bits (3 * 8) are split into 4 groups of 6 bits.
26
//
27
// input |------||------||------| (3 values each with 8 bits)
28
// 101010101010101010101010
29
// output |----||----||----||----| (4 values each with 6 bits)
30
//
31
// 3) Each of these 4 groups of 6 bits are converted back to a number, which will fall in the range of 0 - 63.
32
//
33
// 4) Each of these 4 numbers are converted to an alphanumeric char in a specified mapping table, to create
34
// a 4 character string.
35
//
36
// 5) This is repeated for all groups of three bytes.
37
//
38
// 6) Special padding is done at the end of the stream using the '=' char.
39

40     private static final char[] SIXTY_FOUR_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
41     private static final int[] REVERSE_MAPPING = new int[123];
42
43     static {
44         for (int i = 0; i < SIXTY_FOUR_CHARS.length; i++) REVERSE_MAPPING[SIXTY_FOUR_CHARS[i]] = i + 1;
45     }
46
47     public String JavaDoc encode(byte[] input) {
48         StringBuffer JavaDoc result = new StringBuffer JavaDoc();
49         int outputCharCount = 0;
50         for (int i = 0; i < input.length; i += 3) {
51             int remaining = Math.min(3, input.length - i);
52             int oneBigNumber = (input[i] & 0xff) << 16 | (remaining <= 1 ? 0 : input[i + 1] & 0xff) << 8 | (remaining <= 2 ? 0 : input[i + 2] & 0xff);
53             for (int j = 0; j < 4; j++) result.append(remaining + 1 > j ? SIXTY_FOUR_CHARS[0x3f & oneBigNumber >> 6 * (3 - j)] : '=');
54             if ((outputCharCount += 4) % 76 == 0) result.append('\n');
55         }
56         return result.toString();
57     }
58
59     public byte[] decode(String JavaDoc input) {
60         try {
61             ByteArrayOutputStream JavaDoc out = new ByteArrayOutputStream JavaDoc();
62             StringReader JavaDoc in = new StringReader JavaDoc(input);
63             for (int i = 0; i < input.length(); i += 4) {
64                 int a[] = {mapCharToInt(in), mapCharToInt(in), mapCharToInt(in), mapCharToInt(in)};
65                 int oneBigNumber = (a[0] & 0x3f) << 18 | (a[1] & 0x3f) << 12 | (a[2] & 0x3f) << 6 | (a[3] & 0x3f);
66                 for (int j = 0; j < 3; j++) if (a[j + 1] >= 0) out.write(0xff & oneBigNumber >> 8 * (2 - j));
67             }
68             return out.toByteArray();
69         } catch (IOException JavaDoc e) {
70             throw new Error JavaDoc(e + ": " + e.getMessage());
71         }
72     }
73
74     private int mapCharToInt(Reader JavaDoc input) throws IOException JavaDoc {
75         int c;
76         while ((c = input.read()) != -1) {
77             int result = REVERSE_MAPPING[c];
78             if (result != 0) return result -1;
79             if (c == '=') return -1;
80         }
81         return -1;
82     }
83 }
84
Popular Tags