clean base64 stream

This commit is contained in:
Jörg Prante 2022-10-22 15:17:57 +02:00
parent 3a1adbbcfe
commit 721fa0e17e
4 changed files with 33 additions and 49 deletions

View file

@ -13,7 +13,7 @@ import java.io.InputStream;
* any input stream and read bytes from this filter. The decoding
* 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
* based on RFC1521.
@ -41,12 +41,17 @@ final class BASE64DecoderStream extends FilterInputStream {
// buffer of decoded bytes for single byte reads
private final byte[] buffer = new byte[3];
// buffer for almost 8K of typical 76 chars + CRLF lines,
// used by getByte method. this buffer contains encoded bytes.
private final byte[] input_buffer = new byte[78 * 105];
private int bufsize = 0; // size of the cache
private int index = 0; // index into the cache
private int input_pos = 0;
private int input_len = 0;
/**
@ -57,7 +62,7 @@ final class BASE64DecoderStream extends FilterInputStream {
*
* @param in the input stream
*/
public BASE64DecoderStream(InputStream in) {
public Base64DecoderStream(InputStream in) {
super(in);
}
@ -75,7 +80,6 @@ final class BASE64DecoderStream extends FilterInputStream {
if (size == 0) {
return inbuf;
}
if (inbuf[inbuf.length - 1] == '=') {
size--;
if (inbuf[inbuf.length - 2] == '=') {
@ -83,7 +87,6 @@ final class BASE64DecoderStream extends FilterInputStream {
}
}
byte[] outbuf = new byte[size];
int inpos = 0, outpos = 0;
size = inbuf.length;
while (size > 0) {
@ -173,7 +176,6 @@ final class BASE64DecoderStream extends FilterInputStream {
if (index >= bufsize) {
bufsize = index = 0;
}
int bsize = (len / 3) * 3; // round down to multiple of 3 bytes
if (bsize > 0) {
int size = 0;
@ -184,7 +186,6 @@ final class BASE64DecoderStream extends FilterInputStream {
}
off += size;
len -= size;
if (size != bsize) { // hit EOF?
if (off == off0) {
return -1;
@ -193,7 +194,6 @@ final class BASE64DecoderStream extends FilterInputStream {
}
}
}
// finish up with a partial read if necessary
for (; len > 0; len--) {
int c = read();
@ -202,7 +202,6 @@ final class BASE64DecoderStream extends FilterInputStream {
}
buf[off++] = (byte) c;
}
if (off == off0) {
return -1;
} else {
@ -292,50 +291,35 @@ final class BASE64DecoderStream extends FilterInputStream {
" before padding character (=)" +
recentChars());
}
// didn't get any characters before padding character?
if (got == 0) {
return pos - pos0;
}
atEOF = false; // need to keep reading
}
// pad partial result with zeroes
// how many bytes will we produce on output?
// (got always < 4, so size always < 3)
int size = got - 1;
if (size == 0) {
size = 1;
}
// handle the one padding character we've seen
got++;
val <<= 6;
while (got < 4) {
if (!atEOF) {
// consume the rest of the padding characters,
// filling with zeroes
i = getByte();
if (i == -1) {
throw new MimeException(
"BASE64Decoder: Error in encoded " +
"stream: hit EOF while looking for " +
"padding characters (=)" +
recentChars());
} else if (i != -2) {
throw new MimeException(
"BASE64Decoder: Error in encoded " +
"stream: found valid base64 " +
"character after a padding character " +
"(=)" + recentChars());
}
// consume the rest of the padding characters,
// filling with zeroes
i = getByte();
if (i == -1) {
throw new MimeException(
"BASE64Decoder: Error in encoded " +
"stream: hit EOF while looking for " +
"padding characters (=)" +
recentChars());
} else if (i != -2) {
throw new MimeException(
"BASE64Decoder: Error in encoded " +
"stream: found valid base64 " +
"character after a padding character " +
"(=)" + recentChars());
}
val <<= 6;
got++;
}
// now pull out however many valid bytes we got
val >>= 8; // always skip first one
if (size == 2) {
@ -353,7 +337,6 @@ final class BASE64DecoderStream extends FilterInputStream {
val |= i;
}
}
// read 4 valid characters, now extract 3 bytes
outbuf[pos + 2] = (byte) (val & 0xff);
val >>= 8;
@ -424,7 +407,7 @@ final class BASE64DecoderStream extends FilterInputStream {
errstr.append("\\t");
break;
default:
if (c >= ' ' && c < 0177) {
if (c >= ' ' && c < 127) {
errstr.append(c);
} else {
errstr.append("\\").append((int) c);

View file

@ -11,7 +11,7 @@ public class Base64InputStream extends FilterInputStream {
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;
@ -97,7 +97,7 @@ public class Base64InputStream extends FilterInputStream {
return 0;
}
long bytes = Math.min(n, outputEnd-outputStart);
outputStart += bytes;
outputStart = outputStart + (int)bytes;
return bytes;
}
@ -123,7 +123,7 @@ public class Base64InputStream extends FilterInputStream {
}
int bytes = Math.min(len, outputEnd-outputStart);
System.arraycopy(coder.output, outputStart, b, off, bytes);
outputStart += bytes;
outputStart = outputStart + bytes;
return bytes;
}

View file

@ -11,7 +11,7 @@ public class MimeStream {
public static InputStream decode(InputStream inputStream, String encoding) throws MimeException {
if (encoding.equalsIgnoreCase("base64"))
return new BASE64DecoderStream(inputStream);
return new Base64DecoderStream(inputStream);
else if (encoding.equalsIgnoreCase("quoted-printable"))
return new QuotedPrintableInputStream(inputStream);
else if (encoding.equalsIgnoreCase("binary") ||

View file

@ -17,10 +17,11 @@ public class MimeMultipartTest {
@Test
public void multiPartTest() throws MimeException, IOException {
InputStream inputStream = getClass().getResourceAsStream("/org/xbib/net/mime/test/msg.txt");
Objects.requireNonNull(inputStream);
MimeMultipartParser parser = new MimeMultipartParser("multipart/mixed; boundary=\"----=_Part_4_910054940.1065629194743\"; charset=\"ISO-8859-1\"");
parser.parse(ByteBuffer.wrap(inputStream.readAllBytes()),
e -> logger.log(Level.INFO, e.getHeaders().toString() + " length = " + e.getLength() + " content = " + e.getCharset().decode(e.getBody())));
try (InputStream inputStream = getClass().getResourceAsStream("/org/xbib/net/mime/test/msg.txt")) {
Objects.requireNonNull(inputStream);
MimeMultipartParser parser = new MimeMultipartParser("multipart/mixed; boundary=\"----=_Part_4_910054940.1065629194743\"; charset=\"ISO-8859-1\"");
parser.parse(ByteBuffer.wrap(inputStream.readAllBytes()),
e -> logger.log(Level.INFO, e.getHeaders().toString() + " length = " + e.getLength() + " content = " + e.getCharset().decode(e.getBody())));
}
}
}