clean base64 stream
This commit is contained in:
parent
3a1adbbcfe
commit
721fa0e17e
4 changed files with 33 additions and 49 deletions
|
@ -13,7 +13,7 @@ import java.io.InputStream;
|
||||||
* any input stream and read bytes from this filter. The decoding
|
* any input stream and read bytes from this filter. The decoding
|
||||||
* is done as the bytes are read out.
|
* is done as the bytes are read out.
|
||||||
*/
|
*/
|
||||||
final class BASE64DecoderStream extends FilterInputStream {
|
final class Base64DecoderStream extends FilterInputStream {
|
||||||
/**
|
/**
|
||||||
* This character array provides the character to value map
|
* This character array provides the character to value map
|
||||||
* based on RFC1521.
|
* based on RFC1521.
|
||||||
|
@ -41,12 +41,17 @@ final class BASE64DecoderStream extends FilterInputStream {
|
||||||
|
|
||||||
// buffer of decoded bytes for single byte reads
|
// buffer of decoded bytes for single byte reads
|
||||||
private final byte[] buffer = new byte[3];
|
private final byte[] buffer = new byte[3];
|
||||||
|
|
||||||
// buffer for almost 8K of typical 76 chars + CRLF lines,
|
// buffer for almost 8K of typical 76 chars + CRLF lines,
|
||||||
// used by getByte method. this buffer contains encoded bytes.
|
// used by getByte method. this buffer contains encoded bytes.
|
||||||
private final byte[] input_buffer = new byte[78 * 105];
|
private final byte[] input_buffer = new byte[78 * 105];
|
||||||
|
|
||||||
private int bufsize = 0; // size of the cache
|
private int bufsize = 0; // size of the cache
|
||||||
|
|
||||||
private int index = 0; // index into the cache
|
private int index = 0; // index into the cache
|
||||||
|
|
||||||
private int input_pos = 0;
|
private int input_pos = 0;
|
||||||
|
|
||||||
private int input_len = 0;
|
private int input_len = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,7 +62,7 @@ final class BASE64DecoderStream extends FilterInputStream {
|
||||||
*
|
*
|
||||||
* @param in the input stream
|
* @param in the input stream
|
||||||
*/
|
*/
|
||||||
public BASE64DecoderStream(InputStream in) {
|
public Base64DecoderStream(InputStream in) {
|
||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +80,6 @@ final class BASE64DecoderStream extends FilterInputStream {
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
return inbuf;
|
return inbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inbuf[inbuf.length - 1] == '=') {
|
if (inbuf[inbuf.length - 1] == '=') {
|
||||||
size--;
|
size--;
|
||||||
if (inbuf[inbuf.length - 2] == '=') {
|
if (inbuf[inbuf.length - 2] == '=') {
|
||||||
|
@ -83,7 +87,6 @@ final class BASE64DecoderStream extends FilterInputStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
byte[] outbuf = new byte[size];
|
byte[] outbuf = new byte[size];
|
||||||
|
|
||||||
int inpos = 0, outpos = 0;
|
int inpos = 0, outpos = 0;
|
||||||
size = inbuf.length;
|
size = inbuf.length;
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
|
@ -173,7 +176,6 @@ final class BASE64DecoderStream extends FilterInputStream {
|
||||||
if (index >= bufsize) {
|
if (index >= bufsize) {
|
||||||
bufsize = index = 0;
|
bufsize = index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bsize = (len / 3) * 3; // round down to multiple of 3 bytes
|
int bsize = (len / 3) * 3; // round down to multiple of 3 bytes
|
||||||
if (bsize > 0) {
|
if (bsize > 0) {
|
||||||
int size = 0;
|
int size = 0;
|
||||||
|
@ -184,7 +186,6 @@ final class BASE64DecoderStream extends FilterInputStream {
|
||||||
}
|
}
|
||||||
off += size;
|
off += size;
|
||||||
len -= size;
|
len -= size;
|
||||||
|
|
||||||
if (size != bsize) { // hit EOF?
|
if (size != bsize) { // hit EOF?
|
||||||
if (off == off0) {
|
if (off == off0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -193,7 +194,6 @@ final class BASE64DecoderStream extends FilterInputStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// finish up with a partial read if necessary
|
// finish up with a partial read if necessary
|
||||||
for (; len > 0; len--) {
|
for (; len > 0; len--) {
|
||||||
int c = read();
|
int c = read();
|
||||||
|
@ -202,7 +202,6 @@ final class BASE64DecoderStream extends FilterInputStream {
|
||||||
}
|
}
|
||||||
buf[off++] = (byte) c;
|
buf[off++] = (byte) c;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (off == off0) {
|
if (off == off0) {
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -292,50 +291,35 @@ final class BASE64DecoderStream extends FilterInputStream {
|
||||||
" before padding character (=)" +
|
" before padding character (=)" +
|
||||||
recentChars());
|
recentChars());
|
||||||
}
|
}
|
||||||
|
|
||||||
// didn't get any characters before padding character?
|
|
||||||
if (got == 0) {
|
|
||||||
return pos - pos0;
|
|
||||||
}
|
|
||||||
atEOF = false; // need to keep reading
|
atEOF = false; // need to keep reading
|
||||||
}
|
}
|
||||||
|
|
||||||
// pad partial result with zeroes
|
// pad partial result with zeroes
|
||||||
|
|
||||||
// how many bytes will we produce on output?
|
// how many bytes will we produce on output?
|
||||||
// (got always < 4, so size always < 3)
|
// (got always < 4, so size always < 3)
|
||||||
int size = got - 1;
|
int size = got - 1;
|
||||||
if (size == 0) {
|
|
||||||
size = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle the one padding character we've seen
|
// handle the one padding character we've seen
|
||||||
got++;
|
got++;
|
||||||
val <<= 6;
|
val <<= 6;
|
||||||
|
|
||||||
while (got < 4) {
|
while (got < 4) {
|
||||||
if (!atEOF) {
|
// consume the rest of the padding characters,
|
||||||
// consume the rest of the padding characters,
|
// filling with zeroes
|
||||||
// filling with zeroes
|
i = getByte();
|
||||||
i = getByte();
|
if (i == -1) {
|
||||||
if (i == -1) {
|
throw new MimeException(
|
||||||
throw new MimeException(
|
"BASE64Decoder: Error in encoded " +
|
||||||
"BASE64Decoder: Error in encoded " +
|
"stream: hit EOF while looking for " +
|
||||||
"stream: hit EOF while looking for " +
|
"padding characters (=)" +
|
||||||
"padding characters (=)" +
|
recentChars());
|
||||||
recentChars());
|
} else if (i != -2) {
|
||||||
} else if (i != -2) {
|
throw new MimeException(
|
||||||
throw new MimeException(
|
"BASE64Decoder: Error in encoded " +
|
||||||
"BASE64Decoder: Error in encoded " +
|
"stream: found valid base64 " +
|
||||||
"stream: found valid base64 " +
|
"character after a padding character " +
|
||||||
"character after a padding character " +
|
"(=)" + recentChars());
|
||||||
"(=)" + recentChars());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val <<= 6;
|
val <<= 6;
|
||||||
got++;
|
got++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now pull out however many valid bytes we got
|
// now pull out however many valid bytes we got
|
||||||
val >>= 8; // always skip first one
|
val >>= 8; // always skip first one
|
||||||
if (size == 2) {
|
if (size == 2) {
|
||||||
|
@ -353,7 +337,6 @@ final class BASE64DecoderStream extends FilterInputStream {
|
||||||
val |= i;
|
val |= i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// read 4 valid characters, now extract 3 bytes
|
// read 4 valid characters, now extract 3 bytes
|
||||||
outbuf[pos + 2] = (byte) (val & 0xff);
|
outbuf[pos + 2] = (byte) (val & 0xff);
|
||||||
val >>= 8;
|
val >>= 8;
|
||||||
|
@ -424,7 +407,7 @@ final class BASE64DecoderStream extends FilterInputStream {
|
||||||
errstr.append("\\t");
|
errstr.append("\\t");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (c >= ' ' && c < 0177) {
|
if (c >= ' ' && c < 127) {
|
||||||
errstr.append(c);
|
errstr.append(c);
|
||||||
} else {
|
} else {
|
||||||
errstr.append("\\").append((int) c);
|
errstr.append("\\").append((int) c);
|
|
@ -11,7 +11,7 @@ public class Base64InputStream extends FilterInputStream {
|
||||||
|
|
||||||
private static final byte[] EMPTY = new byte[0];
|
private static final byte[] EMPTY = new byte[0];
|
||||||
|
|
||||||
private static final int BUFFER_SIZE = 2048;
|
private static final int BUFFER_SIZE = 8192;
|
||||||
|
|
||||||
private final Base64.Coder coder;
|
private final Base64.Coder coder;
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ public class Base64InputStream extends FilterInputStream {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
long bytes = Math.min(n, outputEnd-outputStart);
|
long bytes = Math.min(n, outputEnd-outputStart);
|
||||||
outputStart += bytes;
|
outputStart = outputStart + (int)bytes;
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ public class Base64InputStream extends FilterInputStream {
|
||||||
}
|
}
|
||||||
int bytes = Math.min(len, outputEnd-outputStart);
|
int bytes = Math.min(len, outputEnd-outputStart);
|
||||||
System.arraycopy(coder.output, outputStart, b, off, bytes);
|
System.arraycopy(coder.output, outputStart, b, off, bytes);
|
||||||
outputStart += bytes;
|
outputStart = outputStart + bytes;
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ public class MimeStream {
|
||||||
|
|
||||||
public static InputStream decode(InputStream inputStream, String encoding) throws MimeException {
|
public static InputStream decode(InputStream inputStream, String encoding) throws MimeException {
|
||||||
if (encoding.equalsIgnoreCase("base64"))
|
if (encoding.equalsIgnoreCase("base64"))
|
||||||
return new BASE64DecoderStream(inputStream);
|
return new Base64DecoderStream(inputStream);
|
||||||
else if (encoding.equalsIgnoreCase("quoted-printable"))
|
else if (encoding.equalsIgnoreCase("quoted-printable"))
|
||||||
return new QuotedPrintableInputStream(inputStream);
|
return new QuotedPrintableInputStream(inputStream);
|
||||||
else if (encoding.equalsIgnoreCase("binary") ||
|
else if (encoding.equalsIgnoreCase("binary") ||
|
||||||
|
|
|
@ -17,10 +17,11 @@ public class MimeMultipartTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void multiPartTest() throws MimeException, IOException {
|
public void multiPartTest() throws MimeException, IOException {
|
||||||
InputStream inputStream = getClass().getResourceAsStream("/org/xbib/net/mime/test/msg.txt");
|
try (InputStream inputStream = getClass().getResourceAsStream("/org/xbib/net/mime/test/msg.txt")) {
|
||||||
Objects.requireNonNull(inputStream);
|
Objects.requireNonNull(inputStream);
|
||||||
MimeMultipartParser parser = new MimeMultipartParser("multipart/mixed; boundary=\"----=_Part_4_910054940.1065629194743\"; charset=\"ISO-8859-1\"");
|
MimeMultipartParser parser = new MimeMultipartParser("multipart/mixed; boundary=\"----=_Part_4_910054940.1065629194743\"; charset=\"ISO-8859-1\"");
|
||||||
parser.parse(ByteBuffer.wrap(inputStream.readAllBytes()),
|
parser.parse(ByteBuffer.wrap(inputStream.readAllBytes()),
|
||||||
e -> logger.log(Level.INFO, e.getHeaders().toString() + " length = " + e.getLength() + " content = " + e.getCharset().decode(e.getBody())));
|
e -> logger.log(Level.INFO, e.getHeaders().toString() + " length = " + e.getLength() + " content = " + e.getCharset().decode(e.getBody())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue