001: /*
002: *
003: *
004: * Portions Copyright 2000-2007 Sun Microsystems, Inc. All Rights
005: * Reserved. Use is subject to license terms.
006: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
007: *
008: * This program is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public License version
010: * 2 only, as published by the Free Software Foundation.
011: *
012: * This program is distributed in the hope that it will be useful, but
013: * WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * General Public License version 2 for more details (a copy is
016: * included at /legal/license.txt).
017: *
018: * You should have received a copy of the GNU General Public License
019: * version 2 along with this work; if not, write to the Free Software
020: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
021: * 02110-1301 USA
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
024: * Clara, CA 95054 or visit www.sun.com if you need additional
025: * information or have any questions.
026: */
027:
028: /*****************************************************************************
029: * Copyright (C) The Apache Software Foundation. All rights reserved. *
030: * ------------------------------------------------------------------------- *
031: * This software is published under the terms of the Apache Software License *
032: * version 1.1, a copy of which has been included with this distribution in *
033: * the LICENSE file. *
034: *****************************************************************************/package com.sun.perseus.util;
035:
036: import java.io.InputStream;
037: import java.io.IOException;
038:
039: /**
040: * This class implements a Base64 Character decoder as specified in RFC1113.
041: * Unlike some other encoding schemes there is nothing in this encoding that
042: * tells the decoder where a buffer starts or stops, so to use it you will need
043: * to isolate your encoded data into a single chunk and then feed them
044: * this decoder. The simplest way to do that is to read all of the encoded
045: * data into a string and then use:
046: * <pre>
047: * byte data[];
048: * InputStream is = new ByteArrayInputStream(data);
049: * is = new Base64DecodeStream(is);
050: * </pre>
051: *
052: * On errors, this class throws a IOException with the following detail
053: * strings:
054: * <pre>
055: * "Base64DecodeStream: Bad Padding byte (2)."
056: * "Base64DecodeStream: Bad Padding byte (1)."
057: * </pre>
058: *
059: * @author <a href="thomas.deweese@kodak.com">Thomas DeWeese</a>
060: * @author Chuck McManis
061: * @version $Id: Base64DecodeStream.java,v 1.2 2006/04/21 06:35:45 st125089 Exp $
062: */
063:
064: public class Base64DecodeStream extends InputStream {
065: /**
066: * The stream to be decoded
067: */
068: protected InputStream src;
069:
070: /**
071: * @param src the Base64 encoded input stream
072: */
073: public Base64DecodeStream(final InputStream src) {
074: this .src = src;
075: }
076:
077: /**
078: * Decode table
079: */
080: private static final byte[] PEM_ARRAY = new byte[256];
081: static {
082: for (int i = 0; i < PEM_ARRAY.length; i++) {
083: PEM_ARRAY[i] = -1;
084: }
085:
086: int idx = 0;
087: for (char c = 'A'; c <= 'Z'; c++) {
088: PEM_ARRAY[c] = (byte) idx++;
089: }
090: for (char c = 'a'; c <= 'z'; c++) {
091: PEM_ARRAY[c] = (byte) idx++;
092: }
093:
094: for (char c = '0'; c <= '9'; c++) {
095: PEM_ARRAY[c] = (byte) idx++;
096: }
097:
098: PEM_ARRAY['+'] = (byte) idx++;
099: PEM_ARRAY['/'] = (byte) idx++;
100: }
101:
102: /**
103: * Closes the stream. Note that this <b>does not</b> close
104: * the associated <tt>InputStream</tt>
105: */
106: public void close() {
107: eof = true;
108: }
109:
110: /**
111: * @return the number of available bytes
112: * @throws IOException if an I/O error occurs
113: */
114: public int available() throws IOException {
115: return 3 - outOffset;
116: }
117:
118: /**
119: * Encoded data buffer
120: */
121: protected byte[] decodeBuffer = new byte[4];
122:
123: /**
124: * Output buffer
125: */
126: protected byte[] outBuffer = new byte[3];
127:
128: /**
129: * Offset in the out buffer
130: */
131: protected int outOffset = 3;
132:
133: /**
134: * Controls whether the end of the input stream has been reached
135: */
136: protected boolean eof = false;
137:
138: /**
139: * @return the next byte of data or -1 if the end of the
140: * stream is reached.
141: * @throws IOException if an I/O error occurs.
142: */
143: public int read() throws IOException {
144:
145: if (outOffset == 3) {
146: if (eof || getNextAtom()) {
147: eof = true;
148: return -1;
149: }
150: }
151:
152: return ((int) outBuffer[outOffset++]) & 0xFF;
153: }
154:
155: /**
156: * @param out where the decoded content should go
157: * @param offset in the out array
158: * @param len the number of atoms to read
159: * @return the number of atoms that were actually read
160: * @throws IOException if an I/O error happens
161: */
162: public int read(final byte[] out, final int offset, final int len)
163: throws IOException {
164:
165: int idx = 0;
166: while (idx < len) {
167: if (outOffset == 3) {
168: if (eof || getNextAtom()) {
169: eof = true;
170: if (idx == 0) {
171: return -1;
172: } else {
173: return idx;
174: }
175: }
176: }
177:
178: out[offset + idx] = outBuffer[outOffset++];
179:
180: idx++;
181: }
182: return idx;
183: }
184:
185: /**
186: * @return true if the next atom has been read
187: * @throws IOException if an I/O error happens
188: */
189: final boolean getNextAtom() throws IOException {
190: int count, a, b, c, d;
191:
192: int off = 0;
193: while (off != 4) {
194: count = src.read(decodeBuffer, off, 4 - off);
195: if (count == -1) {
196: return true;
197: }
198:
199: int in = off, out = off;
200: while (in < off + count) {
201: if ((decodeBuffer[in] != '\n')
202: && (decodeBuffer[in] != '\r')
203: && (decodeBuffer[in] != ' ')) {
204: decodeBuffer[out++] = decodeBuffer[in];
205: }
206: in++;
207: }
208:
209: off = out;
210: }
211:
212: a = PEM_ARRAY[((int) decodeBuffer[0]) & 0xFF];
213: b = PEM_ARRAY[((int) decodeBuffer[1]) & 0xFF];
214: c = PEM_ARRAY[((int) decodeBuffer[2]) & 0xFF];
215: d = PEM_ARRAY[((int) decodeBuffer[3]) & 0xFF];
216:
217: outBuffer[0] = (byte) ((a << 2) | (b >>> 4));
218: outBuffer[1] = (byte) ((b << 4) | (c >>> 2));
219: outBuffer[2] = (byte) ((c << 6) | d);
220:
221: if (decodeBuffer[3] != '=') {
222: // All three bytes are good.
223: outOffset = 0;
224: } else if (decodeBuffer[2] == '=') {
225: // Only one byte of output.
226: outBuffer[2] = outBuffer[0];
227: outOffset = 2;
228: eof = true;
229: } else {
230: // Only two bytes of output.
231: outBuffer[2] = outBuffer[1];
232: outBuffer[1] = outBuffer[0];
233: outOffset = 1;
234: eof = true;
235: }
236:
237: return false;
238: }
239: }
|