1 //Copyright 2003-2010 Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland 2 // www.source-code.biz, www.inventec.ch/chdh 3 // 4 // This module is multi-licensed and may be used under the terms 5 // of any of the following licenses: 6 // 7 // EPL, Eclipse Public License, V1.0 or later, http://www.eclipse.org/legal 8 // LGPL, GNU Lesser General Public License, V2.1 or later, http://www.gnu.org/licenses/lgpl.html 9 // GPL, GNU General Public License, V2 or later, http://www.gnu.org/licenses/gpl.html 10 // AL, Apache License, V2.0 or later, http://www.apache.org/licenses 11 // BSD, BSD License, http://www.opensource.org/licenses/bsd-license.php 12 // 13 // Please contact the author if you need another license. 14 // This module is provided "as is", without warranties of any kind. 15 /** 16 * A Base64 encoder/decoder. 17 * 18 * <p> 19 * This class is used to encode and decode data in Base64 format as described in RFC 1521. 20 * 21 * <p> 22 * Project home page: <a href="http://www.source-code.biz/base64coder/java/">www.source-code.biz/base64coder/java</a><br> 23 * Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland<br> 24 * Multi-licensed: EPL / LGPL / GPL / AL / BSD. 25 * 26 * @author Christian d'Heureuse 27 * @author vaxquis 28 */ 29 30 package com.badlogic.gdx.utils; 31 32 public class Base64Coder { 33 public static class CharMap { 34 protected final char[] encodingMap = new char[64]; 35 protected final byte[] decodingMap = new byte[128]; 36 37 public CharMap (char char63, char char64) { 38 int i = 0; 39 for (char c = 'A'; c <= 'Z'; c++) { 40 encodingMap[i++] = c; 41 } 42 for (char c = 'a'; c <= 'z'; c++) { 43 encodingMap[i++] = c; 44 } 45 for (char c = '0'; c <= '9'; c++) { 46 encodingMap[i++] = c; 47 } 48 encodingMap[i++] = char63; 49 encodingMap[i++] = char64; 50 for (i = 0; i < decodingMap.length; i++) { 51 decodingMap[i] = -1; 52 } 53 for (i = 0; i < 64; i++) { 54 decodingMap[encodingMap[i]] = (byte)i; 55 } 56 } 57 58 public byte[] getDecodingMap () { 59 return decodingMap; 60 } 61 62 public char[] getEncodingMap () { 63 return encodingMap; 64 } 65 } 66 67 // The line separator string of the operating system. 68 private static final String systemLineSeparator = "\n"; 69 70 public static final CharMap regularMap = new CharMap('+', '/'), urlsafeMap = new CharMap('-', '_'); 71 72 /** Encodes a string into Base64 format. No blanks or line breaks are inserted. 73 * @param s A String to be encoded. 74 * @return A String containing the Base64 encoded data. */ 75 public static String encodeString (String s) { 76 return encodeString(s, false); 77 } 78 79 public static String encodeString (String s, boolean useUrlsafeEncoding) { 80 return new String(encode(s.getBytes(), useUrlsafeEncoding ? urlsafeMap.encodingMap : regularMap.encodingMap)); 81 } 82 83 /** Encodes a byte array into Base 64 format and breaks the output into lines of 76 characters. This method is compatible with 84 * <code>sun.misc.BASE64Encoder.encodeBuffer(byte[])</code>. 85 * @param in An array containing the data bytes to be encoded. 86 * @return A String containing the Base64 encoded data, broken into lines. */ 87 public static String encodeLines (byte[] in) { 88 return encodeLines(in, 0, in.length, 76, systemLineSeparator, regularMap.encodingMap); 89 } 90 91 public static String encodeLines (byte[] in, int iOff, int iLen, int lineLen, String lineSeparator, CharMap charMap) { 92 return encodeLines(in, iOff, iLen, lineLen, lineSeparator, charMap.encodingMap); 93 } 94 95 /** Encodes a byte array into Base 64 format and breaks the output into lines. 96 * @param in An array containing the data bytes to be encoded. 97 * @param iOff Offset of the first byte in <code>in</code> to be processed. 98 * @param iLen Number of bytes to be processed in <code>in</code>, starting at <code>iOff</code>. 99 * @param lineLen Line length for the output data. Should be a multiple of 4. 100 * @param lineSeparator The line separator to be used to separate the output lines. 101 * @param charMap char map to use 102 * @return A String containing the Base64 encoded data, broken into lines. */ 103 public static String encodeLines (byte[] in, int iOff, int iLen, int lineLen, String lineSeparator, char[] charMap) { 104 int blockLen = (lineLen * 3) / 4; 105 if (blockLen <= 0) { 106 throw new IllegalArgumentException(); 107 } 108 int lines = (iLen + blockLen - 1) / blockLen; 109 int bufLen = ((iLen + 2) / 3) * 4 + lines * lineSeparator.length(); 110 StringBuilder buf = new StringBuilder(bufLen); 111 int ip = 0; 112 while (ip < iLen) { 113 int l = Math.min(iLen - ip, blockLen); 114 buf.append(encode(in, iOff + ip, l, charMap)); 115 buf.append(lineSeparator); 116 ip += l; 117 } 118 return buf.toString(); 119 } 120 121 /** Encodes a byte array into Base64 format. No blanks or line breaks are inserted in the output. 122 * @param in An array containing the data bytes to be encoded. 123 * @return A character array containing the Base64 encoded data. */ 124 public static char[] encode (byte[] in) { 125 return encode(in, regularMap.encodingMap); 126 } 127 128 public static char[] encode (byte[] in, CharMap charMap) { 129 return encode(in, 0, in.length, charMap); 130 } 131 132 public static char[] encode (byte[] in, char[] charMap) { 133 return encode(in, 0, in.length, charMap); 134 } 135 136 /** Encodes a byte array into Base64 format. No blanks or line breaks are inserted in the output. 137 * @param in An array containing the data bytes to be encoded. 138 * @param iLen Number of bytes to process in <code>in</code>. 139 * @return A character array containing the Base64 encoded data. */ 140 public static char[] encode (byte[] in, int iLen) { 141 return encode(in, 0, iLen, regularMap.encodingMap); 142 } 143 144 public static char[] encode (byte[] in, int iOff, int iLen, CharMap charMap) { 145 return encode(in, iOff, iLen, charMap.encodingMap); 146 } 147 148 /** Encodes a byte array into Base64 format. No blanks or line breaks are inserted in the output. 149 * @param in An array containing the data bytes to be encoded. 150 * @param iOff Offset of the first byte in <code>in</code> to be processed. 151 * @param iLen Number of bytes to process in <code>in</code>, starting at <code>iOff</code>. 152 * @param charMap char map to use 153 * @return A character array containing the Base64 encoded data. */ 154 public static char[] encode (byte[] in, int iOff, int iLen, char[] charMap) { 155 int oDataLen = (iLen * 4 + 2) / 3; // output length without padding 156 int oLen = ((iLen + 2) / 3) * 4; // output length including padding 157 char[] out = new char[oLen]; 158 int ip = iOff; 159 int iEnd = iOff + iLen; 160 int op = 0; 161 while (ip < iEnd) { 162 int i0 = in[ip++] & 0xff; 163 int i1 = ip < iEnd ? in[ip++] & 0xff : 0; 164 int i2 = ip < iEnd ? in[ip++] & 0xff : 0; 165 int o0 = i0 >>> 2; 166 int o1 = ((i0 & 3) << 4) | (i1 >>> 4); 167 int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6); 168 int o3 = i2 & 0x3F; 169 out[op++] = charMap[o0]; 170 out[op++] = charMap[o1]; 171 out[op] = op < oDataLen ? charMap[o2] : '='; 172 op++; 173 out[op] = op < oDataLen ? charMap[o3] : '='; 174 op++; 175 } 176 return out; 177 } 178 179 /** Decodes a string from Base64 format. No blanks or line breaks are allowed within the Base64 encoded input data. 180 * @param s A Base64 String to be decoded. 181 * @return A String containing the decoded data. 182 * @throws IllegalArgumentException If the input is not valid Base64 encoded data. */ 183 public static String decodeString (String s) { 184 return decodeString(s, false); 185 } 186 187 public static String decodeString (String s, boolean useUrlSafeEncoding) { 188 return new String(decode(s.toCharArray(), useUrlSafeEncoding ? urlsafeMap.decodingMap : regularMap.decodingMap)); 189 } 190 191 public static byte[] decodeLines (String s) { 192 return decodeLines(s, regularMap.decodingMap); 193 } 194 195 public static byte[] decodeLines (String s, CharMap inverseCharMap) { 196 return decodeLines(s, inverseCharMap.decodingMap); 197 } 198 199 /** Decodes a byte array from Base64 format and ignores line separators, tabs and blanks. CR, LF, Tab and Space characters are 200 * ignored in the input data. This method is compatible with <code>sun.misc.BASE64Decoder.decodeBuffer(String)</code>. 201 * @param s A Base64 String to be decoded. 202 * @param inverseCharMap 203 * @return An array containing the decoded data bytes. 204 * @throws IllegalArgumentException If the input is not valid Base64 encoded data. */ 205 public static byte[] decodeLines (String s, byte[] inverseCharMap) { 206 char[] buf = new char[s.length()]; 207 int p = 0; 208 for (int ip = 0; ip < s.length(); ip++) { 209 char c = s.charAt(ip); 210 if (c != ' ' && c != '\r' && c != '\n' && c != '\t') { 211 buf[p++] = c; 212 } 213 } 214 return decode(buf, 0, p, inverseCharMap); 215 } 216 217 /** Decodes a byte array from Base64 format. No blanks or line breaks are allowed within the Base64 encoded input data. 218 * @param s A Base64 String to be decoded. 219 * @return An array containing the decoded data bytes. 220 * @throws IllegalArgumentException If the input is not valid Base64 encoded data. */ 221 public static byte[] decode (String s) { 222 return decode(s.toCharArray()); 223 } 224 225 /** Decodes a byte array from Base64 format. No blanks or line breaks are allowed within the Base64 encoded input data. 226 * @param s A Base64 String to be decoded. 227 * @param inverseCharMap 228 * @return An array containing the decoded data bytes. 229 * @throws IllegalArgumentException If the input is not valid Base64 encoded data. */ 230 public static byte[] decode (String s, CharMap inverseCharMap) { 231 return decode(s.toCharArray(), inverseCharMap); 232 } 233 234 public static byte[] decode (char[] in, byte[] inverseCharMap) { 235 return decode(in, 0, in.length, inverseCharMap); 236 } 237 238 public static byte[] decode (char[] in, CharMap inverseCharMap) { 239 return decode(in, 0, in.length, inverseCharMap); 240 } 241 242 /** Decodes a byte array from Base64 format. No blanks or line breaks are allowed within the Base64 encoded input data. 243 * @param in A character array containing the Base64 encoded data. 244 * @return An array containing the decoded data bytes. 245 * @throws IllegalArgumentException If the input is not valid Base64 encoded data. */ 246 public static byte[] decode (char[] in) { 247 return decode(in, 0, in.length, regularMap.decodingMap); 248 } 249 250 public static byte[] decode (char[] in, int iOff, int iLen, CharMap inverseCharMap) { 251 return decode(in, iOff, iLen, inverseCharMap.decodingMap); 252 } 253 254 /** Decodes a byte array from Base64 format. No blanks or line breaks are allowed within the Base64 encoded input data. 255 * @param in A character array containing the Base64 encoded data. 256 * @param iOff Offset of the first character in <code>in</code> to be processed. 257 * @param iLen Number of characters to process in <code>in</code>, starting at <code>iOff</code>. 258 * @param inverseCharMap charMap to use 259 * @return An array containing the decoded data bytes. 260 * @throws IllegalArgumentException If the input is not valid Base64 encoded data. */ 261 public static byte[] decode (char[] in, int iOff, int iLen, byte[] inverseCharMap) { 262 if (iLen % 4 != 0) { 263 throw new IllegalArgumentException("Length of Base64 encoded input string is not a multiple of 4."); 264 } 265 while (iLen > 0 && in[iOff + iLen - 1] == '=') { 266 iLen--; 267 } 268 int oLen = (iLen * 3) / 4; 269 byte[] out = new byte[oLen]; 270 int ip = iOff; 271 int iEnd = iOff + iLen; 272 int op = 0; 273 while (ip < iEnd) { 274 int i0 = in[ip++]; 275 int i1 = in[ip++]; 276 int i2 = ip < iEnd ? in[ip++] : 'A'; 277 int i3 = ip < iEnd ? in[ip++] : 'A'; 278 if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) { 279 throw new IllegalArgumentException("Illegal character in Base64 encoded data."); 280 } 281 int b0 = inverseCharMap[i0]; 282 int b1 = inverseCharMap[i1]; 283 int b2 = inverseCharMap[i2]; 284 int b3 = inverseCharMap[i3]; 285 if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) { 286 throw new IllegalArgumentException("Illegal character in Base64 encoded data."); 287 } 288 int o0 = (b0 << 2) | (b1 >>> 4); 289 int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2); 290 int o2 = ((b2 & 3) << 6) | b3; 291 out[op++] = (byte)o0; 292 if (op < oLen) { 293 out[op++] = (byte)o1; 294 } 295 if (op < oLen) { 296 out[op++] = (byte)o2; 297 } 298 } 299 return out; 300 } 301 302 // Dummy constructor. 303 private Base64Coder () { 304 } 305 } 306