FileDocCategorySizeDatePackage
UUDecoderStream.javaAPI DocGlassfish v2 API8331Mon May 14 15:28:46 BST 2007com.sun.mail.util

UUDecoderStream

public class UUDecoderStream extends FilterInputStream
This class implements a UUDecoder. 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
author
Bill Shannon

Fields Summary
private String
name
private int
mode
private byte[]
buffer
private int
bufsize
private int
index
private boolean
gotPrefix
private boolean
gotEnd
private LineInputStream
lin
Constructors Summary
public UUDecoderStream(InputStream in)
Create a UUdecoder that decodes the specified input stream

param
in the input stream


                              
       
	super(in);
	lin = new LineInputStream(in);
	buffer = new byte[45]; // max decoded chars in a line = 45
    
Methods Summary
public intavailable()

	 // This is only an estimate, since in.available()
	 // might include CRLFs too ..
	 return ((in.available() * 3)/4 + (bufsize-index));
    
private booleandecode()


	if (gotEnd)
	    return false;
	bufsize = 0;
	String line;
	do {
	    line = lin.readLine();

	    /*
	     * Improperly encoded data sometimes omits the zero length
	     * line that starts with a space character, we detect the
	     * following "end" line here.
	     */
	    if (line == null)
		throw new IOException("Missing End");
	    if (line.regionMatches(true, 0, "end", 0, 3)) {
		gotEnd = true;
		return false;
	    }
	} while (line.length() == 0);
	int count = line.charAt(0);
	if (count < ' ")
	    throw new IOException("Buffer format error");

	/*
	 * The first character in a line is the number of original (not
	 *  the encoded atoms) characters in the line. Note that all the
	 *  code below has to handle the <SPACE> character that indicates
	 *  end of encoded stream.
	 */
	count = (count - ' ") & 0x3f;

	if (count == 0) {
	    line = lin.readLine();
	    if (line == null || !line.regionMatches(true, 0, "end", 0, 3))
		throw new IOException("Missing End");
	    gotEnd = true;
	    return false;
	}

	int need = ((count * 8)+5)/6;
//System.out.println("count " + count + ", need " + need + ", len " + line.length());
	if (line.length() < need + 1)
	    throw new IOException("Short buffer error");
	    
	int i = 1;
	byte a, b;
	/*
	 * A correct uuencoder always encodes 3 characters at a time, even
	 * if there aren't 3 characters left.  But since some people out
	 * there have broken uuencoders we handle the case where they
	 * don't include these "unnecessary" characters.
	 */
	while (bufsize < count) {
	    // continue decoding until we get 'count' decoded chars
	    a = (byte)((line.charAt(i++) - ' ") & 0x3f);
	    b = (byte)((line.charAt(i++) - ' ") & 0x3f);
	    buffer[bufsize++] = (byte)(((a << 2) & 0xfc) | ((b >>> 4) & 3));

	    if (bufsize < count) {
		a = b;
		b = (byte)((line.charAt(i++) - ' ") & 0x3f);
		buffer[bufsize++] =
				(byte)(((a << 4) & 0xf0) | ((b >>> 2) & 0xf));
	    }

	    if (bufsize < count) {
		a = b;
		b = (byte)((line.charAt(i++) - ' ") & 0x3f);
		buffer[bufsize++] = (byte)(((a << 6) & 0xc0) | (b & 0x3f));
	    }
	}
	return true;
    
public intgetMode()
Get the "mode" field from the prefix. This is the permission mode of the source file.

return
permission mode of source file
exception
IOException if an I/O error occurs.

	readPrefix();
	return mode;
    
public java.lang.StringgetName()
Get the "name" field from the prefix. This is meant to be the pathname of the decoded file

return
name of decoded file
exception
IOException if an I/O error occurs.

	readPrefix();
	return name;
    
public booleanmarkSupported()

	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
next byte of data, or -1 if the end of stream is reached.
exception
IOException if an I/O error occurs.
see
java.io.FilterInputStream#in

	if (index >= bufsize) {
	    readPrefix();
	    if (!decode())
		return -1;
	    index = 0; // reset index into buffer
	}
	return buffer[index++] & 0xff; // return lower byte
    
public intread(byte[] buf, int off, int len)

	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;
    
private voidreadPrefix()
UUencoded streams start off with the line: "begin " Search for this prefix and gobble it up.

	if (gotPrefix) // got the prefix
	    return;

	String s;
	for (;;) {
	    // read till we get the prefix: "begin MODE FILENAME"
	    s = lin.readLine(); // NOTE: readLine consumes CRLF pairs too
	    if (s == null)
		throw new IOException("UUDecoder error: No Begin");
	    if (s.regionMatches(true, 0, "begin", 0, 5)) {
		try {
		    mode = Integer.parseInt(s.substring(6,9));
		} catch (NumberFormatException ex) {
		    throw new IOException("UUDecoder error: " + ex.toString());
		}
		name = s.substring(10);
		gotPrefix = true;
		return;
	    }
	}