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 }