• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package de.timroes.base64;
2 
3 import java.util.HashMap;
4 
5 /**
6  * A Base64 en/decoder. You can use it to encode and decode strings and byte arrays.
7  *
8  * @author Tim Roes
9  */
10 public class Base64 {
11 
12 	private static final char[] code = ("=ABCDEFGHIJKLMNOPQRSTUVWXYZ"
13 			+ "abcdefghijklmnopqrstuvwxyz0123456789+/").toCharArray();
14 
15 	private static final HashMap<Character,Byte> map = new HashMap<Character, Byte>();
16 
Base64()17 	private Base64() {}
18 
19 	static {
20 		for(int i = 0; i < code.length; i++) {
map.put(code[i], (byte)i)21 			map.put(code[i], (byte)i);
22 		}
23 	}
24 
25 	/**
26 	 * Decode a base64 encoded string to a byte array.
27 	 *
28 	 * @param in A string representing a base64 encoding.
29 	 * @return The decoded byte array.
30 	 */
decode(String in)31 	public static byte[] decode(String in) {
32 
33 		in = in.replaceAll("\\r|\\n","");
34 		if(in.length() % 4 != 0) {
35 			throw new IllegalArgumentException("The length of the input string must be a multiple of four.");
36 		}
37 
38 		if(!in.matches("^[A-Za-z0-9+/]*[=]{0,3}$")) {
39 			throw new IllegalArgumentException("The argument contains illegal characters.");
40 		}
41 
42 		byte[] out = new byte[(in.length()*3)/4];
43 
44 		char[] input = in.toCharArray();
45 
46 		int outi = 0;
47 		int b1, b2, b3, b4;
48 		for(int i = 0; i < input.length; i+=4) {
49 			b1 = map.get(input[i]) - 1;
50 			b2 = map.get(input[i+1]) - 1;
51 			b3 = map.get(input[i+2]) - 1;
52 			b4 = map.get(input[i+3]) - 1;
53 			out[outi++] = (byte)(b1 << 2 | b2 >>> 4);
54 			out[outi++] = (byte)((b2 & 0x0F) << 4 | b3 >>> 2);
55 			out[outi++] = (byte)((b3 & 0x03) << 6 | (b4 & 0x3F));
56 		}
57 
58 		if(in.endsWith("=")) {
59 			byte[] trimmed = new byte[out.length - (in.length() - in.indexOf("="))];
60 			System.arraycopy(out, 0, trimmed, 0, trimmed.length);
61 			return trimmed;
62 		}
63 
64 		return out;
65 
66 	}
67 
68 	/**
69 	 * Decode a base64 encoded string to a string.
70 	 *
71 	 * @param in The string representation of the base64 encoding.
72 	 * @return The decoded string in the default charset of the JVM.
73 	 */
decodeAsString(String in)74 	public static String decodeAsString(String in) {
75 		return new String(decode(in));
76 	}
77 
78 	/**
79 	 * Encode a String and return the encoded string.
80 	 *
81 	 * @param in A string to encode.
82 	 * @return The encoded byte array.
83 	 */
encode(String in)84 	public static String encode(String in) {
85 		return encode(in.getBytes());
86 	}
87 
88 	/**
89 	 * Encode a Byte array and return the encoded string.
90 	 *
91 	 * @param in A string to encode.
92 	 * @return The encoded byte array.
93 	 */
encode(Byte[] in)94 	public static String encode(Byte[] in) {
95 		byte[] tmp = new byte[in.length];
96 		for(int i = 0; i < tmp.length; i++) {
97 			tmp[i] = in[i];
98 		}
99 		return encode(tmp);
100 	}
101 
102 	/**
103 	 * Encode a byte array and return the encoded string.
104 	 *
105 	 * @param in A string to encode.
106 	 * @return The encoded byte array.
107 	 */
encode(byte[] in)108 	public static String encode(byte[] in) {
109 		StringBuilder builder = new StringBuilder(4 * ((in.length+2)/3));
110 		byte[] encoded = encodeAsBytes(in);
111 		for(int i = 0; i < encoded.length; i++) {
112 			builder.append(code[encoded[i]+1]);
113 			if(i % 72 == 71)
114 				builder.append("\n");
115 		}
116 		return builder.toString();
117 	}
118 
119 	/**
120 	 * Encode a String and return the encoded byte array. Bytes that has been
121 	 * appended to pad the string to a multiple of four are set to -1 in the array.
122 	 *
123 	 * @param in A string to encode.
124 	 * @return The encoded byte array.
125 	 */
encodeAsBytes(String in)126 	public static byte[] encodeAsBytes(String in) {
127 		return encodeAsBytes(in.getBytes());
128 	}
129 
130 	/**
131 	 * Encode a byte array and return the encoded byte array. Bytes that has been
132 	 * appended to pad the string to a multiple of four are set to -1 in the array.
133 	 *
134 	 * @param inArray A string to encode.
135 	 * @return The encoded byte array.
136 	 */
encodeAsBytes(byte[] inArray)137 	public static byte[] encodeAsBytes(byte[] inArray) {
138 
139 		// Output string must be 4 * floor((n+2)/3) large
140 		byte[] out = new byte[4 * ((inArray.length+2)/3)];
141 		// Create padded input array with the next largest length that is a multiple of 3
142 		byte[] in = new byte[(inArray.length+2)/3*3];
143 		// Copy content form unpadded to padded array
144 		System.arraycopy(inArray, 0, in, 0, inArray.length);
145 
146 		int outi = 0;
147 		for(int i = 0; i < in.length; i+=3) {
148 
149 			out[outi++] = (byte)((in[i] & 0xFF) >>> 2);
150 			out[outi++] = (byte)(((in[i] & 0x03) << 4) | ((in[i+1] & 0xFF) >>> 4));
151 			out[outi++] = (byte)(((in[i+1] & 0x0F) << 2) | ((in[i+2] & 0xFF) >>> 6));
152 			out[outi++] = (byte)(in[i+2] & 0x3F);
153 
154 		}
155 
156 		for(int i = in.length - inArray.length; i > 0; i--) {
157 			out[out.length - i] = -1;
158 		}
159 
160 		return out;
161 	}
162 
163 }