Author: olegk
Date: Fri Dec 18 10:22:42 2009
New Revision: 892206
URL: http://svn.apache.org/viewvc?rev=892206&view=rev
Log:
QuotedPrintableOutputStream refactoring
Removed:
james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableEncoder.java
Modified:
james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/CodecUtil.java
james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java
james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableOutputStream.java
Modified:
james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/CodecUtil.java
URL:
http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/CodecUtil.java?rev=892206&r1=892205&r2=892206&view=diff
==============================================================================
---
james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/CodecUtil.java
(original)
+++
james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/CodecUtil.java
Fri Dec 18 10:22:42 2009
@@ -53,9 +53,9 @@
* @throws IOException
*/
public static void encodeQuotedPrintableBinary(final InputStream in, final
OutputStream out) throws IOException {
-
- QuotedPrintableEncoder encoder = new
QuotedPrintableEncoder(DEFAULT_ENCODING_BUFFER_SIZE, true);
- encoder.encode(in, out);
+ QuotedPrintableOutputStream qpOut = new
QuotedPrintableOutputStream(out, true);
+ copy(in, qpOut);
+ qpOut.close();
}
/**
@@ -67,8 +67,9 @@
* @throws IOException
*/
public static void encodeQuotedPrintable(final InputStream in, final
OutputStream out) throws IOException {
- final QuotedPrintableEncoder encoder = new
QuotedPrintableEncoder(DEFAULT_ENCODING_BUFFER_SIZE, false);
- encoder.encode(in, out);
+ QuotedPrintableOutputStream qpOut = new
QuotedPrintableOutputStream(out, false);
+ copy(in, qpOut);
+ qpOut.close();
}
/**
Modified:
james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java
URL:
http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java?rev=892206&r1=892205&r2=892206&view=diff
==============================================================================
---
james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java
(original)
+++
james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java
Fri Dec 18 10:22:42 2009
@@ -30,10 +30,11 @@
*/
public class QuotedPrintableInputStream extends InputStream {
- private static final int ENCODED_BUFFER_SIZE = 1024 * 2;
- private static char CR = '\r';
- private static char LF = '\n';
- private static char EQ = '=';
+ private static final int DEFAULT_BUFFER_SIZE = 1024 * 2;
+
+ private static final byte EQ = 0x3D;
+ private static final byte CR = 0x0D;
+ private static final byte LF = 0x0A;
private static Log log =
LogFactory.getLog(QuotedPrintableInputStream.class);
@@ -59,11 +60,11 @@
}
public QuotedPrintableInputStream(final InputStream in, boolean strict) {
- this(ENCODED_BUFFER_SIZE, in, strict);
+ this(DEFAULT_BUFFER_SIZE, in, strict);
}
public QuotedPrintableInputStream(final InputStream in) {
- this(ENCODED_BUFFER_SIZE, in, false);
+ this(DEFAULT_BUFFER_SIZE, in, false);
}
/**
Modified:
james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableOutputStream.java
URL:
http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableOutputStream.java?rev=892206&r1=892205&r2=892206&view=diff
==============================================================================
---
james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableOutputStream.java
(original)
+++
james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableOutputStream.java
Fri Dec 18 10:22:42 2009
@@ -28,22 +28,183 @@
*/
public class QuotedPrintableOutputStream extends FilterOutputStream {
- private QuotedPrintableEncoder encoder;
+ private static final int DEFAULT_BUFFER_SIZE = 1024 * 3;
+
+ private static final byte TB = 0x09;
+ private static final byte SP = 0x20;
+ private static final byte EQ = 0x3D;
+ private static final byte CR = 0x0D;
+ private static final byte LF = 0x0A;
+ private static final byte QUOTED_PRINTABLE_LAST_PLAIN = 0x7E;
+ private static final int QUOTED_PRINTABLE_MAX_LINE_LENGTH = 76;
+ private static final int QUOTED_PRINTABLE_OCTETS_PER_ESCAPE = 3;
+ private static final byte[] HEX_DIGITS = {
+ '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+ private final byte[] outBuffer;
+ private final boolean binary;
+
+ private boolean pendingSpace;
+ private boolean pendingTab;
+ private boolean pendingCR;
+ private int nextSoftBreak;
+ private int outputIndex;
+
private boolean closed = false;
- public QuotedPrintableOutputStream(OutputStream out, boolean binary) {
+ private byte[] oneByte = new byte[1];
+
+ public QuotedPrintableOutputStream(int bufsize, OutputStream out, boolean
binary) {
super(out);
- encoder = new
QuotedPrintableEncoder(CodecUtil.DEFAULT_ENCODING_BUFFER_SIZE, binary);
- encoder.initEncoding(out);
+ this.outBuffer = new byte[bufsize];
+ this.binary = binary;
+ this.pendingSpace = false;
+ this.pendingTab = false;
+ this.pendingCR = false;
+ this.outputIndex = 0;
+ this.nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH + 1;
}
+ public QuotedPrintableOutputStream(OutputStream out, boolean binary) {
+ this(DEFAULT_BUFFER_SIZE, out, binary);
+ }
+
+ private void encodeChunk(byte[] buffer, int off, int len) throws
IOException {
+ for (int inputIndex = off; inputIndex < len + off; inputIndex++) {
+ encode(buffer[inputIndex]);
+ }
+ }
+
+ private void completeEncoding() throws IOException {
+ writePending();
+ flushOutput();
+ }
+
+ private void writePending() throws IOException {
+ if (pendingSpace) {
+ plain(SP);
+ } else if (pendingTab) {
+ plain(TB);
+ } else if (pendingCR) {
+ plain(CR);
+ }
+ clearPending();
+ }
+
+ private void clearPending() throws IOException {
+ pendingSpace = false;
+ pendingTab = false;
+ pendingCR = false;
+ }
+
+ private void encode(byte next) throws IOException {
+ if (next == LF) {
+ if (binary) {
+ writePending();
+ escape(next);
+ } else {
+ if (pendingCR) {
+ // Expect either space or tab pending
+ // but not both
+ if (pendingSpace) {
+ escape(SP);
+ } else if (pendingTab) {
+ escape(TB);
+ }
+ lineBreak();
+ clearPending();
+ } else {
+ writePending();
+ plain(next);
+ }
+ }
+ } else if (next == CR) {
+ if (binary) {
+ escape(next);
+ } else {
+ pendingCR = true;
+ }
+ } else {
+ writePending();
+ if (next == SP) {
+ if (binary) {
+ escape(next);
+ } else {
+ pendingSpace = true;
+ }
+ } else if (next == TB) {
+ if (binary) {
+ escape(next);
+ } else {
+ pendingTab = true;
+ }
+ } else if (next < SP) {
+ escape(next);
+ } else if (next > QUOTED_PRINTABLE_LAST_PLAIN) {
+ escape(next);
+ } else if (next == EQ) {
+ escape(next);
+ } else {
+ plain(next);
+ }
+ }
+ }
+
+ private void plain(byte next) throws IOException {
+ if (--nextSoftBreak <= 1) {
+ softBreak();
+ }
+ write(next);
+ }
+
+ private void escape(byte next) throws IOException {
+ if (--nextSoftBreak <= QUOTED_PRINTABLE_OCTETS_PER_ESCAPE) {
+ softBreak();
+ }
+
+ int nextUnsigned = next & 0xff;
+
+ write(EQ);
+ --nextSoftBreak;
+ write(HEX_DIGITS[nextUnsigned >> 4]);
+ --nextSoftBreak;
+ write(HEX_DIGITS[nextUnsigned % 0x10]);
+ }
+
+ private void write(byte next) throws IOException {
+ outBuffer[outputIndex++] = next;
+ if (outputIndex >= outBuffer.length) {
+ flushOutput();
+ }
+ }
+
+ private void softBreak() throws IOException {
+ write(EQ);
+ lineBreak();
+ }
+
+ private void lineBreak() throws IOException {
+ write(CR);
+ write(LF);
+ nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH;
+ }
+
+ void flushOutput() throws IOException {
+ if (outputIndex < outBuffer.length) {
+ out.write(outBuffer, 0, outputIndex);
+ } else {
+ out.write(outBuffer);
+ }
+ outputIndex = 0;
+ }
+
@Override
public void close() throws IOException {
if (closed)
return;
try {
- encoder.completeEncoding();
+ completeEncoding();
// do not close the wrapped stream
} finally {
closed = true;
@@ -52,21 +213,21 @@
@Override
public void flush() throws IOException {
- encoder.flushOutput();
+ flushOutput();
}
@Override
public void write(int b) throws IOException {
- this.write(new byte[] { (byte) b }, 0, 1);
+ oneByte[0] = (byte) b;
+ this.write(oneByte, 0, 1);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
if (closed) {
- throw new IOException("QuotedPrintableOutputStream has been
closed");
+ throw new IOException("Stream has been closed");
}
-
- encoder.encodeChunk(b, off, len);
+ encodeChunk(b, off, len);
}
}
\ No newline at end of file