1 package net.sf.openrocket.util;
3 import java.util.Arrays;
4 import java.util.HashMap;
9 public static final int DEFAULT_CHARS_PER_LINE = 72;
11 private static final char[] ALPHABET = new char[] {
12 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
13 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
14 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
15 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
17 private static final char PAD = '=';
19 // private static final byte[] REVERSE;
21 // REVERSE = new byte[128];
22 // Arrays.fill(REVERSE, (byte)-1);
23 // for (int i=0; i<64; i++) {
24 // REVERSE[ALPHABET[i]] = (byte)i;
31 private static final Map<Character,Integer> REVERSE = new HashMap<Character,Integer>();
33 for (int i=0; i<64; i++) {
34 REVERSE.put(ALPHABET[i], i);
42 public static String encode(byte[] data) {
43 return encode(data, DEFAULT_CHARS_PER_LINE);
46 public static String encode(byte[] data, int maxColumn) {
47 StringBuilder builder = new StringBuilder();
50 for (int position=0; position < data.length; position+=3) {
51 if (column+4 > maxColumn) {
55 builder.append(encodeGroup(data, position));
59 return builder.toString();
65 public static byte[] decode(String data) {
66 byte[] array = new byte[data.length()*3/4];
67 char[] block = new char[4];
70 for (int position=0; position < data.length(); ) {
72 for (p=0; p<4 && position < data.length(); position++) {
73 char c = data.charAt(position);
74 if (!Character.isWhitespace(c)) {
83 throw new IllegalArgumentException("Data ended when decoding Base64, data=" + data + ", p="+p);
86 int l = decodeGroup(block, array, length);
91 return Arrays.copyOf(array, length);
99 * Encode three bytes of data into four characters.
101 private static char[] encodeGroup(byte[] data, int position) {
102 char[] c = new char[] { '=','=','=','=' };
103 int b1=0, b2=0, b3=0;
104 int length = data.length - position;
110 b1 = ((int)data[position])&0xFF;
113 b2 = ((int)data[position+1])&0xFF;
116 b3 = ((int)data[position+2])&0xFF;
119 c[0] = ALPHABET[b1>>2];
120 c[1] = ALPHABET[(b1 & 3)<<4 | (b2>>4)];
123 c[2] = ALPHABET[(b2 & 15)<<2 | (b3>>6)];
126 c[3] = ALPHABET[b3 & 0x3f];
132 * Decode four chars from data into 0-3 bytes of data starting at position in array.
133 * @return the number of bytes decoded.
135 private static int decodeGroup(char[] data, byte[] array, int position) {
139 b1 = REVERSE.get(data[0]);
140 b2 = REVERSE.get(data[1]);
141 b3 = REVERSE.get(data[2]);
142 b4 = REVERSE.get(data[3]);
143 } catch (NullPointerException e) {
144 // If auto-boxing fails
145 throw new IllegalArgumentException("Illegal characters in the sequence to be "+
146 "decoded: "+Arrays.toString(data));
149 array[position] = (byte)((b1 << 2) | (b2 >> 4));
150 array[position+1] = (byte)((b2 << 4) | (b3 >> 2));
151 array[position+2] = (byte)((b3 << 6) | (b4));
153 // Check the amount of data decoded
156 if (data[1] == PAD) {
157 throw new IllegalArgumentException("Illegal character padding in sequence to be "+
158 "decoded: "+Arrays.toString(data));