james-mime4j-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mwiederk...@apache.org
Subject svn commit: r778457 [2/13] - in /james/mime4j/trunk: benchmark/src/main/java/org/apache/james/mime4j/ core/src/main/java/org/apache/james/mime4j/ core/src/main/java/org/apache/james/mime4j/codec/ core/src/main/java/org/apache/james/mime4j/descriptor/ c...
Date Mon, 25 May 2009 17:20:52 GMT
Modified: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/DecoderUtil.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/DecoderUtil.java?rev=778457&r1=778456&r2=778457&view=diff
==============================================================================
--- james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/DecoderUtil.java (original)
+++ james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/DecoderUtil.java Mon May 25 17:20:48 2009
@@ -1,252 +1,252 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.mime4j.codec;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-
-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);
-    
-    /**
-     * Decodes a string containing quoted-printable encoded data. 
-     * 
-     * @param s the string to decode.
-     * @return the decoded bytes.
-     */
-    public static byte[] decodeBaseQuotedPrintable(String s) {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        
-        try {
-            byte[] bytes = s.getBytes("US-ASCII");
-            
-            QuotedPrintableInputStream is = new QuotedPrintableInputStream(
-                                               new ByteArrayInputStream(bytes));
-            
-            int b = 0;
-            while ((b = is.read()) != -1) {
-                baos.write(b);
-            }
-        } catch (IOException e) {
-            /*
-             * This should never happen!
-             */
-            log.error(e);
-        }
-        
-        return baos.toByteArray();
-    }
-    
-    /**
-     * Decodes a string containing base64 encoded data. 
-     * 
-     * @param s the string to decode.
-     * @return the decoded bytes.
-     */
-    public static byte[] decodeBase64(String s) {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        
-        try {
-            byte[] bytes = s.getBytes("US-ASCII");
-            
-            Base64InputStream is = new Base64InputStream(
-                                        new ByteArrayInputStream(bytes));
-            
-            int b = 0;
-            while ((b = is.read()) != -1) {
-                baos.write(b);
-            }
-        } catch (IOException e) {
-            /*
-             * This should never happen!
-             */
-            log.error(e);
-        }
-        
-        return baos.toByteArray();
-    }
-    
-    /**
-     * Decodes an encoded word encoded with the 'B' encoding (described in 
-     * RFC 2047) found in a header field body.
-     * 
-     * @param encodedWord the encoded word to decode.
-     * @param charset the Java charset to use.
-     * @return the decoded string.
-     * @throws UnsupportedEncodingException if the given Java charset isn't 
-     *         supported.
-     */
-    public static String decodeB(String encodedWord, String charset) 
-            throws UnsupportedEncodingException {
-        
-        return new String(decodeBase64(encodedWord), charset);
-    }
-    
-    /**
-     * Decodes an encoded word encoded with the 'Q' encoding (described in 
-     * RFC 2047) found in a header field body.
-     * 
-     * @param encodedWord the encoded word to decode.
-     * @param charset the Java charset to use.
-     * @return the decoded string.
-     * @throws UnsupportedEncodingException if the given Java charset isn't 
-     *         supported.
-     */
-    public static String decodeQ(String encodedWord, String charset)
-            throws UnsupportedEncodingException {
-           
-        /*
-         * Replace _ with =20
-         */
-        StringBuilder sb = new StringBuilder(128);
-        for (int i = 0; i < encodedWord.length(); i++) {
-            char c = encodedWord.charAt(i);
-            if (c == '_') {
-                sb.append("=20");
-            } else {
-                sb.append(c);
-            }
-        }
-        
-        return new String(decodeBaseQuotedPrintable(sb.toString()), charset);
-    }
-    
-    /**
-     * Decodes a string containing encoded words as defined by RFC 2047.
-     * Encoded words in have the form 
-     * =?charset?enc?Encoded word?= where enc is either 'Q' or 'q' for 
-     * quoted-printable and 'B' or 'b' for Base64.
-     * 
-     * @param body the string to decode.
-     * @return the decoded string.
-     */
-    public static String decodeEncodedWords(String body) {
-        int previousEnd = 0;
-        boolean previousWasEncoded = false;
-
-        StringBuilder sb = new StringBuilder();
-
-        while (true) {
-            int begin = body.indexOf("=?", previousEnd);
-            int end = begin == -1 ? -1 : body.indexOf("?=", begin + 2);
-            if (end == -1) {
-                if (previousEnd == 0)
-                    return body;
-
-                sb.append(body.substring(previousEnd));
-                return sb.toString();
-            }
-            end += 2;
-
-            String sep = body.substring(previousEnd, begin);
-
-            String decoded = decodeEncodedWord(body, begin, end);
-            if (decoded == null) {
-                sb.append(sep);
-                sb.append(body.substring(begin, end));
-            } else {
-                if (!previousWasEncoded || !CharsetUtil.isWhitespace(sep)) {
-                    sb.append(sep);
-                }
-                sb.append(decoded);
-            }
-
-            previousEnd = end;
-            previousWasEncoded = decoded != null;
-        }
-    }
-
-    // return null on error
-    private static String decodeEncodedWord(String body, int begin, int end) {
-        int qm1 = body.indexOf('?', begin + 2);
-        if (qm1 == end - 2)
-            return null;
-
-        int qm2 = body.indexOf('?', qm1 + 1);
-        if (qm2 == end - 2)
-            return null;
-
-        String mimeCharset = body.substring(begin + 2, qm1);
-        String encoding = body.substring(qm1 + 1, qm2);
-        String encodedText = body.substring(qm2 + 1, end - 2);
-
-        String charset = CharsetUtil.toJavaCharset(mimeCharset);
-        if (charset == null) {
-            if (log.isWarnEnabled()) {
-                log.warn("MIME charset '" + mimeCharset + "' in encoded word '"
-                        + body.substring(begin, end) + "' 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 '" + body.substring(begin, end)
-                        + "')");
-            }
-            return null;
-        }
-
-        if (encodedText.length() == 0) {
-            if (log.isWarnEnabled()) {
-                log.warn("Missing encoded text in encoded word: '"
-                        + body.substring(begin, end) + "'");
-            }
-            return null;
-        }
-
-        try {
-            if (encoding.equalsIgnoreCase("Q")) {
-                return DecoderUtil.decodeQ(encodedText, charset);
-            } else if (encoding.equalsIgnoreCase("B")) {
-                return DecoderUtil.decodeB(encodedText, charset);
-            } else {
-                if (log.isWarnEnabled()) {
-                    log.warn("Warning: Unknown encoding in encoded word '"
-                            + body.substring(begin, end) + "'");
-                }
-                return null;
-            }
-        } catch (UnsupportedEncodingException e) {
-            // should not happen because of isDecodingSupported check above
-            if (log.isWarnEnabled()) {
-                log.warn("Unsupported encoding in encoded word '"
-                        + body.substring(begin, end) + "'", e);
-            }
-            return null;
-        } catch (RuntimeException e) {
-            if (log.isWarnEnabled()) {
-                log.warn("Could not decode encoded word '"
-                        + body.substring(begin, end) + "'", e);
-            }
-            return null;
-        }
-    }
-}
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.codec;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+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);
+    
+    /**
+     * Decodes a string containing quoted-printable encoded data. 
+     * 
+     * @param s the string to decode.
+     * @return the decoded bytes.
+     */
+    public static byte[] decodeBaseQuotedPrintable(String s) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        
+        try {
+            byte[] bytes = s.getBytes("US-ASCII");
+            
+            QuotedPrintableInputStream is = new QuotedPrintableInputStream(
+                                               new ByteArrayInputStream(bytes));
+            
+            int b = 0;
+            while ((b = is.read()) != -1) {
+                baos.write(b);
+            }
+        } catch (IOException e) {
+            /*
+             * This should never happen!
+             */
+            log.error(e);
+        }
+        
+        return baos.toByteArray();
+    }
+    
+    /**
+     * Decodes a string containing base64 encoded data. 
+     * 
+     * @param s the string to decode.
+     * @return the decoded bytes.
+     */
+    public static byte[] decodeBase64(String s) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        
+        try {
+            byte[] bytes = s.getBytes("US-ASCII");
+            
+            Base64InputStream is = new Base64InputStream(
+                                        new ByteArrayInputStream(bytes));
+            
+            int b = 0;
+            while ((b = is.read()) != -1) {
+                baos.write(b);
+            }
+        } catch (IOException e) {
+            /*
+             * This should never happen!
+             */
+            log.error(e);
+        }
+        
+        return baos.toByteArray();
+    }
+    
+    /**
+     * Decodes an encoded word encoded with the 'B' encoding (described in 
+     * RFC 2047) found in a header field body.
+     * 
+     * @param encodedWord the encoded word to decode.
+     * @param charset the Java charset to use.
+     * @return the decoded string.
+     * @throws UnsupportedEncodingException if the given Java charset isn't 
+     *         supported.
+     */
+    public static String decodeB(String encodedWord, String charset) 
+            throws UnsupportedEncodingException {
+        
+        return new String(decodeBase64(encodedWord), charset);
+    }
+    
+    /**
+     * Decodes an encoded word encoded with the 'Q' encoding (described in 
+     * RFC 2047) found in a header field body.
+     * 
+     * @param encodedWord the encoded word to decode.
+     * @param charset the Java charset to use.
+     * @return the decoded string.
+     * @throws UnsupportedEncodingException if the given Java charset isn't 
+     *         supported.
+     */
+    public static String decodeQ(String encodedWord, String charset)
+            throws UnsupportedEncodingException {
+           
+        /*
+         * Replace _ with =20
+         */
+        StringBuilder sb = new StringBuilder(128);
+        for (int i = 0; i < encodedWord.length(); i++) {
+            char c = encodedWord.charAt(i);
+            if (c == '_') {
+                sb.append("=20");
+            } else {
+                sb.append(c);
+            }
+        }
+        
+        return new String(decodeBaseQuotedPrintable(sb.toString()), charset);
+    }
+    
+    /**
+     * Decodes a string containing encoded words as defined by RFC 2047.
+     * Encoded words in have the form 
+     * =?charset?enc?Encoded word?= where enc is either 'Q' or 'q' for 
+     * quoted-printable and 'B' or 'b' for Base64.
+     * 
+     * @param body the string to decode.
+     * @return the decoded string.
+     */
+    public static String decodeEncodedWords(String body) {
+        int previousEnd = 0;
+        boolean previousWasEncoded = false;
+
+        StringBuilder sb = new StringBuilder();
+
+        while (true) {
+            int begin = body.indexOf("=?", previousEnd);
+            int end = begin == -1 ? -1 : body.indexOf("?=", begin + 2);
+            if (end == -1) {
+                if (previousEnd == 0)
+                    return body;
+
+                sb.append(body.substring(previousEnd));
+                return sb.toString();
+            }
+            end += 2;
+
+            String sep = body.substring(previousEnd, begin);
+
+            String decoded = decodeEncodedWord(body, begin, end);
+            if (decoded == null) {
+                sb.append(sep);
+                sb.append(body.substring(begin, end));
+            } else {
+                if (!previousWasEncoded || !CharsetUtil.isWhitespace(sep)) {
+                    sb.append(sep);
+                }
+                sb.append(decoded);
+            }
+
+            previousEnd = end;
+            previousWasEncoded = decoded != null;
+        }
+    }
+
+    // return null on error
+    private static String decodeEncodedWord(String body, int begin, int end) {
+        int qm1 = body.indexOf('?', begin + 2);
+        if (qm1 == end - 2)
+            return null;
+
+        int qm2 = body.indexOf('?', qm1 + 1);
+        if (qm2 == end - 2)
+            return null;
+
+        String mimeCharset = body.substring(begin + 2, qm1);
+        String encoding = body.substring(qm1 + 1, qm2);
+        String encodedText = body.substring(qm2 + 1, end - 2);
+
+        String charset = CharsetUtil.toJavaCharset(mimeCharset);
+        if (charset == null) {
+            if (log.isWarnEnabled()) {
+                log.warn("MIME charset '" + mimeCharset + "' in encoded word '"
+                        + body.substring(begin, end) + "' 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 '" + body.substring(begin, end)
+                        + "')");
+            }
+            return null;
+        }
+
+        if (encodedText.length() == 0) {
+            if (log.isWarnEnabled()) {
+                log.warn("Missing encoded text in encoded word: '"
+                        + body.substring(begin, end) + "'");
+            }
+            return null;
+        }
+
+        try {
+            if (encoding.equalsIgnoreCase("Q")) {
+                return DecoderUtil.decodeQ(encodedText, charset);
+            } else if (encoding.equalsIgnoreCase("B")) {
+                return DecoderUtil.decodeB(encodedText, charset);
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn("Warning: Unknown encoding in encoded word '"
+                            + body.substring(begin, end) + "'");
+                }
+                return null;
+            }
+        } catch (UnsupportedEncodingException e) {
+            // should not happen because of isDecodingSupported check above
+            if (log.isWarnEnabled()) {
+                log.warn("Unsupported encoding in encoded word '"
+                        + body.substring(begin, end) + "'", e);
+            }
+            return null;
+        } catch (RuntimeException e) {
+            if (log.isWarnEnabled()) {
+                log.warn("Could not decode encoded word '"
+                        + body.substring(begin, end) + "'", e);
+            }
+            return null;
+        }
+    }
+}

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/DecoderUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/EncoderUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

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=778457&r1=778456&r2=778457&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 Mon May 25 17:20:48 2009
@@ -1,230 +1,230 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.mime4j.codec;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Performs Quoted-Printable decoding on an underlying stream.
- */
-public class QuotedPrintableInputStream extends InputStream {
-    private static Log log = LogFactory.getLog(QuotedPrintableInputStream.class);
-    
-    private InputStream stream;
-    ByteQueue byteq = new ByteQueue();
-    ByteQueue pushbackq = new ByteQueue();
-    private byte state = 0;
-    private boolean closed = false;
-
-    public QuotedPrintableInputStream(InputStream stream) {
-        this.stream = stream;
-    }
-    
-    /**
-     * Terminates Quoted-Printable coded content. This method does NOT close 
-     * the underlying input stream.
-     * 
-     * @throws IOException on I/O errors.
-     */
-    @Override
-    public void close() throws IOException {
-        this.closed = true;
-    }
-
-    @Override
-    public int read() throws IOException {
-        if (closed) {
-            throw new IOException("QuotedPrintableInputStream has been closed");
-        }
-        fillBuffer();
-        if (byteq.count() == 0)
-            return -1;
-        else {
-            byte val = byteq.dequeue();
-            if (val >= 0)
-                return val;
-            else
-                return val & 0xFF;
-        }
-    }
-
-    /**
-     * Pulls bytes out of the underlying stream and places them in the
-     * pushback queue.  This is necessary (vs. reading from the
-     * underlying stream directly) to detect and filter out "transport
-     * padding" whitespace, i.e., all whitespace that appears immediately
-     * before a CRLF.
-     *
-     * @throws IOException Underlying stream threw IOException.
-     */
-    private void populatePushbackQueue() throws IOException {
-        //Debug.verify(pushbackq.count() == 0, "PopulatePushbackQueue called when pushback queue was not empty!");
-
-        if (pushbackq.count() != 0)
-            return;
-
-        while (true) {
-            int i = stream.read();
-            switch (i) {
-                case -1:
-                    // stream is done
-                    pushbackq.clear();  // discard any whitespace preceding EOF
-                    return;
-                case ' ':
-                case '\t':
-                    pushbackq.enqueue((byte)i);
-                    break;
-                case '\r':
-                case '\n':
-                    pushbackq.clear();  // discard any whitespace preceding EOL
-                    pushbackq.enqueue((byte)i);
-                    return;
-                default:
-                    pushbackq.enqueue((byte)i);
-                    return;
-            }
-        }
-    }
-
-    /**
-     * Causes the pushback queue to get populated if it is empty, then
-     * consumes and decodes bytes out of it until one or more bytes are
-     * in the byte queue.  This decoding step performs the actual QP
-     * decoding.
-     *
-     * @throws IOException Underlying stream threw IOException.
-     */
-    private void fillBuffer() throws IOException {
-        byte msdChar = 0;  // first digit of escaped num
-        while (byteq.count() == 0) {
-            if (pushbackq.count() == 0) {
-                populatePushbackQueue();
-                if (pushbackq.count() == 0)
-                    return;
-            }
-
-            byte b = pushbackq.dequeue();
-
-            switch (state) {
-                case 0:  // start state, no bytes pending
-                    if (b != '=') {
-                        byteq.enqueue(b);
-                        break;  // state remains 0
-                    } else {
-                        state = 1;
-                        break;
-                    }
-                case 1:  // encountered "=" so far
-                    if (b == '\r') {
-                        state = 2;
-                        break;
-                    } else if ((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F') || (b >= 'a' && b <= 'f')) {
-                        state = 3;
-                        msdChar = b;  // save until next digit encountered
-                        break;
-                    } else if (b == '=') {
-                        /*
-                         * Special case when == is encountered.
-                         * Emit one = and stay in this state.
-                         */
-                        if (log.isWarnEnabled()) {
-                            log.warn("Malformed MIME; got ==");
-                        }
-                        byteq.enqueue((byte)'=');
-                        break;
-                    } else {
-                        if (log.isWarnEnabled()) {
-                            log.warn("Malformed MIME; expected \\r or "
-                                    + "[0-9A-Z], got " + b);
-                        }
-                        state = 0;
-                        byteq.enqueue((byte)'=');
-                        byteq.enqueue(b);
-                        break;
-                    }
-                case 2:  // encountered "=\r" so far
-                    if (b == '\n') {
-                        state = 0;
-                        break;
-                    } else {
-                        if (log.isWarnEnabled()) {
-                            log.warn("Malformed MIME; expected " 
-                                    + (int)'\n' + ", got " + b);
-                        }
-                        state = 0;
-                        byteq.enqueue((byte)'=');
-                        byteq.enqueue((byte)'\r');
-                        byteq.enqueue(b);
-                        break;
-                    }
-                case 3:  // encountered =<digit> so far; expecting another <digit> to complete the octet
-                    if ((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F') || (b >= 'a' && b <= 'f')) {
-                        byte msd = asciiCharToNumericValue(msdChar);
-                        byte low = asciiCharToNumericValue(b);
-                        state = 0;
-                        byteq.enqueue((byte)((msd << 4) | low));
-                        break;
-                    } else {
-                        if (log.isWarnEnabled()) {
-                            log.warn("Malformed MIME; expected "
-                                     + "[0-9A-Z], got " + b);
-                        }
-                        state = 0;
-                        byteq.enqueue((byte)'=');
-                        byteq.enqueue(msdChar);
-                        byteq.enqueue(b);
-                        break;
-                    }
-                default:  // should never happen
-                    log.error("Illegal state: " + state);
-                    state = 0;
-                    byteq.enqueue(b);
-                    break;
-            }
-        }
-    }
-
-    /**
-     * Converts '0' => 0, 'A' => 10, etc.
-     * @param c ASCII character value.
-     * @return Numeric value of hexadecimal character.
-     */
-    private byte asciiCharToNumericValue(byte c) {
-        if (c >= '0' && c <= '9') {
-            return (byte)(c - '0');
-        } else if (c >= 'A' && c <= 'Z') {
-            return (byte)(0xA + (c - 'A'));
-        } else if (c >= 'a' && c <= 'z') {
-            return (byte)(0xA + (c - 'a'));
-        } else {
-            /*
-             * This should never happen since all calls to this method
-             * are preceded by a check that c is in [0-9A-Za-z]
-             */
-            throw new IllegalArgumentException((char) c 
-                    + " is not a hexadecimal digit");
-        }
-    }
-
-}
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.codec;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Performs Quoted-Printable decoding on an underlying stream.
+ */
+public class QuotedPrintableInputStream extends InputStream {
+    private static Log log = LogFactory.getLog(QuotedPrintableInputStream.class);
+    
+    private InputStream stream;
+    ByteQueue byteq = new ByteQueue();
+    ByteQueue pushbackq = new ByteQueue();
+    private byte state = 0;
+    private boolean closed = false;
+
+    public QuotedPrintableInputStream(InputStream stream) {
+        this.stream = stream;
+    }
+    
+    /**
+     * Terminates Quoted-Printable coded content. This method does NOT close 
+     * the underlying input stream.
+     * 
+     * @throws IOException on I/O errors.
+     */
+    @Override
+    public void close() throws IOException {
+        this.closed = true;
+    }
+
+    @Override
+    public int read() throws IOException {
+        if (closed) {
+            throw new IOException("QuotedPrintableInputStream has been closed");
+        }
+        fillBuffer();
+        if (byteq.count() == 0)
+            return -1;
+        else {
+            byte val = byteq.dequeue();
+            if (val >= 0)
+                return val;
+            else
+                return val & 0xFF;
+        }
+    }
+
+    /**
+     * Pulls bytes out of the underlying stream and places them in the
+     * pushback queue.  This is necessary (vs. reading from the
+     * underlying stream directly) to detect and filter out "transport
+     * padding" whitespace, i.e., all whitespace that appears immediately
+     * before a CRLF.
+     *
+     * @throws IOException Underlying stream threw IOException.
+     */
+    private void populatePushbackQueue() throws IOException {
+        //Debug.verify(pushbackq.count() == 0, "PopulatePushbackQueue called when pushback queue was not empty!");
+
+        if (pushbackq.count() != 0)
+            return;
+
+        while (true) {
+            int i = stream.read();
+            switch (i) {
+                case -1:
+                    // stream is done
+                    pushbackq.clear();  // discard any whitespace preceding EOF
+                    return;
+                case ' ':
+                case '\t':
+                    pushbackq.enqueue((byte)i);
+                    break;
+                case '\r':
+                case '\n':
+                    pushbackq.clear();  // discard any whitespace preceding EOL
+                    pushbackq.enqueue((byte)i);
+                    return;
+                default:
+                    pushbackq.enqueue((byte)i);
+                    return;
+            }
+        }
+    }
+
+    /**
+     * Causes the pushback queue to get populated if it is empty, then
+     * consumes and decodes bytes out of it until one or more bytes are
+     * in the byte queue.  This decoding step performs the actual QP
+     * decoding.
+     *
+     * @throws IOException Underlying stream threw IOException.
+     */
+    private void fillBuffer() throws IOException {
+        byte msdChar = 0;  // first digit of escaped num
+        while (byteq.count() == 0) {
+            if (pushbackq.count() == 0) {
+                populatePushbackQueue();
+                if (pushbackq.count() == 0)
+                    return;
+            }
+
+            byte b = pushbackq.dequeue();
+
+            switch (state) {
+                case 0:  // start state, no bytes pending
+                    if (b != '=') {
+                        byteq.enqueue(b);
+                        break;  // state remains 0
+                    } else {
+                        state = 1;
+                        break;
+                    }
+                case 1:  // encountered "=" so far
+                    if (b == '\r') {
+                        state = 2;
+                        break;
+                    } else if ((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F') || (b >= 'a' && b <= 'f')) {
+                        state = 3;
+                        msdChar = b;  // save until next digit encountered
+                        break;
+                    } else if (b == '=') {
+                        /*
+                         * Special case when == is encountered.
+                         * Emit one = and stay in this state.
+                         */
+                        if (log.isWarnEnabled()) {
+                            log.warn("Malformed MIME; got ==");
+                        }
+                        byteq.enqueue((byte)'=');
+                        break;
+                    } else {
+                        if (log.isWarnEnabled()) {
+                            log.warn("Malformed MIME; expected \\r or "
+                                    + "[0-9A-Z], got " + b);
+                        }
+                        state = 0;
+                        byteq.enqueue((byte)'=');
+                        byteq.enqueue(b);
+                        break;
+                    }
+                case 2:  // encountered "=\r" so far
+                    if (b == '\n') {
+                        state = 0;
+                        break;
+                    } else {
+                        if (log.isWarnEnabled()) {
+                            log.warn("Malformed MIME; expected " 
+                                    + (int)'\n' + ", got " + b);
+                        }
+                        state = 0;
+                        byteq.enqueue((byte)'=');
+                        byteq.enqueue((byte)'\r');
+                        byteq.enqueue(b);
+                        break;
+                    }
+                case 3:  // encountered =<digit> so far; expecting another <digit> to complete the octet
+                    if ((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F') || (b >= 'a' && b <= 'f')) {
+                        byte msd = asciiCharToNumericValue(msdChar);
+                        byte low = asciiCharToNumericValue(b);
+                        state = 0;
+                        byteq.enqueue((byte)((msd << 4) | low));
+                        break;
+                    } else {
+                        if (log.isWarnEnabled()) {
+                            log.warn("Malformed MIME; expected "
+                                     + "[0-9A-Z], got " + b);
+                        }
+                        state = 0;
+                        byteq.enqueue((byte)'=');
+                        byteq.enqueue(msdChar);
+                        byteq.enqueue(b);
+                        break;
+                    }
+                default:  // should never happen
+                    log.error("Illegal state: " + state);
+                    state = 0;
+                    byteq.enqueue(b);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Converts '0' => 0, 'A' => 10, etc.
+     * @param c ASCII character value.
+     * @return Numeric value of hexadecimal character.
+     */
+    private byte asciiCharToNumericValue(byte c) {
+        if (c >= '0' && c <= '9') {
+            return (byte)(c - '0');
+        } else if (c >= 'A' && c <= 'Z') {
+            return (byte)(0xA + (c - 'A'));
+        } else if (c >= 'a' && c <= 'z') {
+            return (byte)(0xA + (c - 'a'));
+        } else {
+            /*
+             * This should never happen since all calls to this method
+             * are preceded by a check that c is in [0-9A-Za-z]
+             */
+            throw new IllegalArgumentException((char) c 
+                    + " is not a hexadecimal digit");
+        }
+    }
+
+}

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/UnboundedFifoByteBuffer.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/UnboundedFifoByteBuffer.java?rev=778457&r1=778456&r2=778457&view=diff
==============================================================================
--- james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/UnboundedFifoByteBuffer.java (original)
+++ james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/UnboundedFifoByteBuffer.java Mon May 25 17:20:48 2009
@@ -1,265 +1,265 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.mime4j.codec;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-/**
- * UnboundedFifoByteBuffer is a very efficient buffer implementation.
- * According to performance testing, it exhibits a constant access time, but it
- * also outperforms ArrayList when used for the same purpose.
- * <p>
- * The removal order of an <code>UnboundedFifoByteBuffer</code> is based on the insertion
- * order; elements are removed in the same order in which they were added.
- * The iteration order is the same as the removal order.
- * <p>
- * The {@link #remove()} and {@link #get()} operations perform in constant time.
- * The {@link #add(Object)} operation performs in amortized constant time.  All
- * other operations perform in linear time or worse.
- * <p>
- * Note that this implementation is not synchronized.  The following can be
- * used to provide synchronized access to your <code>UnboundedFifoByteBuffer</code>:
- * <pre>
- *   Buffer fifo = BufferUtils.synchronizedBuffer(new UnboundedFifoByteBuffer());
- * </pre>
- * <p>
- * This buffer prevents null objects from being added.
- *
- * @since Commons Collections 3.0 (previously in main package v2.1)
- */
-class UnboundedFifoByteBuffer {
-
-    protected byte[] buffer;
-    protected int head;
-    protected int tail;
-
-    /**
-     * Constructs an UnboundedFifoByteBuffer with the default number of elements.
-     * It is exactly the same as performing the following:
-     *
-     * <pre>
-     *   new UnboundedFifoByteBuffer(32);
-     * </pre>
-     */
-    public UnboundedFifoByteBuffer() {
-        this(32);
-    }
-
-    /**
-     * Constructs an UnboundedFifoByteBuffer with the specified number of elements.
-     * The integer must be a positive integer.
-     *
-     * @param initialSize  the initial size of the buffer
-     * @throws IllegalArgumentException  if the size is less than 1
-     */
-    public UnboundedFifoByteBuffer(int initialSize) {
-        if (initialSize <= 0) {
-            throw new IllegalArgumentException("The size must be greater than 0");
-        }
-        buffer = new byte[initialSize + 1];
-        head = 0;
-        tail = 0;
-    }
-
-    /**
-     * Returns the number of elements stored in the buffer.
-     *
-     * @return this buffer's size
-     */
-    public int size() {
-        int size = 0;
-
-        if (tail < head) {
-            size = buffer.length - head + tail;
-        } else {
-            size = tail - head;
-        }
-
-        return size;
-    }
-
-    /**
-     * Returns true if this buffer is empty; false otherwise.
-     *
-     * @return true if this buffer is empty
-     */
-    public boolean isEmpty() {
-        return (size() == 0);
-    }
-
-    /**
-     * Adds the given element to this buffer.
-     *
-     * @param b  the byte to add
-     * @return true, always
-     */
-    public boolean add(final byte b) {
-
-        if (size() + 1 >= buffer.length) {
-            byte[] tmp = new byte[((buffer.length - 1) * 2) + 1];
-
-            int j = 0;
-            for (int i = head; i != tail;) {
-                tmp[j] = buffer[i];
-                buffer[i] = 0;
-
-                j++;
-                i++;
-                if (i == buffer.length) {
-                    i = 0;
-                }
-            }
-
-            buffer = tmp;
-            head = 0;
-            tail = j;
-        }
-
-        buffer[tail] = b;
-        tail++;
-        if (tail >= buffer.length) {
-            tail = 0;
-        }
-        return true;
-    }
-
-    /**
-     * Returns the next object in the buffer.
-     *
-     * @return the next object in the buffer
-     * @throws BufferUnderflowException  if this buffer is empty
-     */
-    public byte get() {
-        if (isEmpty()) {
-            throw new IllegalStateException("The buffer is already empty");
-        }
-
-        return buffer[head];
-    }
-
-    /**
-     * Removes the next object from the buffer
-     *
-     * @return the removed object
-     * @throws BufferUnderflowException  if this buffer is empty
-     */
-    public byte remove() {
-        if (isEmpty()) {
-            throw new IllegalStateException("The buffer is already empty");
-        }
-
-        byte element = buffer[head];
-
-        head++;
-        if (head >= buffer.length) {
-            head = 0;
-        }
-
-        return element;
-    }
-
-    /**
-     * Increments the internal index.
-     *
-     * @param index  the index to increment
-     * @return the updated index
-     */
-    private int increment(int index) {
-        index++;
-        if (index >= buffer.length) {
-            index = 0;
-        }
-        return index;
-    }
-
-    /**
-     * Decrements the internal index.
-     *
-     * @param index  the index to decrement
-     * @return the updated index
-     */
-    private int decrement(int index) {
-        index--;
-        if (index < 0) {
-            index = buffer.length - 1;
-        }
-        return index;
-    }
-
-    /**
-     * Returns an iterator over this buffer's elements.
-     *
-     * @return an iterator over this buffer's elements
-     */
-    public Iterator<Byte> iterator() {
-        return new Iterator<Byte>() {
-
-            private int index = head;
-            private int lastReturnedIndex = -1;
-
-            public boolean hasNext() {
-                return index != tail;
-
-            }
-
-            public Byte next() {
-                if (!hasNext()) {
-                    throw new NoSuchElementException();
-                }
-                lastReturnedIndex = index;
-                index = increment(index);
-                return new Byte(buffer[lastReturnedIndex]);
-            }
-
-            public void remove() {
-                if (lastReturnedIndex == -1) {
-                    throw new IllegalStateException();
-                }
-
-                // First element can be removed quickly
-                if (lastReturnedIndex == head) {
-                    UnboundedFifoByteBuffer.this.remove();
-                    lastReturnedIndex = -1;
-                    return;
-                }
-
-                // Other elements require us to shift the subsequent elements
-                int i = lastReturnedIndex + 1;
-                while (i != tail) {
-                    if (i >= buffer.length) {
-                        buffer[i - 1] = buffer[0];
-                        i = 0;
-                    } else {
-                        buffer[i - 1] = buffer[i];
-                        i++;
-                    }
-                }
-
-                lastReturnedIndex = -1;
-                tail = decrement(tail);
-                buffer[tail] = 0;
-                index = decrement(index);
-            }
-
-        };
-    }
-
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.codec;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * UnboundedFifoByteBuffer is a very efficient buffer implementation.
+ * According to performance testing, it exhibits a constant access time, but it
+ * also outperforms ArrayList when used for the same purpose.
+ * <p>
+ * The removal order of an <code>UnboundedFifoByteBuffer</code> is based on the insertion
+ * order; elements are removed in the same order in which they were added.
+ * The iteration order is the same as the removal order.
+ * <p>
+ * The {@link #remove()} and {@link #get()} operations perform in constant time.
+ * The {@link #add(Object)} operation performs in amortized constant time.  All
+ * other operations perform in linear time or worse.
+ * <p>
+ * Note that this implementation is not synchronized.  The following can be
+ * used to provide synchronized access to your <code>UnboundedFifoByteBuffer</code>:
+ * <pre>
+ *   Buffer fifo = BufferUtils.synchronizedBuffer(new UnboundedFifoByteBuffer());
+ * </pre>
+ * <p>
+ * This buffer prevents null objects from being added.
+ *
+ * @since Commons Collections 3.0 (previously in main package v2.1)
+ */
+class UnboundedFifoByteBuffer {
+
+    protected byte[] buffer;
+    protected int head;
+    protected int tail;
+
+    /**
+     * Constructs an UnboundedFifoByteBuffer with the default number of elements.
+     * It is exactly the same as performing the following:
+     *
+     * <pre>
+     *   new UnboundedFifoByteBuffer(32);
+     * </pre>
+     */
+    public UnboundedFifoByteBuffer() {
+        this(32);
+    }
+
+    /**
+     * Constructs an UnboundedFifoByteBuffer with the specified number of elements.
+     * The integer must be a positive integer.
+     *
+     * @param initialSize  the initial size of the buffer
+     * @throws IllegalArgumentException  if the size is less than 1
+     */
+    public UnboundedFifoByteBuffer(int initialSize) {
+        if (initialSize <= 0) {
+            throw new IllegalArgumentException("The size must be greater than 0");
+        }
+        buffer = new byte[initialSize + 1];
+        head = 0;
+        tail = 0;
+    }
+
+    /**
+     * Returns the number of elements stored in the buffer.
+     *
+     * @return this buffer's size
+     */
+    public int size() {
+        int size = 0;
+
+        if (tail < head) {
+            size = buffer.length - head + tail;
+        } else {
+            size = tail - head;
+        }
+
+        return size;
+    }
+
+    /**
+     * Returns true if this buffer is empty; false otherwise.
+     *
+     * @return true if this buffer is empty
+     */
+    public boolean isEmpty() {
+        return (size() == 0);
+    }
+
+    /**
+     * Adds the given element to this buffer.
+     *
+     * @param b  the byte to add
+     * @return true, always
+     */
+    public boolean add(final byte b) {
+
+        if (size() + 1 >= buffer.length) {
+            byte[] tmp = new byte[((buffer.length - 1) * 2) + 1];
+
+            int j = 0;
+            for (int i = head; i != tail;) {
+                tmp[j] = buffer[i];
+                buffer[i] = 0;
+
+                j++;
+                i++;
+                if (i == buffer.length) {
+                    i = 0;
+                }
+            }
+
+            buffer = tmp;
+            head = 0;
+            tail = j;
+        }
+
+        buffer[tail] = b;
+        tail++;
+        if (tail >= buffer.length) {
+            tail = 0;
+        }
+        return true;
+    }
+
+    /**
+     * Returns the next object in the buffer.
+     *
+     * @return the next object in the buffer
+     * @throws BufferUnderflowException  if this buffer is empty
+     */
+    public byte get() {
+        if (isEmpty()) {
+            throw new IllegalStateException("The buffer is already empty");
+        }
+
+        return buffer[head];
+    }
+
+    /**
+     * Removes the next object from the buffer
+     *
+     * @return the removed object
+     * @throws BufferUnderflowException  if this buffer is empty
+     */
+    public byte remove() {
+        if (isEmpty()) {
+            throw new IllegalStateException("The buffer is already empty");
+        }
+
+        byte element = buffer[head];
+
+        head++;
+        if (head >= buffer.length) {
+            head = 0;
+        }
+
+        return element;
+    }
+
+    /**
+     * Increments the internal index.
+     *
+     * @param index  the index to increment
+     * @return the updated index
+     */
+    private int increment(int index) {
+        index++;
+        if (index >= buffer.length) {
+            index = 0;
+        }
+        return index;
+    }
+
+    /**
+     * Decrements the internal index.
+     *
+     * @param index  the index to decrement
+     * @return the updated index
+     */
+    private int decrement(int index) {
+        index--;
+        if (index < 0) {
+            index = buffer.length - 1;
+        }
+        return index;
+    }
+
+    /**
+     * Returns an iterator over this buffer's elements.
+     *
+     * @return an iterator over this buffer's elements
+     */
+    public Iterator<Byte> iterator() {
+        return new Iterator<Byte>() {
+
+            private int index = head;
+            private int lastReturnedIndex = -1;
+
+            public boolean hasNext() {
+                return index != tail;
+
+            }
+
+            public Byte next() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+                lastReturnedIndex = index;
+                index = increment(index);
+                return new Byte(buffer[lastReturnedIndex]);
+            }
+
+            public void remove() {
+                if (lastReturnedIndex == -1) {
+                    throw new IllegalStateException();
+                }
+
+                // First element can be removed quickly
+                if (lastReturnedIndex == head) {
+                    UnboundedFifoByteBuffer.this.remove();
+                    lastReturnedIndex = -1;
+                    return;
+                }
+
+                // Other elements require us to shift the subsequent elements
+                int i = lastReturnedIndex + 1;
+                while (i != tail) {
+                    if (i >= buffer.length) {
+                        buffer[i - 1] = buffer[0];
+                        i = 0;
+                    } else {
+                        buffer[i - 1] = buffer[i];
+                        i++;
+                    }
+                }
+
+                lastReturnedIndex = -1;
+                tail = decrement(tail);
+                buffer[tail] = 0;
+                index = decrement(index);
+            }
+
+        };
+    }
+
 }
\ No newline at end of file

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/codec/UnboundedFifoByteBuffer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/descriptor/BodyDescriptor.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/descriptor/BodyDescriptor.java?rev=778457&r1=778456&r2=778457&view=diff
==============================================================================
--- james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/descriptor/BodyDescriptor.java (original)
+++ james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/descriptor/BodyDescriptor.java Mon May 25 17:20:48 2009
@@ -1,35 +1,35 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.mime4j.descriptor;
-
-/**
- * Encapsulates the values of the MIME-specific header fields 
- * (which starts with <code>Content-</code>). 
- */
-public interface BodyDescriptor extends ContentDescriptor {
-
-    /**
-     * Returns the body descriptors boundary.
-     * @return Boundary string, if known, or null. The latter may be the
-     *   case, in particular, if the body is no multipart entity.
-     */
-    String getBoundary();
-
-}
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.descriptor;
+
+/**
+ * Encapsulates the values of the MIME-specific header fields 
+ * (which starts with <code>Content-</code>). 
+ */
+public interface BodyDescriptor extends ContentDescriptor {
+
+    /**
+     * Returns the body descriptors boundary.
+     * @return Boundary string, if known, or null. The latter may be the
+     *   case, in particular, if the body is no multipart entity.
+     */
+    String getBoundary();
+
+}

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/descriptor/BodyDescriptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/descriptor/ContentDescriptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/descriptor/DefaultBodyDescriptor.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/descriptor/DefaultBodyDescriptor.java?rev=778457&r1=778456&r2=778457&view=diff
==============================================================================
--- james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/descriptor/DefaultBodyDescriptor.java (original)
+++ james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/descriptor/DefaultBodyDescriptor.java Mon May 25 17:20:48 2009
@@ -1,244 +1,244 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.mime4j.descriptor;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.james.mime4j.parser.Field;
-import org.apache.james.mime4j.util.MimeUtil;
-
-/**
- * Encapsulates the values of the MIME-specific header fields 
- * (which starts with <code>Content-</code>). 
- */
-public class DefaultBodyDescriptor implements MutableBodyDescriptor {
-    private static final String US_ASCII = "us-ascii";
-
-    private static final String SUB_TYPE_EMAIL = "rfc822";
-
-    private static final String MEDIA_TYPE_TEXT = "text";
-
-    private static final String MEDIA_TYPE_MESSAGE = "message";
-
-    private static final String EMAIL_MESSAGE_MIME_TYPE = MEDIA_TYPE_MESSAGE + "/" + SUB_TYPE_EMAIL;
-
-    private static final String DEFAULT_SUB_TYPE = "plain";
-
-    private static final String DEFAULT_MEDIA_TYPE = MEDIA_TYPE_TEXT;
-
-    private static final String DEFAULT_MIME_TYPE = DEFAULT_MEDIA_TYPE + "/" + DEFAULT_SUB_TYPE;
-
-    private static Log log = LogFactory.getLog(DefaultBodyDescriptor.class);
-    
-    private String mediaType = DEFAULT_MEDIA_TYPE;
-    private String subType = DEFAULT_SUB_TYPE;
-    private String mimeType = DEFAULT_MIME_TYPE;
-    private String boundary = null;
-    private String charset = US_ASCII;
-    private String transferEncoding = "7bit";
-    private Map<String, String> parameters = new HashMap<String, String>();
-    private boolean contentTypeSet;
-    private boolean contentTransferEncSet;
-    private long contentLength = -1;
-    
-    /**
-     * Creates a new root <code>BodyDescriptor</code> instance.
-     */
-    public DefaultBodyDescriptor() {
-        this(null);
-    }
-
-    /**
-     * Creates a new <code>BodyDescriptor</code> instance.
-     * 
-     * @param parent the descriptor of the parent or <code>null</code> if this
-     *        is the root descriptor.
-     */
-    public DefaultBodyDescriptor(BodyDescriptor parent) {
-        if (parent != null && MimeUtil.isSameMimeType("multipart/digest", parent.getMimeType())) {
-            mimeType = EMAIL_MESSAGE_MIME_TYPE;
-            subType = SUB_TYPE_EMAIL;
-            mediaType = MEDIA_TYPE_MESSAGE;
-        } else {
-            mimeType = DEFAULT_MIME_TYPE;
-            subType = DEFAULT_SUB_TYPE;
-            mediaType = DEFAULT_MEDIA_TYPE;
-        }
-    }
-    
-    /**
-     * Should be called for each <code>Content-</code> header field of 
-     * a MIME message or part.
-     * 
-     * @param field the MIME field.
-     */
-    public void addField(Field field) {
-        String name = field.getName();
-        String value = field.getBody();
-
-        name = name.trim().toLowerCase();
-        
-        if (name.equals("content-transfer-encoding") && !contentTransferEncSet) {
-            contentTransferEncSet = true;
-            
-            value = value.trim().toLowerCase();
-            if (value.length() > 0) {
-                transferEncoding = value;
-            }
-            
-        } else if (name.equals("content-length") && contentLength == -1) {
-            try {
-                contentLength = Long.parseLong(value.trim());
-            } catch (NumberFormatException e) {
-                log.error("Invalid content-length: " + value);
-            }
-        } else if (name.equals("content-type") && !contentTypeSet) {
-            parseContentType(value);
-        }
-    }
-
-    private void parseContentType(String value) {
-        contentTypeSet = true;
-        
-        Map<String, String> params = MimeUtil.getHeaderParams(value);
-        
-        String main = params.get("");
-        String type = null;
-        String subtype = null;
-        if (main != null) {
-            main = main.toLowerCase().trim();
-            int index = main.indexOf('/');
-            boolean valid = false;
-            if (index != -1) {
-                type = main.substring(0, index).trim();
-                subtype = main.substring(index + 1).trim();
-                if (type.length() > 0 && subtype.length() > 0) {
-                    main = type + "/" + subtype;
-                    valid = true;
-                }
-            }
-            
-            if (!valid) {
-                main = null;
-                type = null;
-                subtype = null;
-            }
-        }
-        String b = params.get("boundary");
-        
-        if (main != null 
-                && ((main.startsWith("multipart/") && b != null) 
-                        || !main.startsWith("multipart/"))) {
-            
-            mimeType = main;
-            this.subType = subtype;
-            this.mediaType = type;
-        }
-        
-        if (MimeUtil.isMultipart(mimeType)) {
-            boundary = b;
-        }
-        
-        String c = params.get("charset");
-        charset = null;
-        if (c != null) {
-            c = c.trim();
-            if (c.length() > 0) {
-                charset = c.toLowerCase();
-            }
-        }
-        if (charset == null && MEDIA_TYPE_TEXT.equals(mediaType)) {
-            charset = US_ASCII;
-        }
-        
-        /*
-         * Add all other parameters to parameters.
-         */
-        parameters.putAll(params);
-        parameters.remove("");
-        parameters.remove("boundary");
-        parameters.remove("charset");
-    }
-
-    /**
-     * Return the MimeType 
-     * 
-     * @return mimeType
-     */
-    public String getMimeType() {
-        return mimeType;
-    }
-    
-    /**
-     * Return the boundary
-     * 
-     * @return boundary
-     */
-    public String getBoundary() {
-        return boundary;
-    }
-    
-    /**
-     * Return the charset
-     * 
-     * @return charset
-     */
-    public String getCharset() {
-        return charset;
-    }
-    
-    /**
-     * Return all parameters for the BodyDescriptor
-     * 
-     * @return parameters
-     */
-    public Map<String, String> getContentTypeParameters() {
-        return parameters;
-    }
-    
-    /**
-     * Return the TransferEncoding
-     * 
-     * @return transferEncoding
-     */
-    public String getTransferEncoding() {
-        return transferEncoding;
-    }
-    
-    @Override
-    public String toString() {
-        return mimeType;
-    }
-
-    public long getContentLength() {
-        return contentLength;
-    }
-
-    public String getMediaType() {
-        return mediaType;
-    }
-
-    public String getSubType() {
-        return subType;
-    }
-}
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.descriptor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.james.mime4j.parser.Field;
+import org.apache.james.mime4j.util.MimeUtil;
+
+/**
+ * Encapsulates the values of the MIME-specific header fields 
+ * (which starts with <code>Content-</code>). 
+ */
+public class DefaultBodyDescriptor implements MutableBodyDescriptor {
+    private static final String US_ASCII = "us-ascii";
+
+    private static final String SUB_TYPE_EMAIL = "rfc822";
+
+    private static final String MEDIA_TYPE_TEXT = "text";
+
+    private static final String MEDIA_TYPE_MESSAGE = "message";
+
+    private static final String EMAIL_MESSAGE_MIME_TYPE = MEDIA_TYPE_MESSAGE + "/" + SUB_TYPE_EMAIL;
+
+    private static final String DEFAULT_SUB_TYPE = "plain";
+
+    private static final String DEFAULT_MEDIA_TYPE = MEDIA_TYPE_TEXT;
+
+    private static final String DEFAULT_MIME_TYPE = DEFAULT_MEDIA_TYPE + "/" + DEFAULT_SUB_TYPE;
+
+    private static Log log = LogFactory.getLog(DefaultBodyDescriptor.class);
+    
+    private String mediaType = DEFAULT_MEDIA_TYPE;
+    private String subType = DEFAULT_SUB_TYPE;
+    private String mimeType = DEFAULT_MIME_TYPE;
+    private String boundary = null;
+    private String charset = US_ASCII;
+    private String transferEncoding = "7bit";
+    private Map<String, String> parameters = new HashMap<String, String>();
+    private boolean contentTypeSet;
+    private boolean contentTransferEncSet;
+    private long contentLength = -1;
+    
+    /**
+     * Creates a new root <code>BodyDescriptor</code> instance.
+     */
+    public DefaultBodyDescriptor() {
+        this(null);
+    }
+
+    /**
+     * Creates a new <code>BodyDescriptor</code> instance.
+     * 
+     * @param parent the descriptor of the parent or <code>null</code> if this
+     *        is the root descriptor.
+     */
+    public DefaultBodyDescriptor(BodyDescriptor parent) {
+        if (parent != null && MimeUtil.isSameMimeType("multipart/digest", parent.getMimeType())) {
+            mimeType = EMAIL_MESSAGE_MIME_TYPE;
+            subType = SUB_TYPE_EMAIL;
+            mediaType = MEDIA_TYPE_MESSAGE;
+        } else {
+            mimeType = DEFAULT_MIME_TYPE;
+            subType = DEFAULT_SUB_TYPE;
+            mediaType = DEFAULT_MEDIA_TYPE;
+        }
+    }
+    
+    /**
+     * Should be called for each <code>Content-</code> header field of 
+     * a MIME message or part.
+     * 
+     * @param field the MIME field.
+     */
+    public void addField(Field field) {
+        String name = field.getName();
+        String value = field.getBody();
+
+        name = name.trim().toLowerCase();
+        
+        if (name.equals("content-transfer-encoding") && !contentTransferEncSet) {
+            contentTransferEncSet = true;
+            
+            value = value.trim().toLowerCase();
+            if (value.length() > 0) {
+                transferEncoding = value;
+            }
+            
+        } else if (name.equals("content-length") && contentLength == -1) {
+            try {
+                contentLength = Long.parseLong(value.trim());
+            } catch (NumberFormatException e) {
+                log.error("Invalid content-length: " + value);
+            }
+        } else if (name.equals("content-type") && !contentTypeSet) {
+            parseContentType(value);
+        }
+    }
+
+    private void parseContentType(String value) {
+        contentTypeSet = true;
+        
+        Map<String, String> params = MimeUtil.getHeaderParams(value);
+        
+        String main = params.get("");
+        String type = null;
+        String subtype = null;
+        if (main != null) {
+            main = main.toLowerCase().trim();
+            int index = main.indexOf('/');
+            boolean valid = false;
+            if (index != -1) {
+                type = main.substring(0, index).trim();
+                subtype = main.substring(index + 1).trim();
+                if (type.length() > 0 && subtype.length() > 0) {
+                    main = type + "/" + subtype;
+                    valid = true;
+                }
+            }
+            
+            if (!valid) {
+                main = null;
+                type = null;
+                subtype = null;
+            }
+        }
+        String b = params.get("boundary");
+        
+        if (main != null 
+                && ((main.startsWith("multipart/") && b != null) 
+                        || !main.startsWith("multipart/"))) {
+            
+            mimeType = main;
+            this.subType = subtype;
+            this.mediaType = type;
+        }
+        
+        if (MimeUtil.isMultipart(mimeType)) {
+            boundary = b;
+        }
+        
+        String c = params.get("charset");
+        charset = null;
+        if (c != null) {
+            c = c.trim();
+            if (c.length() > 0) {
+                charset = c.toLowerCase();
+            }
+        }
+        if (charset == null && MEDIA_TYPE_TEXT.equals(mediaType)) {
+            charset = US_ASCII;
+        }
+        
+        /*
+         * Add all other parameters to parameters.
+         */
+        parameters.putAll(params);
+        parameters.remove("");
+        parameters.remove("boundary");
+        parameters.remove("charset");
+    }
+
+    /**
+     * Return the MimeType 
+     * 
+     * @return mimeType
+     */
+    public String getMimeType() {
+        return mimeType;
+    }
+    
+    /**
+     * Return the boundary
+     * 
+     * @return boundary
+     */
+    public String getBoundary() {
+        return boundary;
+    }
+    
+    /**
+     * Return the charset
+     * 
+     * @return charset
+     */
+    public String getCharset() {
+        return charset;
+    }
+    
+    /**
+     * Return all parameters for the BodyDescriptor
+     * 
+     * @return parameters
+     */
+    public Map<String, String> getContentTypeParameters() {
+        return parameters;
+    }
+    
+    /**
+     * Return the TransferEncoding
+     * 
+     * @return transferEncoding
+     */
+    public String getTransferEncoding() {
+        return transferEncoding;
+    }
+    
+    @Override
+    public String toString() {
+        return mimeType;
+    }
+
+    public long getContentLength() {
+        return contentLength;
+    }
+
+    public String getMediaType() {
+        return mediaType;
+    }
+
+    public String getSubType() {
+        return subType;
+    }
+}

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/descriptor/DefaultBodyDescriptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/descriptor/MaximalBodyDescriptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/descriptor/MutableBodyDescriptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/field/AbstractField.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/field/AddressListField.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/field/AddressListField.java?rev=778457&r1=778456&r2=778457&view=diff
==============================================================================
--- james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/field/AddressListField.java (original)
+++ james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/field/AddressListField.java Mon May 25 17:20:48 2009
@@ -1,79 +1,79 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.mime4j.field;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.james.mime4j.field.address.AddressList;
-import org.apache.james.mime4j.field.address.parser.ParseException;
-import org.apache.james.mime4j.util.ByteSequence;
-
-/**
- * Address list field such as <code>To</code> or <code>Reply-To</code>.
- */
-public class AddressListField extends AbstractField {
-    private static Log log = LogFactory.getLog(AddressListField.class);
-
-    private boolean parsed = false;
-
-    private AddressList addressList;
-    private ParseException parseException;
-
-    AddressListField(String name, String body, ByteSequence raw) {
-        super(name, body, raw);
-    }
-
-    public AddressList getAddressList() {
-        if (!parsed)
-            parse();
-
-        return addressList;
-    }
-
-    @Override
-    public ParseException getParseException() {
-        if (!parsed)
-            parse();
-
-        return parseException;
-    }
-
-    private void parse() {
-        String body = getBody();
-
-        try {
-            addressList = AddressList.parse(body);
-        } catch (ParseException e) {
-            if (log.isDebugEnabled()) {
-                log.debug("Parsing value '" + body + "': " + e.getMessage());
-            }
-            parseException = e;
-        }
-
-        parsed = true;
-    }
-
-    static final FieldParser PARSER = new FieldParser() {
-        public ParsedField parse(final String name, final String body,
-                final ByteSequence raw) {
-            return new AddressListField(name, body, raw);
-        }
-    };
-}
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.field;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.james.mime4j.field.address.AddressList;
+import org.apache.james.mime4j.field.address.parser.ParseException;
+import org.apache.james.mime4j.util.ByteSequence;
+
+/**
+ * Address list field such as <code>To</code> or <code>Reply-To</code>.
+ */
+public class AddressListField extends AbstractField {
+    private static Log log = LogFactory.getLog(AddressListField.class);
+
+    private boolean parsed = false;
+
+    private AddressList addressList;
+    private ParseException parseException;
+
+    AddressListField(String name, String body, ByteSequence raw) {
+        super(name, body, raw);
+    }
+
+    public AddressList getAddressList() {
+        if (!parsed)
+            parse();
+
+        return addressList;
+    }
+
+    @Override
+    public ParseException getParseException() {
+        if (!parsed)
+            parse();
+
+        return parseException;
+    }
+
+    private void parse() {
+        String body = getBody();
+
+        try {
+            addressList = AddressList.parse(body);
+        } catch (ParseException e) {
+            if (log.isDebugEnabled()) {
+                log.debug("Parsing value '" + body + "': " + e.getMessage());
+            }
+            parseException = e;
+        }
+
+        parsed = true;
+    }
+
+    static final FieldParser PARSER = new FieldParser() {
+        public ParsedField parse(final String name, final String body,
+                final ByteSequence raw) {
+            return new AddressListField(name, body, raw);
+        }
+    };
+}

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/field/AddressListField.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message