UUDecoderStreampublic 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. |
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 | private boolean | ignoreErrors | private boolean | ignoreMissingBeginEnd | private String | readAhead |
Constructors Summary |
---|
public UUDecoderStream(InputStream in)Create a UUdecoder that decodes the specified input stream.
The System property mail.mime.uudecode.ignoreerrors
controls whether errors in the encoded data cause an exception
or are ignored. The default is false (errors cause exception).
The System property mail.mime.uudecode.ignoremissingbeginend
controls whether a missing begin or end line cause an exception
or are ignored. The default is false (errors cause exception).
super(in);
lin = new LineInputStream(in);
// default to false
ignoreErrors = PropUtil.getBooleanSystemProperty(
"mail.mime.uudecode.ignoreerrors", false);
// default to false
ignoreMissingBeginEnd = PropUtil.getBooleanSystemProperty(
"mail.mime.uudecode.ignoremissingbeginend", false);
| public UUDecoderStream(InputStream in, boolean ignoreErrors, boolean ignoreMissingBeginEnd)Create a UUdecoder that decodes the specified input stream.
super(in);
lin = new LineInputStream(in);
this.ignoreErrors = ignoreErrors;
this.ignoreMissingBeginEnd = ignoreMissingBeginEnd;
|
Methods Summary |
---|
public int | available()
// This is only an estimate, since in.available()
// might include CRLFs too ..
return ((in.available() * 3)/4 + (bufsize-index));
| private boolean | decode()
if (gotEnd)
return false;
bufsize = 0;
int count = 0;
String line;
for (;;) {
/*
* If we ignored a missing "begin", the first line
* will be saved in readAhead.
*/
if (readAhead != null) {
line = readAhead;
readAhead = null;
} else
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) {
if (!ignoreMissingBeginEnd)
throw new DecodingException(
"UUDecoder: Missing end at EOF");
gotEnd = true;
return false;
}
if (line.equals("end")) {
gotEnd = true;
return false;
}
if (line.length() == 0)
continue;
count = line.charAt(0);
if (count < ' ") {
if (!ignoreErrors)
throw new DecodingException(
"UUDecoder: Buffer format error");
continue;
}
/*
* 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.equals("end")) {
if (!ignoreMissingBeginEnd)
throw new DecodingException(
"UUDecoder: Missing End after count 0 line");
}
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) {
if (!ignoreErrors)
throw new DecodingException(
"UUDecoder: Short buffer error");
continue;
}
// got a line we're committed to, break out and decode it
break;
}
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 int | getMode()Get the "mode" field from the prefix. This is the permission
mode of the source file.
readPrefix();
return mode;
| public java.lang.String | getName()Get the "name" field from the prefix. This is meant to
be the pathname of the decoded file
readPrefix();
return name;
| public boolean | markSupported()
return false;
| public int | read()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.
if (index >= bufsize) {
readPrefix();
if (!decode())
return -1;
index = 0; // reset index into buffer
}
return buffer[index++] & 0xff; // return lower byte
| public int | read(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 void | readPrefix()UUencoded streams start off with the line:
"begin "
Search for this prefix and gobble it up.
if (gotPrefix) // got the prefix
return;
mode = 0666; // defaults, overridden below
name = "encoder.buf"; // same default used by encoder
String line;
for (;;) {
// read till we get the prefix: "begin MODE FILENAME"
line = lin.readLine(); // NOTE: readLine consumes CRLF pairs too
if (line == null) {
if (!ignoreMissingBeginEnd)
throw new DecodingException("UUDecoder: Missing begin");
// at EOF, fake it
gotPrefix = true;
gotEnd = true;
break;
}
if (line.regionMatches(false, 0, "begin", 0, 5)) {
try {
mode = Integer.parseInt(line.substring(6,9));
} catch (NumberFormatException ex) {
if (!ignoreErrors)
throw new DecodingException(
"UUDecoder: Error in mode: " + ex.toString());
}
if (line.length() > 10) {
name = line.substring(10);
} else {
if (!ignoreErrors)
throw new DecodingException(
"UUDecoder: Missing name: " + line);
}
gotPrefix = true;
break;
} else if (ignoreMissingBeginEnd) {
int count = line.charAt(0);
count = (count - ' ") & 0x3f;
int need = ((count * 8)+5)/6;
if (need == 0 || line.length() >= need + 1) {
/*
* Looks like a legitimate encoded line.
* Pretend we saw the "begin" line and
* save this line for later processing in
* decode().
*/
readAhead = line;
gotPrefix = true; // fake it
break;
}
}
}
|
|