james-mime4j-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From b...@apache.org
Subject svn commit: r895486 - in /james/mime4j/branches/cycleclean/core/src: main/java/org/apache/james/mime4j/codec/ test/java/org/apache/james/mime4j/codec/
Date Sun, 03 Jan 2010 21:47:39 GMT
Author: bago
Date: Sun Jan  3 21:47:38 2010
New Revision: 895486

URL: http://svn.apache.org/viewvc?rev=895486&view=rev
Log:
Introduced a DecodeMonitor object with 2 basic implementations (SILENT, STRICT). The decoding
classes/methods in codec have been upgraded to use a DecodeMonitor instead of the internal
boolean strict. Fixed a bug in QuotedPrintableInputStream that sometimes was not converting
a lonely LF to CRLF. Added some malformation monitoring to QuotedPrintableInputStream (lone
LF and lone CR are "monitored"). Added some more invalid data monitoring to Base64InputStream
that now "notifies" unexpected chars (non base64, non CR, LF or SP). (MIME4J-158 + MIME4J-161)

Added:
    james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/DecodeMonitor.java
  (with props)
Modified:
    james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/Base64InputStream.java
    james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/DecoderUtil.java
    james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java
    james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/codec/DecoderUtilTest.java
    james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableInputStreamTest.java
    james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableTextEncodeTest.java

Modified: james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/Base64InputStream.java
URL: http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/Base64InputStream.java?rev=895486&r1=895485&r2=895486&view=diff
==============================================================================
--- james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/Base64InputStream.java
(original)
+++ james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/Base64InputStream.java
Sun Jan  3 21:47:38 2010
@@ -22,16 +22,12 @@
 import java.io.IOException;
 import java.io.InputStream;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.apache.james.mime4j.util.ByteArrayBuffer;
 
 /**
  * Performs Base-64 decoding on an underlying stream.
  */
 public class Base64InputStream extends InputStream {
-    private static Log log = LogFactory.getLog(Base64InputStream.class);
-
     private static final int ENCODED_BUFFER_SIZE = 1536;
 
     private static final int[] BASE64_DECODE = new int[256];
@@ -50,7 +46,6 @@
     private final byte[] singleByte = new byte[1];
 
     private final InputStream in;
-    private final boolean strict;
     private final byte[] encoded;
     private final ByteArrayBuffer decodedBuf;
 
@@ -60,21 +55,27 @@
     private boolean closed = false;
     private boolean eof; // end of file or pad character reached
 
-    protected Base64InputStream(int bufsize, InputStream in, boolean strict) {
+    private final DecodeMonitor monitor;
+
+    public Base64InputStream(InputStream in, DecodeMonitor monitor) {
+        this(ENCODED_BUFFER_SIZE, in, monitor);
+    }
+
+    protected Base64InputStream(int bufsize, InputStream in, DecodeMonitor monitor) {
         if (in == null)
             throw new IllegalArgumentException();
         this.encoded = new byte[bufsize];
         this.decodedBuf = new ByteArrayBuffer(512);
         this.in = in;
-        this.strict = strict;
+        this.monitor = monitor;
     }
 
     public Base64InputStream(InputStream in) {
-        this(ENCODED_BUFFER_SIZE, in, false);
+        this(in, false);
     }
 
     public Base64InputStream(InputStream in, boolean strict) {
-        this(ENCODED_BUFFER_SIZE, in, strict);
+        this(ENCODED_BUFFER_SIZE, in, strict ? DecodeMonitor.STRICT : DecodeMonitor.SILENT);
     }
 
     @Override
@@ -187,8 +188,13 @@
                 }
 
                 int decoded = BASE64_DECODE[value];
-                if (decoded < 0) // -1: not a base64 char
+                if (decoded < 0) { // -1: not a base64 char
+                    if (value != 0x0D && value != 0x0A && value != 0x20)
{
+                        if (monitor.warn("Unexpected base64 byte: "+(byte) value, "ignoring."))
+                            throw new IOException("Unexpected base64 byte");
+                    }
                     continue;
+                }
 
                 data = (data << 6) | decoded;
                 sextets++;
@@ -269,18 +275,12 @@
     }
 
     private void handleUnexpectedEof(int sextets) throws IOException {
-        if (strict)
+        if (monitor.warn("Unexpected end of BASE64 stream", "dropping " + sextets + " sextet(s)"))
             throw new IOException("Unexpected end of BASE64 stream");
-        else
-            log.warn("Unexpected end of BASE64 stream; dropping " + sextets
-                    + " sextet(s)");
     }
 
     private void handleUnexpecedPad(int sextets) throws IOException {
-        if (strict)
+        if (monitor.warn("Unexpected padding character", "dropping " + sextets + " sextet(s)"))
             throw new IOException("Unexpected padding character");
-        else
-            log.warn("Unexpected padding character; dropping " + sextets
-                    + " sextet(s)");
     }
 }

