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