FileDocCategorySizeDatePackage
QPDecoderStream.javaAPI DocJavaMail 1.4.37230Tue Nov 17 10:38:12 GMT 2009com.sun.mail.util

QPDecoderStream

public class QPDecoderStream extends FilterInputStream
This class implements a QP Decoder. It is implemented as a FilterInputStream, so one can just wrap this class around any input stream and read bytes from this filter. The decoding is done as the bytes are read out.
author
John Mani

Fields Summary
protected byte[]
ba
protected int
spaces
Constructors Summary
public QPDecoderStream(InputStream in)
Create a Quoted Printable decoder that decodes the specified input stream.

param
in the input stream


                                 
       
	super(new PushbackInputStream(in, 2)); // pushback of size=2
    
Methods Summary
public intavailable()
Returns the number of bytes that can be read from this input stream without blocking. The QP algorithm does not permit a priori knowledge of the number of bytes after decoding, so this method just invokes the available method of the original input stream.

	// This is bogus ! We don't really know how much
	// bytes are available *after* decoding
	return in.available();
    
public booleanmarkSupported()
Tests if this input stream supports marks. Currently this class does not support marks

	return false;
    
public intread()
Read the next decoded byte from this input stream. The byte is returned as an int in the range 0 to 255. If no byte is available because the end of the stream has been reached, the value -1 is returned. This method blocks until input data is available, the end of the stream is detected, or an exception is thrown.

return
the next byte of data, or -1 if the end of the stream is reached.
exception
IOException if an I/O error occurs.

	if (spaces > 0) {
	    // We have cached space characters, return one
	    spaces--;
	    return ' ";
	}
	
	int c = in.read();

	if (c == ' ") { 
	    // Got space, keep reading till we get a non-space char
	    while ((c = in.read()) == ' ")
		spaces++;

	    if (c == '\r" || c == '\n" || c == -1)
		// If the non-space char is CR/LF/EOF, the spaces we got
	    	// so far is junk introduced during transport. Junk 'em.
		spaces = 0;
    	    else {
		// The non-space char is NOT CR/LF, the spaces are valid.
		((PushbackInputStream)in).unread(c);
		c = ' ";
	    }
	    return c; // return either <SPACE> or <CR/LF>
	}
	else if (c == '=") {
	    // QP Encoded atom. Decode the next two bytes
	    int a = in.read();

	    if (a == '\n") {
		/* Hmm ... not really confirming QP encoding, but lets
		 * allow this as a LF terminated encoded line .. and
		 * consider this a soft linebreak and recurse to fetch 
		 * the next char.
		 */
		return read();
	    } else if (a == '\r") {
		// Expecting LF. This forms a soft linebreak to be ignored.
		int b = in.read();
		if (b != '\n") 
		    /* Not really confirming QP encoding, but
		     * lets allow this as well.
		     */
		    ((PushbackInputStream)in).unread(b);
		return read();
	    } else if (a == -1) {
	   	// Not valid QP encoding, but we be nice and tolerant here !
		return -1;
	    } else {
		ba[0] = (byte)a;
		ba[1] = (byte)in.read();
		try {
		    return ASCIIUtility.parseInt(ba, 0, 2, 16);
		} catch (NumberFormatException nex) {
		    /*
		    System.err.println(
		     	"Illegal characters in QP encoded stream: " + 
		     	ASCIIUtility.toString(ba, 0, 2)
		    );
		    */

		    ((PushbackInputStream)in).unread(ba);
		    return c;
		}
	    }
	}
	return c;
    
public intread(byte[] buf, int off, int len)
Reads up to len decoded bytes of data from this input stream into an array of bytes. This method blocks until some input is available.

param
buf the buffer into which the data is read.
param
off the start offset of the data.
param
len the maximum number of bytes read.
return
the total number of bytes read into the buffer, or -1 if there is no more data because the end of the stream has been reached.
exception
IOException if an I/O error occurs.

	int i, c;
	for (i = 0; i < len; i++) {
	    if ((c = read()) == -1) {
		if (i == 0) // At end of stream, so we should
		    i = -1; // return -1 , NOT 0.
		break;
	    }
	    buf[off+i] = (byte)c;
	}
        return i;
    
public longskip(long n)
Skips over and discards n bytes of data from this stream.

	long skipped = 0;
	while (n-- > 0 && read() >= 0)
	    skipped++;
	return skipped;