james-mime4j-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ol...@apache.org
Subject svn commit: r892206 - in /james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec: CodecUtil.java QuotedPrintableEncoder.java QuotedPrintableInputStream.java QuotedPrintableOutputStream.java
Date Fri, 18 Dec 2009 10:22:42 GMT
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



Mime
View raw message