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 gnu.java.lang.CPStringBuilder; 87: 88: import java.io.ByteArrayOutputStream; 89: import java.io.IOException; 90: 91: public final class Base64 92: { 93: 94: // No constructor. 95: private Base64() { } 96: 97: // Class methods. 98: // ------------------------------------------------------------------------- 99: 100: /** Base-64 characters. */ 101: private static final String BASE_64 = 102: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 103: 104: /** Base-64 padding character. */ 105: private static final char BASE_64_PAD = '='; 106: 107: /** 108: * Base64 encode a byte array, with no line wrapping. 109: * 110: * @param buf The byte array to encode. 111: * @return <tt>buf</tt> encoded in Base64. 112: */ 113: public static String encode(byte[] buf) 114: { 115: return encode(buf, 0); 116: } 117: 118: /** 119: * Base64 encode a byte array, returning the returning string. 120: * 121: * @param buf The byte array to encode. 122: * @param tw The total length of any line, 0 for unlimited. 123: * @return <tt>buf</tt> encoded in Base64. 124: */ 125: public static String encode(byte[] buf, int tw) 126: { 127: return encode(buf, 0, buf.length, tw); 128: } 129: 130: /** 131: * Base64 encode a byte array, returning the returning string. 132: * 133: * @param buf The byte array to encode. 134: * @param offset The offset in the byte array to start. 135: * @param length The number of bytes to encode. 136: * @param tw The total length of any line, 0 for unlimited. 137: * @return <tt>buf</tt> encoded in Base64. 138: */ 139: public static String encode(byte[] buf, int offset, int length, int tw) 140: { 141: if (offset < 0 || length < 0 || offset + length > buf.length) 142: throw new ArrayIndexOutOfBoundsException(buf.length + " " 143: + offset + " " 144: + length); 145: int srcLength = buf.length - offset; 146: byte[] input = new byte[3]; 147: int[] output = new int[4]; 148: CPStringBuilder out = new CPStringBuilder(); 149: int i = offset; 150: int chars = 0; 151: 152: while (srcLength > 2) 153: { 154: input[0] = buf[i++]; 155: input[1] = buf[i++]; 156: input[2] = buf[i++]; 157: srcLength -= 3; 158: 159: output[0] = (input[0] & 0xff) >>> 2; 160: output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4); 161: output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6); 162: output[3] = input[2] & 0x3f; 163: 164: out.append(BASE_64.charAt(output[0])); 165: if (tw > 0 && ++chars % tw == 0) 166: { 167: out.append("\n"); 168: } 169: out.append(BASE_64.charAt(output[1])); 170: if (tw > 0 && ++chars % tw == 0) 171: { 172: out.append("\n"); 173: } 174: out.append(BASE_64.charAt(output[2])); 175: if (tw > 0 && ++chars % tw == 0) 176: { 177: out.append("\n"); 178: } 179: out.append(BASE_64.charAt(output[3])); 180: if (tw > 0 && ++chars % tw == 0) 181: { 182: out.append("\n"); 183: } 184: } 185: 186: if (srcLength != 0) 187: { 188: input[0] = input[1] = input[2] = 0; 189: for (int j = 0; j < srcLength; j++) 190: { 191: input[j] = buf[i+j]; 192: } 193: output[0] = (input[0] & 0xff) >>> 2; 194: output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4); 195: output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6); 196: 197: out.append(BASE_64.charAt(output[0])); 198: if (tw > 0 && ++chars % tw == 0) 199: { 200: out.append("\n"); 201: } 202: out.append(BASE_64.charAt(output[1])); 203: if (tw > 0 && ++chars % tw == 0) 204: { 205: out.append("\n"); 206: } 207: if (srcLength == 1) 208: { 209: out.append(BASE_64_PAD); 210: } 211: else 212: { 213: out.append(BASE_64.charAt(output[2])); 214: } 215: if (tw > 0 && ++chars % tw == 0) 216: { 217: out.append("\n"); 218: } 219: out.append(BASE_64_PAD); 220: if (tw > 0 && ++chars % tw == 0) 221: { 222: out.append("\n"); 223: } 224: } 225: if (tw > 0) 226: { 227: out.append("\n"); 228: } 229: 230: return out.toString(); 231: } 232: 233: /** 234: * Decode a Base-64 string into a byte array. 235: * 236: * @param b64 The Base-64 encoded string. 237: * @return The decoded bytes. 238: * @throws java.io.IOException If the argument is not a valid Base-64 239: * encoding. 240: */ 241: public static byte[] decode(String b64) throws IOException 242: { 243: ByteArrayOutputStream result = new ByteArrayOutputStream(b64.length() / 3); 244: int state = 0, i; 245: byte temp = 0; 246: 247: for (i = 0; i < b64.length(); i++) 248: { 249: if (Character.isWhitespace(b64.charAt(i))) 250: { 251: continue; 252: } 253: if (b64.charAt(i) == BASE_64_PAD) 254: { 255: break; 256: } 257: 258: int pos = BASE_64.indexOf(b64.charAt(i)); 259: if (pos < 0) 260: { 261: throw new IOException("non-Base64 character " + b64.charAt(i)); 262: } 263: switch (state) 264: { 265: case 0: 266: temp = (byte) (pos - BASE_64.indexOf('A') << 2); 267: state = 1; 268: break; 269: 270: case 1: 271: temp |= (byte) (pos - BASE_64.indexOf('A') >>> 4); 272: result.write(temp); 273: temp = (byte) ((pos - BASE_64.indexOf('A') & 0x0f) << 4); 274: state = 2; 275: break; 276: 277: case 2: 278: temp |= (byte) ((pos - BASE_64.indexOf('A') & 0x7f) >>> 2); 279: result.write(temp); 280: temp = (byte) ((pos - BASE_64.indexOf('A') & 0x03) << 6); 281: state = 3; 282: break; 283: 284: case 3: 285: temp |= (byte) (pos - BASE_64.indexOf('A') & 0xff); 286: result.write(temp); 287: state = 0; 288: break; 289: 290: default: 291: throw new Error("this statement should be unreachable"); 292: } 293: } 294: 295: if (i < b64.length() && b64.charAt(i) == BASE_64_PAD) 296: { 297: switch (state) 298: { 299: case 0: 300: case 1: 301: throw new IOException("malformed Base64 sequence"); 302: 303: case 2: 304: i++; 305: for ( ; i < b64.length(); i++) 306: { 307: if (!Character.isWhitespace(b64.charAt(i))) 308: { 309: break; 310: } 311: } 312: // We must see a second pad character here. 313: if (b64.charAt(i) != BASE_64_PAD) 314: { 315: throw new IOException("malformed Base64 sequence"); 316: } 317: i++; 318: // Fall-through. 319: 320: case 3: 321: i++; 322: for ( ; i < b64.length(); i++) 323: { 324: // We should only see whitespace after this. 325: if (!Character.isWhitespace(b64.charAt(i))) 326: { 327: throw new IOException("malformed Base64 sequence"); 328: } 329: } 330: } 331: } 332: else 333: { 334: if (state != 0) 335: { 336: throw new IOException("malformed Base64 sequence"); 337: } 338: } 339: 340: return result.toByteArray(); 341: } 342: }