Frames | No Frames |
1: /* Base64.java -- Base64 encoding and decoding. 2: Copyright (C) 2006, 2007 Free Software Foundation, Inc. 3: 4: This file is a part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2 of the License, or (at 9: your option) any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; if not, write to the Free Software 18: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 19: USA 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. 37: 38: -- 39: Base64 encoding derived from ISC's DHCP. Copyright notices from DHCP 40: follow. See http://www.isc.org/products/DHCP/. 41: 42: Copyright (c) 1996 by Internet Software Consortium. 43: 44: Permission to use, copy, modify, and distribute this software for any 45: purpose with or without fee is hereby granted, provided that the above 46: copyright notice and this permission notice appear in all copies. 47: 48: THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM 49: DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 50: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 51: INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 52: INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING 53: FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 54: NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 55: WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 56: 57: -- 58: Portions Copyright (c) 1995 by International Business Machines, Inc. 59: 60: International Business Machines, Inc. (hereinafter called IBM) grants 61: permission under its copyrights to use, copy, modify, and distribute 62: this Software with or without fee, provided that the above copyright 63: notice and all paragraphs of this notice appear in all copies, and 64: that the name of IBM not be used in connection with the marketing of 65: any product incorporating the Software or modifications thereof, 66: without specific, written prior permission. 67: 68: To the extent it has a right to do so, IBM grants an immunity from 69: suit under its patents, if any, for the use, sale or manufacture of 70: products to the extent that such products are used for performing 71: Domain Name System dynamic updates in TCP/IP networks by means of the 72: Software. No immunity is granted for any product per se or for any 73: other function of any product. 74: 75: THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, 76: INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 77: PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, 78: DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 79: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 80: SOFTWARE, EVEN IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH 81: DAMAGES. */ 82: 83: 84: package gnu.java.util; 85: 86: import java.io.ByteArrayOutputStream; 87: import java.io.IOException; 88: 89: public final class Base64 90: { 91: 92: // No constructor. 93: private Base64() { } 94: 95: // Class methods. 96: // ------------------------------------------------------------------------- 97: 98: /** Base-64 characters. */ 99: private static final String BASE_64 = 100: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 101: 102: /** Base-64 padding character. */ 103: private static final char BASE_64_PAD = '='; 104: 105: /** 106: * Base64 encode a byte array, with no line wrapping. 107: * 108: * @param buf The byte array to encode. 109: * @return <tt>buf</tt> encoded in Base64. 110: */ 111: public static String encode(byte[] buf) 112: { 113: return encode(buf, 0); 114: } 115: 116: /** 117: * Base64 encode a byte array, returning the returning string. 118: * 119: * @param buf The byte array to encode. 120: * @param tw The total length of any line, 0 for unlimited. 121: * @return <tt>buf</tt> encoded in Base64. 122: */ 123: public static String encode(byte[] buf, int tw) 124: { 125: return encode(buf, 0, buf.length, tw); 126: } 127: 128: /** 129: * Base64 encode a byte array, returning the returning string. 130: * 131: * @param buf The byte array to encode. 132: * @param offset The offset in the byte array to start. 133: * @param length The number of bytes to encode. 134: * @param tw The total length of any line, 0 for unlimited. 135: * @return <tt>buf</tt> encoded in Base64. 136: */ 137: public static String encode(byte[] buf, int offset, int length, int tw) 138: { 139: if (offset < 0 || length < 0 || offset + length > buf.length) 140: throw new ArrayIndexOutOfBoundsException(buf.length + " " 141: + offset + " " 142: + length); 143: int srcLength = buf.length - offset; 144: byte[] input = new byte[3]; 145: int[] output = new int[4]; 146: StringBuffer out = new StringBuffer(); 147: int i = offset; 148: int chars = 0; 149: 150: while (srcLength > 2) 151: { 152: input[0] = buf[i++]; 153: input[1] = buf[i++]; 154: input[2] = buf[i++]; 155: srcLength -= 3; 156: 157: output[0] = (input[0] & 0xff) >>> 2; 158: output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4); 159: output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6); 160: output[3] = input[2] & 0x3f; 161: 162: out.append(BASE_64.charAt(output[0])); 163: if (tw > 0 && ++chars % tw == 0) 164: { 165: out.append("\n"); 166: } 167: out.append(BASE_64.charAt(output[1])); 168: if (tw > 0 && ++chars % tw == 0) 169: { 170: out.append("\n"); 171: } 172: out.append(BASE_64.charAt(output[2])); 173: if (tw > 0 && ++chars % tw == 0) 174: { 175: out.append("\n"); 176: } 177: out.append(BASE_64.charAt(output[3])); 178: if (tw > 0 && ++chars % tw == 0) 179: { 180: out.append("\n"); 181: } 182: } 183: 184: if (srcLength != 0) 185: { 186: input[0] = input[1] = input[2] = 0; 187: for (int j = 0; j < srcLength; j++) 188: { 189: input[j] = buf[i+j]; 190: } 191: output[0] = (input[0] & 0xff) >>> 2; 192: output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4); 193: output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6); 194: 195: out.append(BASE_64.charAt(output[0])); 196: if (tw > 0 && ++chars % tw == 0) 197: { 198: out.append("\n"); 199: } 200: out.append(BASE_64.charAt(output[1])); 201: if (tw > 0 && ++chars % tw == 0) 202: { 203: out.append("\n"); 204: } 205: if (srcLength == 1) 206: { 207: out.append(BASE_64_PAD); 208: } 209: else 210: { 211: out.append(BASE_64.charAt(output[2])); 212: } 213: if (tw > 0 && ++chars % tw == 0) 214: { 215: out.append("\n"); 216: } 217: out.append(BASE_64_PAD); 218: if (tw > 0 && ++chars % tw == 0) 219: { 220: out.append("\n"); 221: } 222: } 223: if (tw > 0) 224: { 225: out.append("\n"); 226: } 227: 228: return out.toString(); 229: } 230: 231: /** 232: * Decode a Base-64 string into a byte array. 233: * 234: * @param b64 The Base-64 encoded string. 235: * @return The decoded bytes. 236: * @throws java.io.IOException If the argument is not a valid Base-64 237: * encoding. 238: */ 239: public static byte[] decode(String b64) throws IOException 240: { 241: ByteArrayOutputStream result = new ByteArrayOutputStream(b64.length() / 3); 242: int state = 0, i; 243: byte temp = 0; 244: 245: for (i = 0; i < b64.length(); i++) 246: { 247: if (Character.isWhitespace(b64.charAt(i))) 248: { 249: continue; 250: } 251: if (b64.charAt(i) == BASE_64_PAD) 252: { 253: break; 254: } 255: 256: int pos = BASE_64.indexOf(b64.charAt(i)); 257: if (pos < 0) 258: { 259: throw new IOException("non-Base64 character " + b64.charAt(i)); 260: } 261: switch (state) 262: { 263: case 0: 264: temp = (byte) (pos - BASE_64.indexOf('A') << 2); 265: state = 1; 266: break; 267: 268: case 1: 269: temp |= (byte) (pos - BASE_64.indexOf('A') >>> 4); 270: result.write(temp); 271: temp = (byte) ((pos - BASE_64.indexOf('A') & 0x0f) << 4); 272: state = 2; 273: break; 274: 275: case 2: 276: temp |= (byte) ((pos - BASE_64.indexOf('A') & 0x7f) >>> 2); 277: result.write(temp); 278: temp = (byte) ((pos - BASE_64.indexOf('A') & 0x03) << 6); 279: state = 3; 280: break; 281: 282: case 3: 283: temp |= (byte) (pos - BASE_64.indexOf('A') & 0xff); 284: result.write(temp); 285: state = 0; 286: break; 287: 288: default: 289: throw new Error("this statement should be unreachable"); 290: } 291: } 292: 293: if (i < b64.length() && b64.charAt(i) == BASE_64_PAD) 294: { 295: switch (state) 296: { 297: case 0: 298: case 1: 299: throw new IOException("malformed Base64 sequence"); 300: 301: case 2: 302: i++; 303: for ( ; i < b64.length(); i++) 304: { 305: if (!Character.isWhitespace(b64.charAt(i))) 306: { 307: break; 308: } 309: } 310: // We must see a second pad character here. 311: if (b64.charAt(i) != BASE_64_PAD) 312: { 313: throw new IOException("malformed Base64 sequence"); 314: } 315: i++; 316: // Fall-through. 317: 318: case 3: 319: i++; 320: for ( ; i < b64.length(); i++) 321: { 322: // We should only see whitespace after this. 323: if (!Character.isWhitespace(b64.charAt(i))) 324: { 325: throw new IOException("malformed Base64 sequence"); 326: } 327: } 328: } 329: } 330: else 331: { 332: if (state != 0) 333: { 334: throw new IOException("malformed Base64 sequence"); 335: } 336: } 337: 338: return result.toByteArray(); 339: } 340: }