From 721fa0e17e563f7aceb471c4aac44c6387a4e7a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=CC=88rg=20Prante?= Date: Sat, 22 Oct 2022 15:17:57 +0200 Subject: [PATCH] clean base64 stream --- ...erStream.java => Base64DecoderStream.java} | 63 +++++++------------ .../net/mime/stream/Base64InputStream.java | 6 +- .../org/xbib/net/mime/stream/MimeStream.java | 2 +- .../xbib/net/mime/test/MimeMultipartTest.java | 11 ++-- 4 files changed, 33 insertions(+), 49 deletions(-) rename net-mime/src/main/java/org/xbib/net/mime/stream/{BASE64DecoderStream.java => Base64DecoderStream.java} (90%) diff --git a/net-mime/src/main/java/org/xbib/net/mime/stream/BASE64DecoderStream.java b/net-mime/src/main/java/org/xbib/net/mime/stream/Base64DecoderStream.java similarity index 90% rename from net-mime/src/main/java/org/xbib/net/mime/stream/BASE64DecoderStream.java rename to net-mime/src/main/java/org/xbib/net/mime/stream/Base64DecoderStream.java index 3f6eeb5..371416d 100644 --- a/net-mime/src/main/java/org/xbib/net/mime/stream/BASE64DecoderStream.java +++ b/net-mime/src/main/java/org/xbib/net/mime/stream/Base64DecoderStream.java @@ -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); diff --git a/net-mime/src/main/java/org/xbib/net/mime/stream/Base64InputStream.java b/net-mime/src/main/java/org/xbib/net/mime/stream/Base64InputStream.java index d962ef9..156acd5 100644 --- a/net-mime/src/main/java/org/xbib/net/mime/stream/Base64InputStream.java +++ b/net-mime/src/main/java/org/xbib/net/mime/stream/Base64InputStream.java @@ -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; } diff --git a/net-mime/src/main/java/org/xbib/net/mime/stream/MimeStream.java b/net-mime/src/main/java/org/xbib/net/mime/stream/MimeStream.java index 90d8425..6d565c6 100644 --- a/net-mime/src/main/java/org/xbib/net/mime/stream/MimeStream.java +++ b/net-mime/src/main/java/org/xbib/net/mime/stream/MimeStream.java @@ -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") || diff --git a/net-mime/src/test/java/org/xbib/net/mime/test/MimeMultipartTest.java b/net-mime/src/test/java/org/xbib/net/mime/test/MimeMultipartTest.java index 05388b0..8204536 100644 --- a/net-mime/src/test/java/org/xbib/net/mime/test/MimeMultipartTest.java +++ b/net-mime/src/test/java/org/xbib/net/mime/test/MimeMultipartTest.java @@ -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()))); + } } }