001    /**
002     *
003     * Copyright 2003-2006 The Apache Software Foundation
004     *
005     *  Licensed under the Apache License, Version 2.0 (the "License");
006     *  you may not use this file except in compliance with the License.
007     *  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.mail.util;
019    
020    import java.io.ByteArrayOutputStream;
021    import java.io.FilterInputStream;
022    import java.io.IOException;
023    import java.io.InputStream;
024    import java.io.UnsupportedEncodingException;
025    
026    /**
027     * An implementation of a FilterOutputStream that decodes the
028     * stream data in Q-P encoding format.  This version does the
029     * decoding "on the fly" rather than decoding a single block of
030     * data.  Since this version is intended for use by the MimeUtilty class,
031     * it also handles line breaks in the encoded data.
032     */
033    public class QuotedPrintableDecoderStream extends FilterInputStream {
034        // our decoder for processing the data
035        protected QuotedPrintableEncoder decoder;
036    
037    
038        /**
039         * Stream constructor.
040         *
041         * @param in     The InputStream this stream is filtering.
042         */
043        public QuotedPrintableDecoderStream(InputStream in) {
044            super(in);
045            decoder = new QuotedPrintableEncoder();
046        }
047    
048        // in order to function as a filter, these streams need to override the different
049        // read() signatures.
050    
051    
052        /**
053         * Read a single byte from the stream.
054         *
055         * @return The next byte of the stream.  Returns -1 for an EOF condition.
056         * @exception IOException
057         */
058        public int read() throws IOException
059        {
060            // just get a single byte from the decoder
061            return decoder.decode(in);
062        }
063    
064    
065        /**
066         * Read a buffer of data from the input stream.
067         *
068         * @param buffer The target byte array the data is placed into.
069         * @param offset The starting offset for the read data.
070         * @param length How much data is requested.
071         *
072         * @return The number of bytes of data read.
073         * @exception IOException
074         */
075        public int read(byte [] buffer, int offset, int length) throws IOException {
076    
077            for (int i = 0; i < length; i++) {
078                int ch = decoder.decode(in);
079                if (ch == -1) {
080                    return i;
081                }
082                buffer[offset + i] = (byte)ch;
083            }
084    
085            return length;
086        }
087    
088    
089        /**
090         * Indicate whether this stream supports the mark() operation.
091         *
092         * @return Always returns false.
093         */
094        public boolean markSupported() {
095            return false;
096        }
097    
098    
099        /**
100         * Give an estimate of how much additional data is available
101         * from this stream.
102         *
103         * @return Always returns -1.
104         * @exception IOException
105         */
106        public int available() throws IOException {
107            // this is almost impossible to determine at this point
108            return -1;
109        }
110    }
111    
112