001    /*
002     * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/Base64InputStream.java $
003     * $Revision: 121 $
004     * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
005     *
006     * ====================================================================
007     * Licensed to the Apache Software Foundation (ASF) under one
008     * or more contributor license agreements.  See the NOTICE file
009     * distributed with this work for additional information
010     * regarding copyright ownership.  The ASF licenses this file
011     * to you under the Apache License, Version 2.0 (the
012     * "License"); you may not use this file except in compliance
013     * with the License.  You may obtain a copy of the License at
014     *
015     *   http://www.apache.org/licenses/LICENSE-2.0
016     *
017     * Unless required by applicable law or agreed to in writing,
018     * software distributed under the License is distributed on an
019     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
020     * KIND, either express or implied.  See the License for the
021     * specific language governing permissions and limitations
022     * under the License.
023     * ====================================================================
024     *
025     * This software consists of voluntary contributions made by many
026     * individuals on behalf of the Apache Software Foundation.  For more
027     * information on the Apache Software Foundation, please see
028     * <http://www.apache.org/>.
029     *
030     */
031    
032    package org.apache.commons.ssl;
033    
034    import java.io.FilterInputStream;
035    import java.io.IOException;
036    import java.io.InputStream;
037    
038    /**
039     * @author Credit Union Central of British Columbia
040     * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
041     * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a>
042     * @since 22-Feb-2007
043     */
044    public class Base64InputStream extends FilterInputStream {
045        private final static byte[] LINE_ENDING =
046            System.getProperty("line.separator").getBytes();
047    
048        final boolean decodeMode;
049    
050        byte[] currentLine = null;
051        int pos = 0;
052    
053        public Base64InputStream(InputStream base64, boolean decodeMode) {
054            super(base64);
055            this.decodeMode = decodeMode;
056        }
057    
058        public int read() throws IOException {
059            getLine();
060            if (currentLine == null) {
061                return -1;
062            } else {
063                byte b = currentLine[pos++];
064                if (pos >= currentLine.length) {
065                    currentLine = null;
066                }
067                return b;
068            }
069        }
070    
071        public int read(byte b[], int off, int len) throws IOException {
072            if (b == null) {
073                throw new NullPointerException();
074            } else if ((off < 0) || (off > b.length) || (len < 0) ||
075                       ((off + len) > b.length) || ((off + len) < 0)) {
076                throw new IndexOutOfBoundsException();
077            } else if (len == 0) {
078                return 0;
079            }
080    
081            getLine();
082            if (currentLine == null) {
083                return -1;
084            }
085            int size = Math.min(currentLine.length - pos, len);
086            System.arraycopy(currentLine, pos, b, off, size);
087            if (size >= currentLine.length - pos) {
088                currentLine = null;
089            } else {
090                pos += size;
091            }
092            return size;
093        }
094    
095        private void getLine() throws IOException {
096            if (currentLine == null) {
097                if (decodeMode) {
098                    String line = Util.readLine(in);
099                    if (line != null) {
100                        byte[] b = line.getBytes();
101                        currentLine = Base64.decodeBase64(b);
102                        pos = 0;
103                    }
104                } else {
105                    // It will expand to 64 bytes (16 * 4) after base64 encoding!
106                    byte[] b = Util.streamToBytes(in, 16 * 3);
107                    if (b.length > 0) {
108                        b = Base64.encodeBase64(b);
109    
110                        int lfLen = LINE_ENDING.length;
111                        currentLine = new byte[b.length + lfLen];
112                        System.arraycopy(b, 0, currentLine, 0, b.length);
113                        System.arraycopy(LINE_ENDING, 0, currentLine, b.length, lfLen);
114                    }
115                }
116            }
117        }
118    
119    
120    }