Added: james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/DecodeMonitor.java
URL: http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/DecodeMonitor.java?rev=895486&view=auto
==============================================================================
--- james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/DecodeMonitor.java
(added)
+++ james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/DecodeMonitor.java
Sun Jan  3 21:47:38 2010
@@ -0,0 +1,46 @@
+package org.apache.james.mime4j.codec;
+
+
+/**
+ * This class is used to drive how decoder/parser should deal with malformed
+ * and unexpected data.
+ * 
+ * 2 basic implementations are provided:
+ * STRICT return "true" on any occourence.
+ * SILENT ignores any problem.
+ * 
+ * @see org.apache.james.mime4j.field.impl.LoggingMonitor for an example
+ * about logging malformations via Commons-logging.
+ */
+public class DecodeMonitor {
+
+    /**
+     * The STRICT monitor throws an exception on every event.
+     */
+    public static final DecodeMonitor STRICT = new DecodeMonitor() {
+
+        @Override
+        public boolean warn(String error, String dropDesc) {
+            return true;
+        }
+
+        @Override
+        public boolean isListening() {
+            return true;
+        }
+    };
+    
+    /**
+     * The SILENT monitor ignore requests.
+     */
+    public static final DecodeMonitor SILENT = new DecodeMonitor();
+    
+    public boolean warn(String error, String dropDesc) {
+        return false;
+    }
+
+    public boolean isListening() {
+        return false;
+    }
+
+}

