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: ; 144: 145: int pos = BASE_64.indexOf((char) i); 146: if (pos >= 0) 147: { 148: switch (state) 149: { 150: case 0: 151: temp = pos << 2; 152: state = 1; 153: break; 154: case 1: 155: buf[count++] = (byte) (temp | (pos >>> 4)); 156: temp = (pos & 0x0F) << 4; 157: state = 2; 158: break; 159: case 2: 160: buf[count++] = (byte) (temp | (pos >>> 2)); 161: temp = (pos & 0x03) << 6; 162: state = 3; 163: break; 164: case 3: 165: buf[count++] = (byte) (temp | pos); 166: state = 0; 167: break; 168: } 169: } 170: else if (i == BASE_64_PAD) 171: { 172: switch (state) 173: { 174: case 0: 175: case 1: 176: throw new IOException("malformed Base-64 input"); 177: case 2: 178: while (Character.isWhitespace((char) (i = in.read()))) 179: ; 180: if (i != BASE_64_PAD) 181: throw new IOException("malformed Base-64 input"); 182: case 3: 183: while (Character.isWhitespace((char) (i = in.read()))) 184: ; 185: } 186: eof = true; 187: break; 188: } 189: else // First non-Base-64 character, consider it end-of-stream. 190: { 191: if (state != 0) 192: throw new IOException("malformed Base-64 input"); 193: eof = true; 194: break; 195: } 196: } 197: return count; 198: } 199: 200: public boolean markSupported() 201: { 202: return false; 203: } 204: 205: public void mark(int markLimit) { } 206: 207: public void reset() throws IOException 208: { 209: throw new IOException("reset not supported"); 210: } 211: 212: public long skip(long n) throws IOException 213: { 214: long skipped; 215: for (skipped = 0; skipped < n; skipped++) 216: if (read() == -1) 217: break; 218: return skipped; 219: } 220: }