Frames | No Frames |
1: /* Base64InputStream.java -- base-64 input stream. 2: Copyright (C) 2003, 2004 Free Software Foundation, Inc. 3: 4: This file is 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, or (at your option) 9: 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; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 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: package gnu.java.io; 40: 41: import java.io.ByteArrayInputStream; 42: import java.io.ByteArrayOutputStream; 43: import java.io.FilterInputStream; 44: import java.io.IOException; 45: import java.io.InputStream; 46: 47: /** 48: * A filter input stream that decodes data encoded in the Base-64 49: * encoding scheme. 50: * 51: * @author Casey Marshall (rsdio@metastatic.org) 52: */ 53: public class Base64InputStream extends FilterInputStream 54: { 55: 56: // Constants and fields. 57: // ------------------------------------------------------------------------ 58: 59: /** Base-64 digits. */ 60: private static final String BASE_64 = 61: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 62: 63: /** Base-64 padding character. */ 64: private static final char BASE_64_PAD = '='; 65: 66: /** Decoding state. */ 67: private int state; 68: 69: /** Intermediate decoded value. */ 70: private int temp; 71: 72: /** EOF flag. */ 73: private boolean eof; 74: 75: private final byte[] one = new byte[1]; 76: 77: // Constructors. 78: // ------------------------------------------------------------------------ 79: 80: /** 81: * Create a new Base-64 input stream. The input bytes must be the 82: * ASCII characters A-Z, a-z, 0-9, + and /, with optional whitespace, 83: * and will be decoded into a byte stream. 84: * 85: * @param in The source of Base-64 input. 86: */ 87: public Base64InputStream(InputStream in) 88: { 89: super(in); 90: state = 0; 91: temp = 0; 92: eof = false; 93: } 94: 95: // Class method. 96: // ------------------------------------------------------------------------ 97: 98: /** 99: * Decode a single Base-64 string to a byte array. 100: * 101: * @param base64 The Base-64 encoded data. 102: * @return The decoded bytes. 103: * @throws IOException If the given data do not compose a valid Base-64 104: * sequence. 105: */ 106: public static byte[] decode(String base64) throws IOException 107: { 108: Base64InputStream in = 109: new Base64InputStream(new ByteArrayInputStream(base64.getBytes())); 110: ByteArrayOutputStream out = 111: new ByteArrayOutputStream((int) (base64.length() / 0.666)); 112: byte[] buf = new byte[1024]; 113: int len; 114: while ((len = in.read(buf)) != -1) 115: out.write(buf, 0, len); 116: return out.toByteArray(); 117: } 118: 119: // Instance methods. 120: // ------------------------------------------------------------------------ 121: 122: public int available() 123: { 124: return 0; 125: } 126: 127: public int read() throws IOException 128: { 129: if (read(one) == 1) 130: return one[0]; 131: return -1; 132: } 133: 134: public int read(byte[] buf, int off, int len) throws IOException 135: { 136: if (eof) 137: return -1; 138: int count = 0; 139: while (count < len) 140: { 141: int i; 142: while (Character.isWhitespace((char) (i = in.read()))); 143: int pos = BASE_64.indexOf((char) i); 144: if (pos >= 0) 145: { 146: switch (state) 147: { 148: case 0: 149: temp = pos << 2; 150: state = 1; 151: break; 152: case 1: 153: buf[count++] = (byte) (temp | (pos >>> 4)); 154: temp = (pos & 0x0F) << 4; 155: state = 2; 156: break; 157: case 2: 158: buf[count++] = (byte) (temp | (pos >>> 2)); 159: temp = (pos & 0x03) << 6; 160: state = 3; 161: break; 162: case 3: 163: buf[count++] = (byte) (temp | pos); 164: state = 0; 165: break; 166: } 167: } 168: else if (i == BASE_64_PAD) 169: { 170: switch (state) 171: { 172: case 0: 173: case 1: 174: throw new IOException("malformed Base-64 input"); 175: case 2: 176: while (Character.isWhitespace((char) (i = in.read()))); 177: if (i != BASE_64_PAD) 178: throw new IOException("malformed Base-64 input"); 179: case 3: 180: while (Character.isWhitespace((char) (i = in.read()))); 181: } 182: eof = true; 183: break; 184: } 185: else // First non-Base-64 character, consider it end-of-stream. 186: { 187: if (state != 0) 188: throw new IOException("malformed Base-64 input"); 189: eof = true; 190: break; 191: } 192: } 193: return count; 194: } 195: 196: public boolean markSupported() 197: { 198: return false; 199: } 200: 201: public void mark(int markLimit) { } 202: 203: public void reset() throws IOException 204: { 205: throw new IOException("reset not supported"); 206: } 207: 208: public long skip(long n) throws IOException 209: { 210: long skipped; 211: for (skipped = 0; skipped < n; skipped++) 212: if (read() == -1) 213: break; 214: return skipped; 215: } 216: }