Propchange: james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/DecodeMonitor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/DecodeMonitor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/DecoderUtil.java
URL: http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/DecoderUtil.java?rev=895486&r1=895485&r2=895486&view=diff
==============================================================================
--- james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/DecoderUtil.java
(original)
+++ james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/DecoderUtil.java
Sun Jan  3 21:47:38 2010
@@ -26,15 +26,12 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.apache.james.mime4j.util.CharsetUtil;
 
 /**
  * Static methods for decoding strings, byte arrays and encoded words.
  */
 public class DecoderUtil {
-    private static Log log = LogFactory.getLog(DecoderUtil.class);
 
     private static final Pattern PATTERN_ENCODED_WORD = Pattern.compile(
             "(.*?)=\\?([^\\?]+?)\\?(\\w)\\?([^\\?]+?)\\?=", Pattern.DOTALL);
@@ -45,14 +42,14 @@
      * @param s the string to decode.
      * @return the decoded bytes.
      */
-    private static byte[] decodeQuotedPrintable(String s) {
+    private static byte[] decodeQuotedPrintable(String s, DecodeMonitor monitor) {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         
         try {
             byte[] bytes = s.getBytes("US-ASCII");
             
             QuotedPrintableInputStream is = new QuotedPrintableInputStream(
-                                               new ByteArrayInputStream(bytes));
+                                               new ByteArrayInputStream(bytes), monitor);
             
             int b = 0;
             while ((b = is.read()) != -1) {
@@ -60,7 +57,6 @@
             }
         } catch (IOException e) {
             // This should never happen!
-            log.error(e);
             throw new IllegalStateException(e);
         }
         
@@ -71,16 +67,17 @@
      * Decodes a string containing base64 encoded data. 
      * 
      * @param s the string to decode.
+     * @param monitor 
      * @return the decoded bytes.
      */
-    private static byte[] decodeBase64(String s) {
+    private static byte[] decodeBase64(String s, DecodeMonitor monitor) {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         
         try {
             byte[] bytes = s.getBytes("US-ASCII");
             
             Base64InputStream is = new Base64InputStream(
-                                        new ByteArrayInputStream(bytes));
+                                        new ByteArrayInputStream(bytes), monitor);
             
             int b = 0;
             while ((b = is.read()) != -1) {
@@ -88,7 +85,6 @@
             }
         } catch (IOException e) {
             // This should never happen!
-            log.error(e);
             throw new IllegalStateException(e);
         }
         
@@ -101,13 +97,14 @@
      * 
      * @param encodedText the encoded text to decode.
      * @param charset the Java charset to use.
+     * @param monitor 
      * @return the decoded string.
      * @throws UnsupportedEncodingException if the given Java charset isn't 
      *         supported.
      */
-    static String decodeB(String encodedText, String charset) 
+    static String decodeB(String encodedText, String charset, DecodeMonitor monitor) 
             throws UnsupportedEncodingException {
-        byte[] decodedBytes = decodeBase64(encodedText);
+        byte[] decodedBytes = decodeBase64(encodedText, monitor);
         return new String(decodedBytes, charset);
     }
     
@@ -121,23 +118,29 @@
      * @throws UnsupportedEncodingException if the given Java charset isn't 
      *         supported.
      */
-    static String decodeQ(String encodedText, String charset)
+    static String decodeQ(String encodedText, String charset, DecodeMonitor monitor)
             throws UnsupportedEncodingException {
         encodedText = replaceUnderscores(encodedText);
         
-        byte[] decodedBytes = decodeQuotedPrintable(encodedText);
+        byte[] decodedBytes = decodeQuotedPrintable(encodedText, monitor);
         return new String(decodedBytes, charset);
     }
 
+    static String decodeEncodedWords(String body)  {
+        return decodeEncodedWords(body, DecodeMonitor.SILENT);
+    }
+
     /**
      * Decodes a string containing encoded words as defined by RFC 2047. Encoded
      * words have the form =?charset?enc?encoded-text?= where enc is either 'Q'
      * or 'q' for quoted-printable and 'B' or 'b' for base64.
      * 
-     * @param body the string to decode.
+     * @param body the string to decode
+     * @param monitor the DecodeMonitor to be used.
      * @return the decoded string.
+     * @throws IllegalArgumentException only if the DecodeMonitor strategy throws it (Strict
parsing)
      */
-    public static String decodeEncodedWords(String body) {
+    public static String decodeEncodedWords(String body, DecodeMonitor monitor) throws IllegalArgumentException
{
         int tailIndex = 0;
         boolean lastMatchValid = false;
 
@@ -149,7 +152,8 @@
             String encoding = matcher.group(3);
             String encodedText = matcher.group(4);
 
-            String decoded = tryDecodeEncodedWord(mimeCharset, encoding, encodedText);
+            String decoded = null;
+            decoded = tryDecodeEncodedWord(mimeCharset, encoding, encodedText, monitor);
             if (decoded == null) {
                 sb.append(matcher.group(0));
             } else {
@@ -173,61 +177,64 @@
 
     // return null on error
     private static String tryDecodeEncodedWord(final String mimeCharset,
-            final String encoding, final String encodedText) {
+            final String encoding, final String encodedText, DecodeMonitor monitor) throws
IllegalArgumentException {
         String charset = CharsetUtil.toJavaCharset(mimeCharset);
         if (charset == null) {
-            if (log.isWarnEnabled()) {
-                log.warn("MIME charset '" + mimeCharset + "' in encoded word '"
-                        + recombine(mimeCharset, encoding, encodedText) + "' doesn't have
a "
-                        + "corresponding Java charset");
-            }
+            monitor(monitor, mimeCharset, encoding, encodedText, "leaving word encoded",

+                    "Mime charser '", mimeCharset, "' doesn't have a corresponding Java charset");
             return null;
         } else if (!CharsetUtil.isDecodingSupported(charset)) {
-            if (log.isWarnEnabled()) {
-                log.warn("Current JDK doesn't support decoding of charset '"
-                        + charset + "' (MIME charset '" + mimeCharset
-                        + "' in encoded word '" + recombine(mimeCharset, encoding, encodedText)
-                        + "')");
-            }
+            monitor(monitor, mimeCharset, encoding, encodedText, "leaving word encoded",

+                    "Current JDK doesn't support decoding of charset '", charset, 
+                    "' - MIME charset '", mimeCharset, "' in encoded word");
             return null;
         }
 
         if (encodedText.length() == 0) {
-            if (log.isWarnEnabled()) {
-                log.warn("Missing encoded text in encoded word: '"
-                        + recombine(mimeCharset, encoding, encodedText) + "'");
-            }
+            monitor(monitor, mimeCharset, encoding, encodedText, "leaving word encoded",

+                    "Missing encoded text in encoded word");
             return null;
         }
 
         try {
             if (encoding.equalsIgnoreCase("Q")) {
-                return DecoderUtil.decodeQ(encodedText, charset);
+                return DecoderUtil.decodeQ(encodedText, charset, monitor);
             } else if (encoding.equalsIgnoreCase("B")) {
-                return DecoderUtil.decodeB(encodedText, charset);
+                return DecoderUtil.decodeB(encodedText, charset, monitor);
             } else {
-                if (log.isWarnEnabled()) {
-                    log.warn("Warning: Unknown encoding in encoded word '"
-                            + recombine(mimeCharset, encoding, encodedText) + "'");
-                }
+                monitor(monitor, mimeCharset, encoding, encodedText, "leaving word encoded",

+                        "Warning: Unknown encoding in encoded word");
                 return null;
             }
         } catch (UnsupportedEncodingException e) {
             // should not happen because of isDecodingSupported check above
-            if (log.isWarnEnabled()) {
-                log.warn("Unsupported encoding in encoded word '"
-                        + recombine(mimeCharset, encoding, encodedText) + "'", e);
-            }
+            monitor(monitor, mimeCharset, encoding, encodedText, "leaving word encoded",

+                    "Unsupported encoding (", e.getMessage(), ") in encoded word");
             return null;
         } catch (RuntimeException e) {
-            if (log.isWarnEnabled()) {
-                log.warn("Could not decode encoded word '"
-                        + recombine(mimeCharset, encoding, encodedText) + "'", e);
-            }
+            monitor(monitor, mimeCharset, encoding, encodedText, "leaving word encoded",

+                    "Could not decode (", e.getMessage(), ") encoded word");
             return null;
         }
     }
 
+    private static void monitor(DecodeMonitor monitor, String mimeCharset, String encoding,
+            String encodedText, String dropDesc, String... strings) throws IllegalArgumentException
{
+        if (monitor.isListening()) {
+            String encodedWord = recombine(mimeCharset, encoding, encodedText);
+            StringBuilder text = new StringBuilder();
+            for (String str : strings) {
+                text.append(str);
+            }
+            text.append(" (");
+            text.append(encodedWord);
+            text.append(")");
+            String exceptionDesc = text.toString();
+            if (monitor.warn(exceptionDesc, dropDesc)) 
+                throw new IllegalArgumentException(text.toString());
+        }
+    }
+
     private static String recombine(final String mimeCharset,
             final String encoding, final String encodedText) {
         return "=?" + mimeCharset + "?" + encoding + "?" + encodedText + "?=";

Modified: james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java
URL: http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java?rev=895486&r1=895485&r2=895486&view=diff
==============================================================================
--- james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java
(original)
+++ james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java
Sun Jan  3 21:47:38 2010
@@ -22,8 +22,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.apache.james.mime4j.util.ByteArrayBuffer;
 
 /**
@@ -37,12 +35,9 @@
     private static final byte CR = 0x0D;
     private static final byte LF = 0x0A;
     
-    private static Log log = LogFactory.getLog(QuotedPrintableInputStream.class);
-    
     private final byte[] singleByte = new byte[1];
     
     private final InputStream in;
-    private boolean strict;
     private final ByteArrayBuffer decodedBuf; 
     private final ByteArrayBuffer blanks; 
     
@@ -52,22 +47,32 @@
     
     private boolean closed;
 
-    protected QuotedPrintableInputStream(final int bufsize, final InputStream in, boolean
strict) {
+    private final DecodeMonitor monitor;
+
+    public QuotedPrintableInputStream(final InputStream in, DecodeMonitor monitor) {
+        this(DEFAULT_BUFFER_SIZE, in, monitor);
+    }
+
+    protected QuotedPrintableInputStream(final int bufsize, final InputStream in, DecodeMonitor
monitor) {
         super();
         this.in = in;
-        this.strict = strict;
         this.encoded = new byte[bufsize];
         this.decodedBuf = new ByteArrayBuffer(512);
         this.blanks = new ByteArrayBuffer(512);
         this.closed = false;
+        this.monitor = monitor;
     }
-    
+
+    protected QuotedPrintableInputStream(final int bufsize, final InputStream in, boolean
strict) {
+        this(bufsize, in, strict ? DecodeMonitor.STRICT : DecodeMonitor.SILENT);
+    }
+
     public QuotedPrintableInputStream(final InputStream in, boolean strict) {
         this(DEFAULT_BUFFER_SIZE, in, strict);
     }
     
     public QuotedPrintableInputStream(final InputStream in) {
-        this(DEFAULT_BUFFER_SIZE, in, false);
+        this(in, false);
     }
     
     /**
@@ -123,7 +128,7 @@
     }
     
     private int transfer(
-            final int b, final byte[] buffer, final int from, final int to, boolean keepblanks)
{
+            final int b, final byte[] buffer, final int from, final int to, boolean keepblanks)
throws IOException {
         int index = from;
         if (keepblanks && blanks.length() > 0) {
             int chunk = Math.min(blanks.length(), to - index);
@@ -134,6 +139,11 @@
                 decodedBuf.append(blanks.buffer(), chunk, remaining);
             }
             blanks.clear();
+        } else if (blanks.length() > 0 && !keepblanks) {
+            StringBuilder sb = new StringBuilder(blanks.length() * 3);
+            for (int i = 0; i < blanks.length(); i++) sb.append(" "+blanks.byteAt(i));
+            if (monitor.warn("ignored blanks", sb.toString()))
+                throw new IOException("ignored blanks");
         }
         if (b != -1) {
             if (index < to) {
@@ -171,12 +181,30 @@
                 return index == from ? -1 : index - from;
             }
 
+            boolean lastWasCR = false;
             while (pos < limit && index < to) {
                 int b = encoded[pos++] & 0xFF;
 
+                if (lastWasCR && b != LF) {
+                    if (monitor.warn("Found CR without LF", "Leaving it as is"))
+                        throw new IOException("Found CR without LF");
+                    index = transfer(CR, buffer, index, to, false);
+                } else if (!lastWasCR && b == LF) {
+                    if (monitor.warn("Found LF without CR", "Translating to CRLF"))
+                        throw new IOException("Found LF without CR");
+                }
+                
+                if (b == CR) {
+                    lastWasCR = true;
+                    continue;
+                } else {
+                    lastWasCR = false;
+                }
+                
                 if (b == LF) {
                     // at end of line
                     if (blanks.length() == 0) {
+                        index = transfer(CR, buffer, index, to, false);
                         index = transfer(LF, buffer, index, to, false);
                     } else {
                         if (blanks.byteAt(0) != EQ) {
@@ -201,7 +229,10 @@
                         int bb1 = peek(0);
                         int bb2 = peek(1);
                         if (bb1 == LF || (bb1 == CR && bb2 == LF)) {
+                            monitor.warn("Unexpected ==EOL encountered", "== 0x"+bb1+" 0x"+bb2);
                             blanks.append(b2);
+                        } else {
+                            monitor.warn("Unexpected == encountered", "==");
                         }
                     } else if (Character.isWhitespace((char) b2)) {
                         // soft line break
@@ -215,14 +246,11 @@
                         int upper = convert(b2);
                         int lower = convert(b3);
                         if (upper < 0 || lower < 0) {
-                            if (strict) {
-                                throw new IOException("Malformed encoded value encountered");
-                            } else {
-                                log.warn("Malformed encoded value encountered");
-                                index = transfer(EQ, buffer, index, to, true);
-                                index = transfer(b2, buffer, index, to, false);
-                                index = transfer(b3, buffer, index, to, false);
-                            }
+                            monitor.warn("Malformed encoded value encountered", "leaving
"+((char) EQ)+((char) b2)+((char) b3)+" as is");
+                            // TODO see MIME4J-160
+                            index = transfer(EQ, buffer, index, to, true);
+                            index = transfer(b2, buffer, index, to, false);
+                            index = transfer(b3, buffer, index, to, false);
                         } else {
                             index = transfer((upper << 4) | lower, buffer, index, to,
true);
                         }

Modified: james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/codec/DecoderUtilTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/codec/DecoderUtilTest.java?rev=895486&r1=895485&r2=895486&view=diff
==============================================================================
--- james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/codec/DecoderUtilTest.java
(original)
+++ james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/codec/DecoderUtilTest.java
Sun Jan  3 21:47:38 2010
@@ -35,12 +35,12 @@
 
     public void testDecodeB() throws UnsupportedEncodingException {
         String s = DecoderUtil.decodeB("VGhpcyBpcyB0aGUgcGxhaW4gd"
-                    + "GV4dCBtZXNzYWdlIQ==", "ISO8859-1");
+                    + "GV4dCBtZXNzYWdlIQ==", "ISO8859-1", DecodeMonitor.STRICT);
         assertEquals("This is the plain text message!", s);
     }
 
     public void testDecodeQ() throws UnsupportedEncodingException {
-        String s = DecoderUtil.decodeQ("=e1_=e2=09=E3_=E4_", "ISO8859-1");
+        String s = DecoderUtil.decodeQ("=e1_=e2=09=E3_=E4_", "ISO8859-1", DecodeMonitor.STRICT);
         assertEquals("\u00e1 \u00e2\t\u00e3 \u00e4 ", s);
     }
 

Modified: james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableInputStreamTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableInputStreamTest.java?rev=895486&r1=895485&r2=895486&view=diff
==============================================================================
--- james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableInputStreamTest.java
(original)
+++ james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableInputStreamTest.java
Sun Jan  3 21:47:38 2010
@@ -68,6 +68,13 @@
         QuotedPrintableInputStream decoder = new QuotedPrintableInputStream(bis);
         assertEquals("Soft line   Hard line\r\n", new String(read(decoder), "ISO8859-1"));
     }
+
+    public void testInvalidCR() throws IOException, UnsupportedEncodingException {
+        ByteArrayInputStream bis = new ByteArrayInputStream("Invalid=\rCR\rHard line   \r\n".getBytes("US-ASCII"));
+        QuotedPrintableInputStream decoder = new QuotedPrintableInputStream(bis);
+        // TODO is this what we really expect from decoding a stream including CR with no
LF?
+        assertEquals("Invalid=\rCR\rHard line\r\n", new String(read(decoder), "ISO8859-1"));
+    }
     
     public void testSoftBreakLoneLFDecode() throws IOException, UnsupportedEncodingException
{
         ByteArrayInputStream bis = new ByteArrayInputStream("Soft line   =\nHard line   \r\n".getBytes("US-ASCII"));
@@ -91,6 +98,7 @@
         ByteArrayInputStream bis = new ByteArrayInputStream("width==340 height=3d200\r\n".getBytes("US-ASCII"));
         QuotedPrintableInputStream decoder = new QuotedPrintableInputStream(bis);
         assertEquals("width=340 height=200\r\n", new String(read(decoder), "ISO8859-1"));
+        // TODO this could be even decoded as width=40 height=200.
     }
 
     public void testBrokenEscapedEQDecode() throws IOException, UnsupportedEncodingException
{
@@ -103,6 +111,13 @@
         assertEquals("width=340 height=200\r\n", new String(read(decoder), "ISO8859-1"));
     }
 
+    public void testSpacesBeforeEOL() throws IOException, UnsupportedEncodingException {
+        ByteArrayInputStream bis = new ByteArrayInputStream("some \r\n spaced\t\r\ncontent
\t \r\n".getBytes("US-ASCII"));
+        QuotedPrintableInputStream decoder = new QuotedPrintableInputStream(bis);
+        assertEquals("some\r\n spaced\r\ncontent\r\n", new String(read(decoder), "ISO8859-1"));
+    }
+
+
     public void testDecodeEndOfStream1() throws IOException, UnsupportedEncodingException
{
         ByteArrayInputStream bis = new ByteArrayInputStream("01234567".getBytes("US-ASCII"));
         QuotedPrintableInputStream decoder = new QuotedPrintableInputStream(6, bis, false);
@@ -118,7 +133,7 @@
     public void testDecodeEndOfStream3() throws IOException, UnsupportedEncodingException
{
         ByteArrayInputStream bis = new ByteArrayInputStream("012345\n".getBytes("US-ASCII"));
         QuotedPrintableInputStream decoder = new QuotedPrintableInputStream(6, bis, false);
-        assertEquals("012345\n", new String(read(decoder), "ISO8859-1"));
+        assertEquals("012345\r\n", new String(read(decoder), "ISO8859-1"));
     }
 
     public void testDecodeEndOfStream4() throws IOException, UnsupportedEncodingException
{
@@ -133,6 +148,12 @@
         assertEquals("01234", new String(read(decoder), "ISO8859-1"));
     }
 
+    public void testDecodeEndOfStream6() throws IOException, UnsupportedEncodingException
{
+        ByteArrayInputStream bis = new ByteArrayInputStream("01234\r\n".getBytes("US-ASCII"));
+        QuotedPrintableInputStream decoder = new QuotedPrintableInputStream(6, bis, false);
+        assertEquals("01234\r\n", new String(read(decoder), "ISO8859-1"));
+    }
+
     public void testDecodePrematureClose() throws IOException, UnsupportedEncodingException
{
         ByteArrayInputStream bis = null;
         QuotedPrintableInputStream decoder = null;

Modified: james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableTextEncodeTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableTextEncodeTest.java?rev=895486&r1=895485&r2=895486&view=diff
==============================================================================
--- james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableTextEncodeTest.java
(original)
+++ james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableTextEncodeTest.java
Sun Jan  3 21:47:38 2010
@@ -103,7 +103,7 @@
         for (byte b=0;b<Byte.MAX_VALUE;b++) {
             byte[] content = {b};
             // White space is only escaped when followed by CRLF
-            if (b != 13 && b != 32 && b != 9) { 
+            if (b != 10 && b != 13 && b != 32 && b != 9) { 
                 checkRoundtrip(content);
             }
         }



Mime
View raw message